Browse Source

add state page

main
matthew 2 years ago
parent
commit
123fb33bc2
  1. BIN
      .DS_Store
  2. 33
      searching-front/app/core/components/ContextProviders/ContextProviders.tsx
  3. 1
      searching-front/app/core/components/ContextProviders/index.tsx
  4. 5
      searching-front/app/core/components/Footer/Footer.tsx
  5. 16
      searching-front/app/core/components/Footer/styles.module.css
  6. 4
      searching-front/app/core/components/Header/Header.tsx
  7. 37
      searching-front/app/core/components/Header/styles.module.css
  8. 38
      searching-front/app/core/components/Link/Link.tsx
  9. 1
      searching-front/app/core/components/Link/index.ts
  10. 40
      searching-front/app/core/components/Link/styles.module.css
  11. 3
      searching-front/app/core/components/SearchForm/styles.module.css
  12. 40
      searching-front/app/core/components/ThemeSwitcher/ThemeSwitcher.tsx
  13. 320
      searching-front/app/core/components/ThemeSwitcher/styles.module.css
  14. 4
      searching-front/app/core/components/TonBrilliant/TonBrillian.tsx
  15. 7
      searching-front/app/core/components/TonBrilliant/styles.module.css
  16. 5
      searching-front/app/core/components/WebsiteCard/styles.module.css
  17. 15
      searching-front/app/core/contextProviders/serverSidePropsProvider.ts
  18. 10
      searching-front/app/core/darkTheme.css
  19. 2
      searching-front/app/core/helpers/common.ts
  20. 2
      searching-front/app/core/helpers/metrika.ts
  21. 13
      searching-front/app/core/hooks/useCurrentTheme.ts
  22. 2
      searching-front/app/core/layouts/Layout/index.tsx
  23. 2
      searching-front/app/core/layouts/Layout/styles.module.css
  24. 10
      searching-front/app/core/lightTheme.css
  25. 51
      searching-front/app/core/pages/Main/LastSitesWidget/LastSitesWidget.tsx
  26. 1
      searching-front/app/core/pages/Main/LastSitesWidget/index.tsx
  27. 170
      searching-front/app/core/pages/Main/LastSitesWidget/styles.module.css
  28. 10
      searching-front/app/core/pages/Main/Main.tsx
  29. 4
      searching-front/app/core/pages/Main/styles.module.css
  30. 8
      searching-front/app/core/pages/Search/styles.module.css
  31. 75
      searching-front/app/core/pages/State/State.tsx
  32. 102
      searching-front/app/core/pages/State/styles.module.css
  33. 2
      searching-front/app/core/variables.css
  34. 16
      searching-front/app/stateSites/queries/getLastWeekNewSites.ts
  35. 46
      searching-front/pages/auth/forgot-password.tsx
  36. 21
      searching-front/pages/auth/login.tsx
  37. 66
      searching-front/pages/auth/reset-password.tsx
  38. 16
      searching-front/pages/auth/signup.tsx
  39. 24
      searching-front/pages/index.tsx
  40. 14
      searching-front/pages/s.tsx
  41. 33
      searching-front/pages/state.tsx
  42. BIN
      searching-front/public/favicon copy.ico
  43. BIN
      searching-front/public/favicon.ico
  44. BIN
      searching-front/public/logo copy.png
  45. BIN
      searching-front/public/logo.png
  46. 16
      searching-front/services/main.ts
  47. 3
      searching-front/services/modules/parser/index.ts
  48. 5
      searching-front/services/parser.ts

BIN
.DS_Store vendored

Binary file not shown.

33
searching-front/app/core/components/ContextProviders/ContextProviders.tsx

@ -0,0 +1,33 @@
import {
ServerSidePropsContext,
ContextParamsServer,
} from "app/core/contextProviders/serverSidePropsProvider"
import { ReactNode, useState } from "react"
import jsCookies from "js-cookie"
interface Props {
children: ReactNode
contextParamsServer: ContextParamsServer
}
type Theme = "light" | "dark"
const THEME_COOKIE_NAME = "theme"
const ContextProviders = ({ children, contextParamsServer: { cookies } }: Props) => {
const [theme, setThemeState] = useState<Theme>((cookies[THEME_COOKIE_NAME] as Theme) || 'dark')
const setTheme = (theme: Theme) => {
jsCookies.set(THEME_COOKIE_NAME, theme)
setThemeState(theme)
}
const context = {
theme,
setTheme,
}
return (
<ServerSidePropsContext.Provider value={context}>{children}</ServerSidePropsContext.Provider>
)
}
export default ContextProviders

1
searching-front/app/core/components/ContextProviders/index.tsx

@ -0,0 +1 @@
export {default} from './ContextProviders'

5
searching-front/app/core/components/Footer/Footer.tsx

@ -34,9 +34,8 @@ const Footer = () => {
return (
<div className={s.root}>
<div className={s.contactsWrapper}>
<FooterLink href="https://searching_ton.t.me/" keyLink="footer.linkContacts" isTg />
<FooterLink href="https://searchington.t.me/" keyLink="footer.linkAnnouncments" isTg />
<FooterLink href="https://searching_ton_feedback_bot.t.me/" keyLink="footer.linkFeedback" isTg />
<FooterLink href="https://searching_ton.t.me/" keyLink="footer.linkContacts" />
<FooterLink href="https://searchington.t.me/" keyLink="footer.linkAnnouncments" />
</div>
</div>
)

16
searching-front/app/core/components/Footer/styles.module.css

@ -2,7 +2,8 @@
margin-top: 30px;
box-sizing: border-box;
display: flex;
justify-content: center;
border-top: 1px solid var(--border_color_main);
padding: var(--layout-padding);
}
.tgIcon {
@ -14,15 +15,20 @@
.contactsWrapper {
flex: 1;
display: flex;
justify-content: space-between;
align-items: center;
color: var(--text_secondary);
max-width: 600px;
}
.footerLinkRoot {
font-size: 15px;
font-weight: 700;
text-decoration: none;
color: var(--text_secondary);
display: flex;
align-items: center;
background: var(--footer_link_color);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
color: #0B2349;
display: table;
margin-right: 40px;
}

4
searching-front/app/core/components/Header/Header.tsx

@ -1,4 +1,5 @@
import { Routes } from "@blitzjs/next"
import { cn } from "app/core/helpers/common"
import TonLogo from "app/core/icons/TonLogo"
import { useRouter } from "next/router"
import SearchForm from "../SearchForm"
@ -14,12 +15,13 @@ const Header = () => {
}
return (
<div className={s.root}>
<div className={cn(s.root, { [s.withBorder]: shouldShowSearchForm })}>
<div onClick={toMain} className={s.logoWrapper}>
<TonLogo /> <span>TON SEARCHING</span>
</div>
{shouldShowSearchForm && <SearchForm />}
{/* <ThemeSwitcher /> */}
<div className={s.rightFiller}/>
</div>
)
}

37
searching-front/app/core/components/Header/styles.module.css

@ -1,14 +1,17 @@
.root {
box-sizing: border-box;
display: flex;
align-items: center;
min-height: 94px;
padding: var(--layout-padding);
justify-content: space-between;
}
@media only screen and (max-width: 900px) {
.root {
flex-direction: column;
}
.root.withBorder {
border-bottom: 1px solid var(--border_color_main);
}
.logoWrapper {
display: flex;
align-items: center;
@ -24,12 +27,32 @@
margin-right: 20px;
}
@media only screen and (max-width: 900px) {
.rightFiller{
width: 230px;
}
@media only screen and (max-width: 1100px) {
.logoWrapper > span {
display: none;
}
.rightFiller{
width: 32px;
}
}
@media only screen and (max-width: 1000px) {
.logoWrapper > span {
display: inline;
}
.root {
flex-direction: column;
padding: 0;
/* padding: 0; */
min-height: none;
}
.logoWrapper {
margin-bottom: 10px;
margin-bottom: 20px;
}
.rightFiller{
width: 0;
}
}

38
searching-front/app/core/components/Link/Link.tsx

@ -0,0 +1,38 @@
import { cn } from "app/core/helpers/common"
import { ReactNode } from "react"
import { AnimatePresence, HTMLMotionProps, motion } from "framer-motion"
import s from "./styles.module.css"
import NextLink from "next/link"
import { Routes } from "@blitzjs/next"
interface Props {
children: ReactNode
theme: "primary" | "clear"
className?: string
onClick?: () => void
href: string | ReturnType<typeof Routes.Home>
wide?: boolean
}
const Link = ({
children,
theme,
className,
onClick,
href,
wide,
...linkProps
}: Props & React.ComponentProps<typeof NextLink>) => {
return (
<div className={cn(s.root, className, `theme-${theme}`)}>
<NextLink target="_blank" href={href} >
<a {...linkProps} onClick={onClick} className={cn({ [s.wide]: wide })}>
{children}
</a>
</NextLink>
</div>
)
}
export default Link

1
searching-front/app/core/components/Link/index.ts

@ -0,0 +1 @@
export { default } from "./Link"

40
searching-front/app/core/components/Link/styles.module.css

@ -0,0 +1,40 @@
.root {
text-decoration: none;
display: inline-block;
/* size */
font-size: 18px;
font-weight: 500px;
}
.root a {
text-decoration: none;
}
.root a.wide::before {
content: "";
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.root:active {
transform: scale(0.95);
}
.root:global(.theme-primary) a {
color: var(--button_primary);
}
.root:global(.theme-primary) a:hover {
color: var(--button_primary_hover);
}
.root:global(.theme-primary) a:active {
color: var(--button_primary_pressed);
}
.root:global(.theme-clear) a {
color: inherit;
}

3
searching-front/app/core/components/SearchForm/styles.module.css

@ -1,5 +1,6 @@
.root {
width: 55vw;
width: 100%;
max-width: 600px;
font-size: 18px;
position: relative;
z-index: 101;

40
searching-front/app/core/components/ThemeSwitcher/ThemeSwitcher.tsx

@ -1,29 +1,27 @@
import { cn } from "app/core/helpers/common"
import { useCurrentTheme } from "app/core/hooks/useCurrentTheme"
import s from "./styles.module.css"
const ThemeSwitcher = () => {
const { theme, setTheme } = useCurrentTheme()
const toggleTheme = () => {
if (theme == "light") {
setTheme("dark")
} else {
setTheme("light")
}
}
let emoji
if (theme == "light") {
emoji = "🌞"
} else {
emoji = "🌛"
}
return (
<div className={s.root}>
<div className={s.wrapper}>
<input type="checkbox" id="hide-checkbox" className={s.hideCheckbox} />
<label htmlFor="hide-checkbox" className={s.toggle}>
<span className={s.toggleButton}>
<span className={(s.crater, s.crater1)}></span>
<span className={(s.crater, s.crater2)}></span>
<span className={(s.crater, s.crater3)}></span>
<span className={(s.crater, s.crater4)}></span>
<span className={(s.crater, s.crater5)}></span>
<span className={(s.crater, s.crater6)}></span>
<span className={(s.crater, s.crater7)}></span>
</span>
<span className={(s.star, s.star1)}></span>
<span className={(s.star, s.star2)}></span>
<span className={(s.star, s.star3)}></span>
<span className={(s.star, s.star4)}></span>
<span className={(s.star, s.star5)}></span>
<span className={(s.star, s.star6)}></span>
<span className={(s.star, s.star7)}></span>
<span className={(s.star, s.star8)}></span>
</label>
<div onClick={toggleTheme} className={s.wrapper}>
<div className={cn(s.content, { [s.light]: theme === "light" })}>{emoji}</div>
</div>
</div>
)

320
searching-front/app/core/components/ThemeSwitcher/styles.module.css

@ -1,311 +1,31 @@
.wrapper {
/* position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%); */
.root{
flex: 1;
display: flex;
justify-content: flex-end;
}
.hideCheckbox {
opacity: 0;
height: 0;
width: 0;
}
.toggle {
position: relative;
cursor: pointer;
display: inline-block;
width: 200px;
height: 100px;
background: #211042;
border-radius: 50px;
transition: 500ms;
overflow: hidden;
}
.toggleButton {
position: absolute;
display: inline-block;
top: 7px;
left: 6px;
width: 86px;
height: 86px;
border-radius: 50%;
background: #faeaf1;
overflow: hidden;
box-shadow: 0 0 35px 4px rgba(255, 255, 255);
transition: all 500ms ease-out;
}
.crater {
position: absolute;
display: inline-block;
background: #faeaf1;
border-radius: 50%;
transition: 500ms;
}
.crater1 {
background: #fffff9;
width: 86px;
height: 86px;
left: 10px;
bottom: 10px;
}
.crater2 {
width: 20px;
height: 20px;
top: -7px;
left: 44px;
}
.crater3 {
width: 16px;
height: 16px;
top: 20px;
right: -4px;
}
.crater4 {
width: 10px;
height: 10px;
top: 24px;
left: 30px;
}
.crater5 {
width: 15px;
height: 15px;
top: 40px;
left: 48px;
}
.crater6 {
width: 10px;
height: 10px;
top: 48px;
left: 20px;
}
.crater7 {
width: 12px;
height: 12px;
bottom: 5px;
left: 35px;
}
.star {
position: absolute;
display: inline-block;
border-radius: 50%;
background: #fff;
box-shadow: 1px 0 2px 2px rgba(255, 255, 255);
}
.star1 {
width: 6px;
height: 6px;
right: 90px;
bottom: 40px;
}
.star2 {
width: 8px;
height: 8px;
right: 70px;
top: 10px;
}
.star3 {
width: 5px;
height: 5px;
right: 60px;
bottom: 15px;
}
.star4 {
width: 3px;
height: 3px;
right: 40px;
bottom: 50px;
}
.star5 {
width: 4px;
height: 4px;
right: 10px;
bottom: 35px;
}
.star6,
.star7,
.star8 {
width: 10px;
height: 2px;
border-radius: 2px;
transform: rotate(-45deg);
box-shadow: 5px 0px 4px 1px #fff;
animation-name: travel;
animation-duration: 1.5s;
animation-timing-function: ease-out;
animation-iteration-count: infinite;
}
.star6 {
right: 30px;
bottom: 30px;
animation-delay: -2s;
}
.star7 {
right: 50px;
bottom: 60px;
}
.star8 {
right: 90px;
top: 10px;
animation-delay: -4s;
}
@keyframes travel {
0% {
transform: rotate(-45deg) translateX(70px);
}
50% {
transform: rotate(-45deg) translateX(-20px);
box-shadow: 5px 0px 6px 1px #fff;
}
100% {
transform: rotate(-45deg) translateX(-30px);
width: 2px;
height: 2px;
opacity: 0;
box-shadow: none;
}
}
.hideCheckbox:checked + .toggle {
background: #24d7f7;
}
.hideCheckbox:checked + .toggle .toggleButton {
background: #f7ffff;
transform: translateX(102px);
box-shadow: 0 0 35px 5px rgba(255, 255, 255);
}
.hideCheckbox:checked + .toggle .toggleButton .crater {
transform: rotate(-45deg) translateX(70px);
}
.hideCheckbox:checked + .toggle .star {
animation: move 2s infinite;
transform: none;
box-shadow: none;
}
.hideCheckbox:checked + .toggle .star1 {
width: 40px;
height: 10px;
.wrapper{
width: 35px;
background: var(--background_secondary);
border-radius: 10px;
background: #fff;
left: 20px;
top: 25px;
box-shadow: none;
}
.hideCheckbox:checked + .toggle .star2 {
width: 12px;
height: 12px;
background: #fff;
left: 26px;
top: 23px;
box-shadow: -1px 0 2px 0 rgba(0, 0, 0, 0.1);
}
.hideCheckbox:checked + .toggle .star3 {
width: 16px;
height: 16px;
background: #fff;
left: 35px;
top: 19px;
box-shadow: -1px 0 2px 0 rgba(0, 0, 0, 0.1);
}
.hideCheckbox:checked + .toggle .star4 {
width: 14px;
height: 14px;
background: #fff;
left: 46px;
top: 21px;
box-shadow: -1px 0 2px 0 rgba(0, 0, 0, 0.1);
}
.hideCheckbox:checked + .toggle .star5 {
width: 60px;
height: 15px;
border-radius: 15px;
background: #fff;
left: 30px;
bottom: 20px;
box-shadow: none;
height: 20px;
display: flex;
align-items: center;
padding: 2px;
cursor: pointer;
}
.hideCheckbox:checked + .toggle .star6 {
.content{
width: 18px;
height: 18px;
background: #fff;
border-radius: 50%;
left: 38px;
bottom: 20px;
box-shadow: -1px 0 2px 0 rgba(0, 0, 0, 0.1);
}
.hideCheckbox:checked + .toggle .star7 {
width: 24px;
height: 24px;
background: #fff;
border-radius: 50%;
left: 52px;
bottom: 20px;
box-shadow: -1px 0 2px 0 rgba(0, 0, 0, 0.1);
}
.hideCheckbox:checked + .toggle .star8 {
width: 21px;
height: 21px;
background: #fff;
border-radius: 50%;
left: 70px;
top: 59px;
box-shadow: -1px 0 2px 0 rgba(0, 0, 0, 0.1);
}
@keyframes move {
0% {
transform: none;
}
25% {
transform: translateX(2px);
}
100% {
transform: translateX(-2px);
}
}
/* p {
background: var(--background_main);
font-size: 15px;
text-align: center;
letter-spacing: 15px;
background: #34495e;
color: #fff;
transition: transform .1s linear;
pointer-events: none;
}
p.morning {
background: #e67e22;
} */
.content.light {
transform: translateX(16px);
}

4
searching-front/app/core/components/TonBrilliant/TonBrillian.tsx

@ -9,8 +9,8 @@ const TonBrilliant = () => {
<div className={s.root}>
<video
className={s.video}
width="300"
height="300"
width="200"
height="200"
autoPlay
loop
playsinline

7
searching-front/app/core/components/TonBrilliant/styles.module.css

@ -1,5 +1,6 @@
.root {
/* position: relative; */
margin-bottom: 20px;
}
.video {
@ -10,12 +11,12 @@
.root:before {
content: "";
z-index: 0;
max-width: 690px;
max-height: 690px;
max-width: 400px;
max-height: 400px;
width: 100vw;
height: 100vh;
position: absolute;
top: -234px;
top: -360px;
left: 0;
right: 0;
bottom: 0;

5
searching-front/app/core/components/WebsiteCard/styles.module.css

@ -22,12 +22,13 @@
}
.miniLink {
text-decoration: none;
font-size: 14px;
color: var(--text_light_secondary);
font-size: 13px;
color: var(--text_secondary);
max-width: 300px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-weight: bold;
}
.description {

15
searching-front/app/core/contextProviders/serverSidePropsProvider.ts

@ -1,17 +1,26 @@
import { gSSP } from "app/blitz-server"
import React from "react"
interface ContextParams {
export interface ContextParamsServer {
cookies: Record<string, string | undefined>
}
interface Props {
props: ContextParams
props: ContextParamsServer
}
export const serverSideProps = async ({ ctx, req }): Promise<Props> => {
export interface ContextParams {
theme: string;
setTheme: (theme:'dark'| 'light')=> void;
}
export const serverSideProps = (pagePropsFunction?:()=>{}) => async ({ ctx, req }): Promise<Props> => {
const pageProps = await pagePropsFunction?.() || {};
return {
props: {
...pageProps,
cookies: req.cookies,
},
}

10
searching-front/app/core/darkTheme.css

@ -1,4 +1,8 @@
#layout.dark {
/* :after,
:before, */
#layout.dark,
#layout.dark::before {
--background_main: #232328;
--background_gradient: linear-gradient(0deg, #232328, #343437 101.47%);
--background_secondary: hsl(240 2% 23% / 1);
@ -29,4 +33,8 @@
--icon_primary: #02a8fb;
--separator: hsla(0, 0%, 100%, 0.06);
--color_link: hsl(200 50% 70% / 1);
--footer_link_color: linear-gradient(270deg, #81CBFA 0%, #459FE8 104.65%);
/* only dark theme */
--border_color_main:#2E2E32;
}

2
searching-front/app/core/helpers/common.ts

@ -8,3 +8,5 @@ export const cleanUrlForUi = (url: string) => {
export const isNode = () => {
return typeof window !== "object"
}
export const getDomainFromUrl = (url: string) => url.match(/http:\/\/(.*).ton/)?.[1]

2
searching-front/app/core/helpers/metrika.ts

@ -1,3 +1,5 @@
export const count = (event:string) => {
yaCounter90644479.reachGoal(event)
gtag('event', event);
console.log(event)
}

13
searching-front/app/core/hooks/useCurrentTheme.ts

@ -1,14 +1,9 @@
import { useContext } from "react"
import { ServerSidePropsContext } from "../contextProviders/serverSidePropsProvider"
import jsCookies from "js-cookie"
const COOKIE_NAME = "theme"
export const useCurrentTheme = () => {
const { cookies } = useContext(ServerSidePropsContext)
if (cookies) {
return jsCookies.get(COOKIE_NAME) || cookies[COOKIE_NAME] || "light"
} else {
return "light"
}
const { theme, setTheme } = useContext(ServerSidePropsContext)
return { theme, setTheme }
}

2
searching-front/app/core/layouts/Layout/index.tsx

@ -12,7 +12,7 @@ const Layout: BlitzLayout<{
children?: React.ReactNode
withoutPaddings?: boolean
}> = ({ title, children, withoutPaddings }) => {
const theme = useCurrentTheme()
const {theme} = useCurrentTheme()
return (
<>
<Head>

2
searching-front/app/core/layouts/Layout/styles.module.css

@ -1,13 +1,11 @@
.root {
background: var(--background_main);
padding: 20px;
display: flex;
flex-direction: column;
box-sizing: border-box;
}
.content {
margin-top: 20px;
margin-left: var(--logoWrapperWidth);
display: flex;
flex-direction: column;

10
searching-front/app/core/lightTheme.css

@ -1,4 +1,10 @@
#layout.light {
/* :after,
:before, */
#layout.light,
#layout.light::before{
--background_main: hsla(206, 63%, 97%, 1);
--background_secondary: white;
--background_gradient: linear-gradient(180deg, #f7f9fb, rgba(238, 242, 245, 0.8) 116.16%);
@ -31,4 +37,6 @@
--icon_thirdly: #98b2bf;
--separator_light: rgba(123, 148, 160, 0.2);
--color_link: #101070;
--footer_link_color: linear-gradient(270deg, #81CBFA 0%, #459FE8 104.65%);
}

51
searching-front/app/core/pages/Main/LastSitesWidget/LastSitesWidget.tsx

@ -0,0 +1,51 @@
import { Routes } from "@blitzjs/next"
import { NftDomain } from "@prisma/client"
import Button from "app/auth/components/Button"
import Link from "app/core/components/Link"
import { getDomainFromUrl } from "app/core/helpers/common"
import { count } from "app/core/helpers/metrika"
import { motion } from "framer-motion"
import s from "./styles.module.css"
interface Props {
lastWeekNewSites: NftDomain[]
}
const LastSitesWidget = (props: Props) => {
return (
<div className={s.root}>
<div className={s.heading}>
New sites{" "}
<Link onClick={()=>count('from_main_new_sites_widget_to_state_page')} className={s.link} theme="primary" href={Routes.StatePage()}>
See all
</Link>
</div>
<div className={s.sitesWrapperShadows}>
<div className={s.sitesWrapper}>
{props.lastWeekNewSites.map((i) => (
<div className={s.sitesItem}>
<Link
className={s.siteAddress}
target="_blank"
theme="clear"
href={i.address + "?from=Searching.ton"}
onClick={()=>count('from_main_new_sites_widget_to_site')}
>
{getDomainFromUrl(i.address)}
<Button onClick={console.log} className={s.siteButton} theme="primary">
.ton
</Button>
</Link>
</div>
))}
</div>
<Button onClick={console.log} className={s.button} theme="primary">
.ton
</Button>
</div>
</div>
)
}
export default LastSitesWidget

1
searching-front/app/core/pages/Main/LastSitesWidget/index.tsx

@ -0,0 +1 @@
export {default} from './LastSitesWidget';

170
searching-front/app/core/pages/Main/LastSitesWidget/styles.module.css

@ -0,0 +1,170 @@
.root {
margin-top: 100px;
overflow: hidden;
position: relative;
padding: 10px;
}
.link{
margin-left: 10px;
}
.heading {
margin-bottom: 25px;
font-size: 16px;
line-height: 20px;
color: var(--text_secondary)
}
.sitesWrapperShadows {
position: relative;
display: flex;
overflow: hidden;
justify-content: end;
}
.sitesWrapper {
height: 140px;
display: flex;
flex-direction: column;
transition: transform 1s ease-in-out;
animation: animateLastSites 40s ease-in-out 2s infinite alternate;
}
.sitesWrapperShadows:before {
content: "";
height: 83px;
width: 100%;
position: absolute;
bottom: 0;
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, var(--background_main) 89%);
z-index: 1;
pointer-events: none;
}
.sitesWrapper {
}
.siteButton,
.button {
width: 52px;
height: 41px;
font-size: 20px;
line-height: 25px;
border-radius: 16px;
transition: opacity 0.2s ease-in-out;
padding: 0;
}
.button {
position: absolute;
top: 2px;
background-color: var(--background_secondary) !important;
}
.sitesWrapperShadows:hover .button {
opacity: 0;
pointer-events: none;
}
.sitesItem {
height: 25px;
position: relative;
padding: 10px 0;
cursor: pointer;
display: flex;
justify-content: right;
align-items: center;
position: relative;
}
.sitesItem:hover {
z-index: 3;
}
.siteButton {
top: 0;
right: -62px;
opacity: 0;
pointer-events: none;
margin-left: 10px;
}
.sitesItem:hover .siteButton {
opacity: 1;
pointer-events: all;
}
.siteAddress {
text-align: right;
font-size: 16px;
}
@keyframes animateLastSites {
0% {
transform: translateY(0);
}
5% {
transform: translateY(0);
}
10% {
transform: translateY(-45px);
}
15% {
transform: translateY(-45px);
}
20% {
transform: translateY(-90px);
}
25% {
transform: translateY(-90px);
}
30% {
transform: translateY(-135px);
}
35% {
transform: translateY(-135px);
}
40% {
transform: translateY(-180px);
}
45% {
transform: translateY(-180px);
}
50% {
transform: translateY(-225px);
}
55% {
transform: translateY(-225px);
}
60% {
transform: translateY(-270px);
}
65% {
transform: translateY(-270px);
}
70% {
transform: translateY(-315px);
}
75% {
transform: translateY(-315px);
}
80% {
transform: translateY(-360px);
}
85% {
transform: translateY(-360px);
}
90% {
transform: translateY(-405px);
}
100% {
transform: translateY(-405px);
}
}

10
searching-front/app/core/pages/Main/Main.tsx

@ -1,12 +1,20 @@
import { NftDomain } from "@prisma/client"
import SearchForm from "app/core/components/SearchForm"
import TonBrilliant from "app/core/components/TonBrilliant"
import LastSitesWidget from "./LastSitesWidget"
import s from "./styles.module.css"
const Main = () => {
interface Props {
lastWeekNewSites: NftDomain[]
}
const Main = (props:Props) => {
return (
<div className={s.root}>
<TonBrilliant />
<SearchForm />
<LastSitesWidget {...props} />
</div>
)
}

4
searching-front/app/core/pages/Main/styles.module.css

@ -4,5 +4,7 @@
/* justify-content: center; */
align-items: center;
flex: 1;
margin-bottom: 200px;
margin:auto;
max-width: 600px;
width: 100%;
}

8
searching-front/app/core/pages/Search/styles.module.css

@ -1,9 +1,5 @@
.root {
/* display: flex; */
/* flex-direction: column;
justify-content: center; */
/* align-items: center; */
/* height: 100%; */
width: 100%;
max-width: 604px;
max-width: 600px;
margin: 0 auto;
}

75
searching-front/app/core/pages/State/State.tsx

@ -9,9 +9,13 @@ import "chart.js/auto"
import getActualSitesState from "app/stateSites/queries/getActualSitesState"
import getHistoryOfSitesState from "app/stateSites/queries/getHistoryOfSitesState"
import { InfluxPeriod } from "services/modules/influxdb/types"
import { cn } from "app/core/helpers/common"
import { cn, getDomainFromUrl } from "app/core/helpers/common"
import s from "./styles.module.css"
import { NftDomain } from "@prisma/client"
import Button from "app/auth/components/Button"
import Link from "app/core/components/Link"
import { count } from "app/core/helpers/metrika"
interface HistoryOfStateItem {
value: number
@ -26,23 +30,12 @@ interface HistoryOfState {
export interface StatePageProps {
actualState: Awaited<ReturnType<typeof getActualSitesState>>
historyOfState: HistoryOfState
lastWeekNewSites: NftDomain[]
}
const availableSitesColor = "#08c"
const allSitesColor = "hsl(200 15% 81% / 1)"
const getDohnutData = (data: number[]) => ({
labels: ["Available", "All"],
datasets: [
{
data: data,
backgroundColor: [availableSitesColor, allSitesColor],
borderColor: [availableSitesColor, "rgba(0,0,0,0)"],
borderWidth: 1,
},
],
})
const liteOptions = {
responsive: true,
plugins: {
@ -91,7 +84,11 @@ const HistoryItem = ({ data, title }: HistoryItemProps) => {
)
}
const State = ({ actualState, historyOfState: historyOfStatePreloaded }: StatePageProps) => {
const State = ({
actualState,
historyOfState: historyOfStatePreloaded,
lastWeekNewSites,
}: StatePageProps) => {
const [historyPeriod, setHistoryPeriod] = useState(InfluxPeriod.D)
const { t } = useTranslation()
const [historyOfState] = useQuery(getHistoryOfSitesState, historyPeriod, {
@ -102,18 +99,38 @@ const State = ({ actualState, historyOfState: historyOfStatePreloaded }: StatePa
console.log(historyPeriod, historyOfState)
return (
<div className={s.root}>
<div className={s.title}>{t("state.title")}</div>
<div className={s.doughnutAvailable}>
<Doughnut
data={getDohnutData([actualState.availableDomainsCount, actualState.allDomainsCount])}
/>
</div>
<div className={s.actualStateWrapper}>
<span className={s.availableCount}>{actualState.availableDomainsCount}</span>{" "}
{t("state.siteOutOf")} <span className={s.allCount}>{actualState.allDomainsCount}</span>
<span className={s.areNowAvailable}>{t("state.areNowAvailable")}</span>
<div className={s.counterWrapper}>
<span className={s.availableCount}>{actualState.availableDomainsCount}</span>
<span className={s.allCount}>/ {actualState.allDomainsCount}</span>
<div className={s.counterFooter}>
<div className={s.areNowAvailable}>{t("state.areNowAvailable")}</div>
<div className={s.counterDate}>9 september</div>
</div>
</div>
</div>
{historyOfState && (
<div className={s.newestTitle}>
10 newest <span className={s.newestTitleTon}>TON</span> sites
</div>
<div className={s.newestListWrapper}>
{lastWeekNewSites.map((i) => (
<Link
target="_blank"
theme="clear"
href={i.address + "?from=Searching.ton"}
wide
className={s.newestListItem}
onClick={()=>count('from_state_page_to_site')}
>
{getDomainFromUrl(i.address)}
<Button onClick={console.log} className={s.siteButton} theme="primary">
.ton
</Button>
</Link>
))}
</div>
{/* {historyOfState && (
<div className={s.historyStateWrapper}>
<div className={s.historyStatePeriodsWrapper}>
{Object.values(InfluxPeriod).map((i) => (
@ -124,8 +141,8 @@ const State = ({ actualState, historyOfState: historyOfStatePreloaded }: StatePa
{i}
</button>
))}
</div>
<HistoryItem
</div> */}
{/* <HistoryItem
title="Available sites count"
data={getGraphData(
historyOfState.available,
@ -136,9 +153,9 @@ const State = ({ actualState, historyOfState: historyOfStatePreloaded }: StatePa
<HistoryItem
title="All sites count"
data={getGraphData(historyOfState.all, "All sites count", allSitesColor)}
/>
</div>
)}
/> */}
{/* </div> */}
{/* )} */}
</div>
)
}

102
searching-front/app/core/pages/State/styles.module.css

@ -1,26 +1,106 @@
.root {
/* margin-right: var(--logoWrapperWidth); */
width: 100vw;
max-width: 600px;
margin: 0 auto;
}
.actualStateWrapper {
width: 100%;
padding: 20px 24px;
font-size: 20px;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
background: rgba(26, 148, 255, 0.06);
border-radius: var(--border_radius_base);
margin-bottom: 60px;
box-sizing: border-box;
}
.availableCount {
font-size: 100px;
margin-right: 10px;
color: var(--button_primary);
font-weight: bold;
font-weight: 700;
font-size: 32px;
line-height: 40px;
margin-right: 8px;
}
.allCount {
margin: 0px 10px;
font-size: 30px;
color: var(--text_secondary);
font-weight: bold;
font-size: 24px;
line-height: 30px;
color: #ffffff;
opacity: 0.4;
}
.areNowAvailable {
margin-top: 6px;
font-weight: 700;
font-size: 16px;
line-height: 20px;
}
.counterFooter {
display: flex;
justify-content: space-between;
align-items: flex-end;
}
.counterDate {
font-weight: 400;
font-size: 12px;
line-height: 15px;
color: #ffffff;
opacity: 0.32;
}
.newestTitle {
text-align: center;
font-weight: 900;
font-size: 32px;
line-height: 40px;
margin-bottom: 32px;
}
.newestTitleTon {
color: var(--button_primary);
}
.newestListWrapper {
display: flex;
flex-direction: column;
}
.newestListItem {
padding: 24px 34px;
border-radius: var(--border_radius_base);
border: 1px solid var(--border_color_main);
text-transform: capitalize;
font-weight: 700;
font-size: 16px;
line-height: 20px;
cursor: pointer;
position: relative;
}
.siteButton.siteButton {
width: 52px;
height: 41px;
font-size: 20px;
line-height: 25px;
border-radius: 16px;
transition: opacity 0.2s ease-in-out;
padding: 0;
background-color: var(--background_secondary);
margin-left: 8px;
}
.newestListItem:hover .siteButton.siteButton {
background-color: var(--button_primary);
}
.button {
position: absolute;
top: 2px;
right: 22px;
background-color: var(--background_secondary);
}
.newestListItem:not(:last-child) {
margin-bottom: 20px;
}
.doughnutAvailable {
width: 200px;

2
searching-front/app/core/variables.css

@ -10,6 +10,8 @@ body {
--toncoin_header: #353538;
--toncoin_gradient: linear-gradient(297.97deg, #232328 9.93%, #343437 76.88%);
--StripeMenuWhite: #fff;
--layout-padding: 20px;
--border_radius_base: 24px;
}
body {

16
searching-front/app/stateSites/queries/getLastWeekNewSites.ts

@ -0,0 +1,16 @@
import { subDays } from "date-fns"
import db from "db"
export default async function getLastWeekNewSites() {
const weekAgo = subDays(new Date(), 7)
const lastWeekNewSites = await db.nftDomain.findMany({
orderBy: { firstAvailableDate: "desc" },
take: 10,
where: { available: true, AND: { firstAvailableDate: { gt: weekAgo } } },
})
console.log(lastWeekNewSites)
return {
lastWeekNewSites,
}
}

46
searching-front/pages/auth/forgot-password.tsx

@ -1,46 +0,0 @@
import Layout from "app/core/layouts/Layout"
import { LabeledTextField } from "app/core/components/LabeledTextField"
import { Form, FORM_ERROR } from "app/core/components/Form"
import { ForgotPassword } from "app/auth/validations"
import forgotPassword from "app/auth/mutations/forgotPassword"
import { useMutation } from "@blitzjs/rpc"
import { BlitzPage } from "@blitzjs/next"
const ForgotPasswordPage: BlitzPage = () => {
const [forgotPasswordMutation, { isSuccess }] = useMutation(forgotPassword)
return (
<Layout title="Forgot Your Password?">
<h1>Forgot your password?</h1>
{isSuccess ? (
<div>
<h2>Request Submitted</h2>
<p>
If your email is in our system, you will receive instructions to reset your password
shortly.
</p>
</div>
) : (
<Form
submitText="Send Reset Password Instructions"
schema={ForgotPassword}
initialValues={{ email: "" }}
onSubmit={async (values) => {
try {
await forgotPasswordMutation(values)
} catch (error: any) {
return {
[FORM_ERROR]: "Sorry, we had an unexpected error. Please try again.",
}
}
}}
>
<LabeledTextField name="email" label="Email" placeholder="Email" />
</Form>
)}
</Layout>
)
}
export default ForgotPasswordPage

21
searching-front/pages/auth/login.tsx

@ -1,21 +0,0 @@
import { BlitzPage } from "@blitzjs/next"
import Layout from "app/core/layouts/Layout"
import { LoginForm } from "app/auth/components/LoginForm"
import { useRouter } from "next/router"
const LoginPage: BlitzPage = () => {
const router = useRouter()
return (
<Layout title="Log In">
<LoginForm
onSuccess={(_user) => {
const next = router.query.next ? decodeURIComponent(router.query.next as string) : "/"
return router.push(next)
}}
/>
</Layout>
)
}
export default LoginPage

66
searching-front/pages/auth/reset-password.tsx

@ -1,66 +0,0 @@
import Layout from "app/core/layouts/Layout"
import { LabeledTextField } from "app/core/components/LabeledTextField"
import { Form, FORM_ERROR } from "app/core/components/Form"
import { ResetPassword } from "app/auth/validations"
import resetPassword from "app/auth/mutations/resetPassword"
import { BlitzPage, Routes } from "@blitzjs/next"
import { useRouter } from "next/router"
import { useMutation } from "@blitzjs/rpc"
import Link from "next/link"
const ResetPasswordPage: BlitzPage = () => {
const router = useRouter()
const [resetPasswordMutation, { isSuccess }] = useMutation(resetPassword)
return (
<div>
<h1>Set a New Password</h1>
{isSuccess ? (
<div>
<h2>Password Reset Successfully</h2>
<p>
Go to the <Link href={Routes.Home()}>homepage</Link>
</p>
</div>
) : (
<Form
submitText="Reset Password"
schema={ResetPassword}
initialValues={{
password: "",
passwordConfirmation: "",
token: router.query.token as string,
}}
onSubmit={async (values) => {
try {
await resetPasswordMutation(values)
} catch (error: any) {
if (error.name === "ResetPasswordError") {
return {
[FORM_ERROR]: error.message,
}
} else {
return {
[FORM_ERROR]: "Sorry, we had an unexpected error. Please try again.",
}
}
}
}}
>
<LabeledTextField name="password" label="New Password" type="password" />
<LabeledTextField
name="passwordConfirmation"
label="Confirm New Password"
type="password"
/>
</Form>
)}
</div>
)
}
ResetPasswordPage.redirectAuthenticatedTo = "/"
ResetPasswordPage.getLayout = (page) => <Layout title="Reset Your Password">{page}</Layout>
export default ResetPasswordPage

16
searching-front/pages/auth/signup.tsx

@ -1,16 +0,0 @@
import { useRouter } from "next/router"
import Layout from "app/core/layouts/Layout"
import { SignupForm } from "app/auth/components/SignupForm"
import { BlitzPage, Routes } from "@blitzjs/next"
const SignupPage: BlitzPage = () => {
const router = useRouter()
return (
<Layout title="Sign Up">
<SignupForm onSuccess={() => router.push(Routes.Home())} />
</Layout>
)
}
export default SignupPage

24
searching-front/pages/index.tsx

@ -26,8 +26,16 @@ import {
ServerSidePropsContext,
} from "app/core/contextProviders/serverSidePropsProvider"
import { gSSP } from "app/blitz-server"
import ContextProviders from "app/core/components/ContextProviders"
import getLastWeekNewSites from "app/stateSites/queries/getLastWeekNewSites"
import { NftDomain } from "@prisma/client"
const Home: BlitzPage = (props) => {
interface Props {
lastWeekNewSites: NftDomain[]
cookies: Record<string,string>
}
const Home: BlitzPage<Props> = (props) => {
return (
<ErrorBoundary
FallbackComponent={ErrorFallback}
@ -35,17 +43,23 @@ const Home: BlitzPage = (props) => {
// reset the state of your app so the error doesn't happen again
}}
>
<ServerSidePropsContext.Provider value={props}>
<ContextProviders contextParamsServer={props}>
<Layout title="Searching" withoutPaddings>
<Suspense fallback="Loading...">
<Main />
<Main lastWeekNewSites={props.lastWeekNewSites}/>
</Suspense>
</Layout>
</ServerSidePropsContext.Provider>
</ContextProviders>
</ErrorBoundary>
)
}
export const getServerSideProps = gSSP(serverSideProps)
export const getServerSideProps = gSSP(
serverSideProps(async () => {
return {
...(await getLastWeekNewSites()),
}
})
)
export default Home

14
searching-front/pages/s.tsx

@ -1,11 +1,6 @@
import { Suspense } from "react"
import Image from "next/image"
import Link from "next/link"
import Layout from "app/core/layouts/Layout"
import { useCurrentUser } from "app/core/hooks/useCurrentUser"
import logout from "app/auth/mutations/logout"
import logo from "public/logo.png"
import { useMutation } from "@blitzjs/rpc"
import { Routes, BlitzPage } from "@blitzjs/next"
import Search from "app/core/pages/Search"
@ -15,6 +10,7 @@ import {
serverSideProps,
ServerSidePropsContext,
} from "app/core/contextProviders/serverSidePropsProvider"
import ContextProviders from "app/core/components/ContextProviders"
function ErrorFallback({ error, resetErrorBoundary }) {
return (
@ -35,17 +31,17 @@ const SearchPage: BlitzPage = (props) => {
// reset the state of your app so the error doesn't happen again
}}
>
<ServerSidePropsContext.Provider value={props}>
<ContextProviders contextParamsServer={props}>
<Layout title="Searching">
<Suspense fallback="Loading....">
<Search />
</Suspense>
</Layout>
</ServerSidePropsContext.Provider>
</ContextProviders>
</ErrorBoundary>
)
}
export const getServerSideProps = gSSP(serverSideProps)
export const getServerSideProps = gSSP(serverSideProps())
export default SearchPage

33
searching-front/pages/state.tsx

@ -5,15 +5,18 @@ import getActualSitesState from "app/stateSites/queries/getActualSitesState"
import getHistoryOfSitesState from "app/stateSites/queries/getHistoryOfSitesState"
import { BlitzPage } from "@blitzjs/next"
import State from "app/core/pages/State"
import { gSP } from "app/blitz-server"
import { ErrorBoundary } from "@blitzjs/next"
import { gSSP } from "app/blitz-server"
import {
serverSideProps,
ServerSidePropsContext,
} from "app/core/contextProviders/serverSidePropsProvider"
import { ErrorBoundary } from "@blitzjs/next"
import { StatePageProps } from "app/core/pages/State/State"
import { StaticPageProps } from "app/core/commonTypes"
import ContextProviders from "app/core/components/ContextProviders"
import getLastWeekNewSites from "app/stateSites/queries/getLastWeekNewSites"
function ErrorFallback({ error, resetErrorBoundary }) {
return (
@ -25,7 +28,8 @@ function ErrorFallback({ error, resetErrorBoundary }) {
)
}
const StatePage: BlitzPage<StatePageProps> = (props) => {
const StatePage: BlitzPage = (props) => {
return (
<ErrorBoundary
FallbackComponent={ErrorFallback}
@ -33,26 +37,27 @@ const StatePage: BlitzPage<StatePageProps> = (props) => {
// reset the state of your app so the error doesn't happen again
}}
>
<ServerSidePropsContext.Provider value={props}>
<ContextProviders contextParamsServer={props}>
<Layout title="State of TON Sites" withoutPaddings>
<Suspense fallback="Loading....">
<State {...props} />
</Suspense>
</Layout>
</ServerSidePropsContext.Provider>
</ContextProviders>
</ErrorBoundary>
)
}
export const getServerSideProps = async ({ params, ctx }): StaticPageProps<StatePageProps> => {
const actualState = await getActualSitesState();
const historyOfState = await getHistoryOfSitesState();
export const getServerSideProps = gSSP(
serverSideProps(async (): Promise<StatePageProps> => {
const actualState = await getActualSitesState()
const historyOfState = await getHistoryOfSitesState()
return {
props: {
actualState,
historyOfState
},
historyOfState,
...(await getLastWeekNewSites()),
}
}
})
)
export default StatePage

BIN
searching-front/public/favicon copy.ico

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

BIN
searching-front/public/favicon.ico

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

BIN
searching-front/public/logo copy.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

BIN
searching-front/public/logo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

16
searching-front/services/main.ts

@ -6,15 +6,15 @@ import parser from "./parser"
import influx from "./influx"
const run = async()=>{
console.log('Start domain watcher')
console.time('watcher')
await domainWatcher();
console.timeEnd('watcher')
influx()
console.log('Start parser');
console.time('watcher');
// console.log('Start domain watcher')
// console.time('watcher')
// await domainWatcher();
// console.timeEnd('watcher')
// influx()
// console.log('Start parser');
// console.time('watcher');
await parser();
console.timeEnd('watcher');
// console.timeEnd('watcher');
}

3
searching-front/services/modules/parser/index.ts

@ -31,6 +31,7 @@ class Parser {
const { data, headers } = await axios.get(url,{
proxy: getTonProxy(),
})
const contentType = headers["content-type"].toLocaleLowerCase()
if (!contentType.startsWith('text/html')) {
@ -69,7 +70,7 @@ class Parser {
subPages,
}
} catch (e) {
console.log("Parse error ", url)
console.log("Parse error ",e, url)
return SHOULD_NOT_PARSE
}
}

5
searching-front/services/parser.ts

@ -11,10 +11,12 @@ const findFirstNotIndexed = (subpages: SubPages = {}) => {
}
const indexWebsite = async (domain: string, path: string, subpages: SubPages = {},count=0) => {
console.log(subpages)
const subpagesLength = Object.keys(subpages).length;
if (!subpages[path]) {
const url = domain + path;
const parseInfo = await Parser.parseUrl(url)
console.log(parseInfo)
subpages[path] = true
let pages = {}
if (parseInfo !== SHOULD_NOT_PARSE && subpagesLength < 50) {
@ -40,6 +42,9 @@ const indexWebsite = async (domain: string, path: string, subpages: SubPages = {
const main = async () => {
await indexWebsite('http://planets.ton', "/")
console.log('finish')
return
await Elastic.initElastic()
const domains = await db.nftDomain.findMany({where:{available: true}})
console.log('Find domains', domains)

Loading…
Cancel
Save