├── .gitattributes ├── .gitignore ├── Dockerfile ├── README.md ├── components ├── APIVerify.ts ├── Libs │ ├── Bold.tsx │ ├── Cap.ts │ ├── Checkbox.tsx │ ├── Circle.tsx │ ├── Comment.tsx │ ├── Component.ts │ ├── Copy.ts │ ├── CountDown.tsx │ ├── Country2Lang.json │ ├── CountryList.tsx │ ├── CurrencyChooserFloat.tsx │ ├── DropDown.tsx │ ├── FindEmojies.ts │ ├── FirstTimeComponentLoad.ts │ ├── Flag.tsx │ ├── FormBackMaker.ts │ ├── FormM.tsx │ ├── FormS.tsx │ ├── FormV.tsx │ ├── GridBtn.tsx │ ├── HandRankExplore.tsx │ ├── HashTrack.tsx │ ├── Icon2CurrencySelectFloat.tsx │ ├── Icon2Titles.tsx │ ├── Icon2TitlesWide.tsx │ ├── Icon3Titles.tsx │ ├── ItemList.tsx │ ├── ItemListFloat.tsx │ ├── LWChart.js │ ├── Langs.ts │ ├── LightweightChart │ │ ├── dev.cjs │ │ ├── production.js │ │ └── types.ts │ ├── LinkHashtags.tsx │ ├── LogFloat.tsx │ ├── Lorem.tsx │ ├── NewUpload.tsx │ ├── Num2EN.tsx │ ├── Num2FA.tsx │ ├── NumAbbrev.ts │ ├── OpeningDetail.tsx │ ├── OpeningTitle.tsx │ ├── PhoneBox.tsx │ ├── PhoneEditFloat.tsx │ ├── PriceRaw.tsx │ ├── PriceTextBox.tsx │ ├── ProfileImage.tsx │ ├── ReplacePro.tsx │ ├── ReplaceWordRegex.ts │ ├── Search.tsx │ ├── SearchFilter.tsx │ ├── SerialGenerator.ts │ ├── ServiceExpiration.ts │ ├── StarRating.tsx │ ├── Text.tsx │ ├── TextArea.tsx │ ├── TextAreaEditFloat.tsx │ ├── TextBox.tsx │ ├── TextBoxBottom.tsx │ ├── TextCenter.tsx │ ├── TextChat.tsx │ ├── TextEditFloat.tsx │ ├── TextEndAbbreviation.ts │ ├── TextMidAbbreviation.ts │ ├── ToLocaleDateTime.tsx │ ├── UniqueInterval.ts │ ├── Upload.tsx │ ├── UploadBox.tsx │ ├── UploadSingleBox.tsx │ ├── UploadVisibility.tsx │ ├── UserAvatar.tsx │ ├── VItem.tsx │ ├── VItemList.tsx │ ├── WalletList.tsx │ ├── Window.tsx │ ├── WindowFloat.tsx │ ├── emoji.json │ ├── lightstreamer.js │ ├── replaveServerDates.ts │ └── useNVState.ts ├── Pages │ └── index.tsx ├── Parent │ ├── Declarations.ts │ ├── Progress.ts │ ├── Prompt.tsx │ ├── QELoader.tsx │ ├── QSON.ts │ └── Scroller.ts ├── ROOT │ ├── Declarations.ts │ ├── Lang.ts │ ├── Mongo.ts │ ├── OnExit.ts │ ├── Schedule │ │ ├── H1.ts │ │ ├── Job │ │ │ ├── JD1.ts │ │ │ ├── JH1.ts │ │ │ ├── JM1.ts │ │ │ ├── JM15.ts │ │ │ ├── JM30.ts │ │ │ └── JM5.ts │ │ ├── M1.ts │ │ ├── M15.ts │ │ ├── M30.ts │ │ ├── M5.ts │ │ ├── S10.ts │ │ └── S30.ts │ ├── TimeOffset.ts │ ├── Websocket.ts │ └── Websocket │ │ ├── echo.ts │ │ ├── hook.ts │ │ ├── subscribe.ts │ │ └── worker.ts ├── SSRVerify.ts ├── SiteConfig.ts ├── User.ts └── UserSSR.ts ├── global.css ├── global.d.ts ├── lib └── mongodb.ts ├── next.config.mjs ├── package-lock.json ├── package.json ├── pages ├── [...path].tsx ├── _app.tsx ├── api │ ├── lang.ts │ ├── login.ts │ ├── ping.ts │ ├── robots.ts │ ├── sitemap.ts │ ├── test.ts │ └── umongo │ │ ├── collections.ts │ │ └── create.ts ├── index.tsx └── stylesx.css ├── process.d.ts ├── public ├── next.svg ├── vercel.svg └── wp.webp ├── startup.ts ├── styles ├── Home.module.css └── globals.css ├── tsconfig.json ├── uweather.png └── yarn.lock /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | 38 | /push.exe -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:20-alpine AS base 2 | 3 | # Install dependencies only when needed 4 | FROM base AS deps 5 | # Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. 6 | RUN apk add --no-cache libc6-compat 7 | 8 | WORKDIR /app 9 | 10 | # Install dependencies based on the preferred package manager 11 | COPY . /app 12 | # RUN yarn 13 | 14 | RUN ["npm", "install"] 15 | 16 | RUN ["npm", "run", "build"] 17 | 18 | # Rebuild the source code only when needed 19 | # FROM base AS builder 20 | # WORKDIR /app 21 | # COPY --from=deps /app/node_modules ./node_modules 22 | # COPY . . 23 | 24 | # Next.js collects completely anonymous telemetry data about general usage. 25 | # Learn more here: https://nextjs.org/telemetry 26 | # Uncomment the following line in case you want to disable telemetry during the build. 27 | # ENV NEXT_TELEMETRY_DISABLED 1 28 | 29 | # RUN yarn run build 30 | 31 | # Production image, copy all the files and run next 32 | # FROM base AS runner 33 | # WORKDIR /app 34 | 35 | # ENV NODE_ENV production 36 | # # Uncomment the following line in case you want to disable telemetry during runtime. 37 | # # ENV NEXT_TELEMETRY_DISABLED 1 38 | 39 | # RUN addgroup --system --gid 1001 nodejs 40 | # RUN adduser --system --uid 1001 nextjs 41 | 42 | # COPY --from=builder /app/public ./public 43 | 44 | # Set the correct permission for prerender cache 45 | # RUN mkdir .next 46 | # RUN chown nextjs:nodejs .next 47 | 48 | # Automatically leverage output traces to reduce image size 49 | # https://nextjs.org/docs/advanced-features/output-file-tracing 50 | # COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ 51 | # COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ 52 | # COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static 53 | 54 | # USER nextjs 55 | 56 | EXPOSE 3002 57 | EXPOSE 3000 58 | 59 | # ENV PORT 2600 60 | 61 | # server.js is created by next build from the standalone output 62 | # https://nextjs.org/docs/pages/api-reference/next-config-js/output 63 | # CMD HOSTNAME="0.0.0.0" node server.js 64 | CMD ["yarn", "start", "-p", "3000"] 65 | # CMD node -e "setInterval(()=>{},1000)" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a Uservice project developed by Me, a member of the Turing Research Team. 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev -- -p 2000 9 | # or 10 | yarn dev -p 2000 11 | ``` 12 | 13 | 14 | 15 | Open [https://xtal.ir/userv](https://xtal.ir/userv) with your browser to see the result. 16 | 17 | You can start editing the page by modifying `components/Pages/index.tsx`. The page auto-updates as you edit the file. 18 |
19 |
20 | 21 | 22 |
23 | Best regards. 24 |
25 |
26 | -------------------------------------------------------------------------------- /components/APIVerify.ts: -------------------------------------------------------------------------------- 1 | import { ObjectId } from "mongodb" 2 | import { NextApiRequest, NextApiResponse } from "next" 3 | 4 | import requestIp from 'request-ip' 5 | 6 | export type APISession = { 7 | uid: string, 8 | name: string, 9 | image: string, 10 | imageprop: { 11 | zoom: number, 12 | x: number, 13 | y: number, 14 | portion: number, 15 | refw: number 16 | }, 17 | cchar: string, 18 | unit: string, 19 | workspace: string, 20 | servid: ObjectId, 21 | servsecret: string, 22 | usedquota: number, 23 | quota: number, 24 | quotaunit: string, 25 | status: "approved" | "rejected" | "waiting", 26 | regdate: number, 27 | expid: ObjectId, 28 | role: string | null, 29 | path: string, 30 | devmod: boolean, 31 | userip: string, 32 | body: any 33 | } 34 | 35 | export default async (req: NextApiRequest, res: NextApiResponse): Promise => { 36 | 37 | if (global.Startup != "OK") { 38 | if (global.Startup == "PENDING") { 39 | await new Promise(r => setInterval(() => { if (global.Startup != "PENDING") r(null); else console.log("WAITING...") }, 100)) 40 | } 41 | else { 42 | global.Startup = "PENDING"; 43 | await (await import("../startup.ts")).Run() 44 | global.Startup = "OK"; 45 | } 46 | } 47 | 48 | const userip = (requestIp.getClientIp(req)?.replace("::ffff:", "")) || "::" 49 | var post = req.method?.toLowerCase() == "post" 50 | 51 | if (post && !(req.body.startsWith("{") || req.body.startsWith("["))) { 52 | return ({ userip }) as APISession 53 | } 54 | var body = post ? JSON.parse(req.body) : null; 55 | 56 | if (post) { 57 | if (body?.expid) { 58 | body.expid = new global.ObjectId(body.expid) 59 | } 60 | if (body?.servid) { 61 | body.servid = new global.ObjectId(body.servid) 62 | } 63 | if (body?.chatid) { 64 | body.chatid = new global.ObjectId(body.chatid) 65 | } 66 | if (body?.msgid) { 67 | body.msgid = new global.ObjectId(body.msgid) 68 | } 69 | if (body?.transid) { 70 | body.transid = new global.ObjectId(body.transid) 71 | } 72 | if (body?.uid) { 73 | body.uid = new global.ObjectId(body.uid) 74 | } 75 | } 76 | 77 | if ((body?.passcode || body?.PASSCODE) && (body?.passcode || body?.PASSCODE) == process.env.PASSCODE) { 78 | return { 79 | name: "Service Bot", 80 | role: "admin", 81 | userip: "0.0.0.0", 82 | uid: new global.ObjectId("635111afff61db2b04928f45"), 83 | body, 84 | } as APISession 85 | } 86 | 87 | 88 | let session = JSON.parse(`{}`) 89 | let cookies = await import("cookies-next") 90 | 91 | if (cookies.hasCookie("session", { req, res })) { 92 | try { 93 | session = cookies.getCookie("session", { req, res }) 94 | session = JSON.parse(decodeURIComponent(session)) 95 | } catch { } 96 | } 97 | 98 | 99 | let srv = {} as any 100 | let user = null; 101 | if (session.servid) { 102 | srv = await api("http://localhost:3000/api/userv/servid", { 103 | servid: session.servid, 104 | servsecret: session.servsecret, 105 | }) 106 | 107 | 108 | let u = global.db.collection("users") 109 | let users = await u.find({}).project({ _id: 0 }).toArray() 110 | 111 | for (let usr of users) { 112 | if (MD5(usr.usersecret) == srv.usersecrethash) { 113 | user = usr 114 | } 115 | } 116 | } 117 | 118 | if (session.servid) { 119 | session.servid = new ObjectId(session.servid) 120 | } 121 | if (session.expid) { 122 | session.expid = new ObjectId(session.expid) 123 | } 124 | 125 | console.log(session) 126 | 127 | 128 | return { 129 | 130 | ...session, 131 | ...srv, 132 | body, 133 | role: user?.role || null, 134 | nodeenv: global.nodeenv, 135 | userip 136 | } as APISession 137 | } -------------------------------------------------------------------------------- /components/Libs/Bold.tsx: -------------------------------------------------------------------------------- 1 | export default (props)=>{ 2 | return {props.on?.()}}>{props.children} 5 | } -------------------------------------------------------------------------------- /components/Libs/Cap.ts: -------------------------------------------------------------------------------- 1 | export default (txt:string):string=> txt.charAt(0).toUpperCase() + txt.slice(1); -------------------------------------------------------------------------------- /components/Libs/Checkbox.tsx: -------------------------------------------------------------------------------- 1 | import { CSSProperties } from "react"; 2 | 3 | export default (props:{on:(cheched:boolean)=>{}, style?:CSSProperties, 4 | defaultChecked?:boolean, defaultValue?:boolean})=> 5 | { 6 | let uid = Math.floor(Math.random()*1000); 7 | return
8 | { 10 | props.on?.(e.target.checked) 11 | }} autoComplete="off"/> 12 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | } -------------------------------------------------------------------------------- /components/Libs/Circle.tsx: -------------------------------------------------------------------------------- 1 | 2 | export default (props)=>{ 3 | function getProgressCircleValues(percentage, radius = 45) { 4 | if (percentage < 0 || percentage > 100) { 5 | throw new Error('Percentage must be between 0 and 100'); 6 | } 7 | 8 | // Calculate the circumference of the circle 9 | const circumference = 2 * Math.PI * radius; 10 | 11 | // Calculate stroke-dasharray and stroke-dashoffset 12 | const strokeDasharray = circumference; 13 | const strokeDashoffset = circumference - (percentage / 100 * circumference); 14 | 15 | return { 16 | strokeDasharray: strokeDasharray.toFixed(2), 17 | strokeDashoffset: strokeDashoffset.toFixed(2) 18 | }; 19 | } 20 | 21 | let v = getProgressCircleValues(props.percent) 22 | 23 | return 24 | 25 | 26 | 28 | {props.percent+"%"} 29 | 30 | 31 | } -------------------------------------------------------------------------------- /components/Libs/Comment.tsx: -------------------------------------------------------------------------------- 1 | 2 | import Bold from './Bold' 3 | 4 | export default (props: { 5 | image: string, on?: () => void, 6 | s?: number, title: string, comment: string 7 | }) => { 8 | return
props.on?.()}> 9 | 10 | 11 | 12 | 13 | 14 |

15 | {props.title} 16 | {props.comment}

17 |
18 |
19 |
20 |
21 | } 22 | -------------------------------------------------------------------------------- /components/Libs/Component.ts: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | 3 | export type PageEl = (props: { [key in any]: any }, state: { [key in any]: any }, refresh: (object?: { [key in any]: any }) => void, getProps: (callback: () => Promise) => void) => JSX.Element 4 | 5 | const convertor = (props: any, Page: PageEl) => { 6 | let [state, setState] = useState({ loaded: false, }) 7 | let [r, setR] = useState(0) 8 | const setst = (obj) => { 9 | 10 | if (obj) { 11 | Object.keys(obj).forEach(k => { 12 | state[k] = obj[k] 13 | }) 14 | } 15 | state["kdt"] = new Date().getTime() 16 | setState(state) 17 | setR(new Date().getTime()) 18 | // setState({ ...state, ...obj }) 19 | } 20 | return Page(props, state, setst, async (func) => { 21 | if (!state.loaded) { 22 | await func(); 23 | state["loaded"] = true 24 | state["kdt"] = new Date().getTime() 25 | setState(state) 26 | setR(new Date().getTime()) 27 | // setState({ ...state, loaded: true }) 28 | } 29 | }) 30 | } 31 | 32 | 33 | export default (props: any, Page: PageEl) => { 34 | return convertor(props, Page) 35 | } 36 | -------------------------------------------------------------------------------- /components/Libs/Copy.ts: -------------------------------------------------------------------------------- 1 | export default (textToCopy: string)=> { 2 | // navigator clipboard api needs a secure context (https) 3 | if (navigator.clipboard && window.isSecureContext) { 4 | // navigator clipboard api method' 5 | return navigator.clipboard.writeText(textToCopy); 6 | } else { 7 | // text area method 8 | let textArea = document.createElement("textarea"); 9 | textArea.value = textToCopy; 10 | // make the textarea out of viewport 11 | textArea.style.position = "fixed"; 12 | textArea.style.left = "-999999px"; 13 | textArea.style.top = "-999999px"; 14 | document.body.appendChild(textArea); 15 | textArea.focus(); 16 | textArea.select(); 17 | return new Promise((res, rej) => { 18 | // here the magic happens 19 | document.execCommand('copy') ? res(null) : rej(); 20 | textArea.remove(); 21 | }); 22 | } 23 | } -------------------------------------------------------------------------------- /components/Libs/CountDown.tsx: -------------------------------------------------------------------------------- 1 | export default (props:{ontimeout?:()=>void, onexpire?:()=>void, expdate:number, })=> 2 | { 3 | var exptime = props.expdate; 4 | var updater = null; 5 | var calcnow = ()=> 6 | { 7 | var timer = Math.max(0,Math.floor((exptime - new Date().getTime())/1000)); 8 | var minutes, seconds; 9 | minutes = parseInt((timer / 60).toString(), 10); 10 | seconds = parseInt((timer % 60).toString(), 10); 11 | minutes = minutes < 10 ? "0" + minutes : minutes; 12 | seconds = seconds < 10 ? "0" + seconds : seconds; 13 | return minutes + ":" + seconds; 14 | } 15 | 16 | var countdown = () => 17 | { 18 | var timer = Math.max(0,Math.floor((exptime - new Date().getTime())/1000)); 19 | var minutes, seconds; 20 | let timedout = false; 21 | setTimeout(() => 22 | { 23 | updater = setInterval(()=> 24 | { 25 | minutes = parseInt((timer / 60).toString(), 10); 26 | seconds = parseInt((timer % 60).toString(), 10); 27 | 28 | minutes = minutes < 10 ? "0" + minutes : minutes; 29 | seconds = seconds < 10 ? "0" + seconds : seconds; 30 | // console.log("RUNNING!") 31 | try 32 | { 33 | if(document.getElementById("gl_counter")!=null) 34 | document.getElementById("gl_counter").textContent = minutes + ":" + seconds; 35 | else 36 | clearInterval(updater) 37 | } catch{clearInterval(updater)} 38 | 39 | timer = Math.floor((exptime - new Date().getTime())/1000); 40 | if(timer < 0 && !timedout) 41 | { 42 | timedout = true 43 | clearInterval(updater) 44 | props.onexpire?.() 45 | props.ontimeout?.() 46 | } 47 | }, 200); 48 | }, 100); 49 | } 50 | countdown() 51 | return {calcnow()} 52 | } -------------------------------------------------------------------------------- /components/Libs/Country2Lang.json: -------------------------------------------------------------------------------- 1 | [{"AD":"ca"},{"AE":"ar"},{"AF":"ps"},{"AG":"en"},{"AI":"en"},{"AL":"sq"},{"AM":"hy"},{"AO":"pt"},{"AQ":"en"},{"AR":"es"},{"AS":"en"},{"AT":"de"},{"AU":"en"},{"AW":"nl"},{"AX":"sv"},{"AZ":"az"},{"BA":"bs"},{"BB":"en"},{"BD":"bn"},{"BE":"nl"},{"BF":"fr"},{"BG":"bg"},{"BH":"ar"},{"BI":"fr"},{"BJ":"fr"},{"BL":"fr"},{"BM":"en"},{"BN":"ms"},{"BO":"es"},{"BQ":"nl"},{"BR":"pt"},{"BS":"en"},{"BT":"dz"},{"BV":"no"},{"BW":"en"},{"BY":"be"},{"BZ":"en"},{"CA":"en"},{"CC":"en"},{"CD":"fr"},{"CF":"fr"},{"CG":"fr"},{"CH":"de"},{"CI":"fr"},{"CK":"en"},{"CL":"es"},{"CM":"en"},{"CN":"zh"},{"CO":"es"},{"CR":"es"},{"CU":"es"},{"CV":"pt"},{"CW":"nl"},{"CX":"en"},{"CY":"el"},{"CZ":"cs"},{"DE":"de"},{"DJ":"fr"},{"DK":"da"},{"DM":"en"},{"DO":"es"},{"DZ":"ar"},{"EC":"es"},{"EE":"et"},{"EG":"ar"},{"EH":"es"},{"ER":"ti"},{"ES":"es"},{"ET":"am"},{"FI":"fi"},{"FJ":"en"},{"FK":"en"},{"FM":"en"},{"FO":"fo"},{"FR":"fr"},{"GA":"fr"},{"GB":"en"},{"GD":"en"},{"GE":"ka"},{"GF":"fr"},{"GG":"en"},{"GH":"en"},{"GI":"en"},{"GL":"kl"},{"GM":"en"},{"GN":"fr"},{"GP":"fr"},{"GQ":"es"},{"GR":"el"},{"GS":"en"},{"GT":"es"},{"GU":"en"},{"GW":"pt"},{"GY":"en"},{"HK":"zh"},{"HM":"en"},{"HN":"es"},{"HR":"hr"},{"HT":"fr"},{"HU":"hu"},{"ID":"id"},{"IE":"ga"},{"IL":"he"},{"IM":"en"},{"IN":"hi"},{"IO":"en"},{"IQ":"ar"},{"IR":"fa"},{"IS":"is"},{"IT":"it"},{"JE":"en"},{"JM":"en"},{"JO":"ar"},{"JP":"ja"},{"KE":"en"},{"KG":"ky"},{"KH":"km"},{"KI":"en"},{"KM":"ar"},{"KN":"en"},{"KP":"ko"},{"KR":"ko"},{"KW":"ar"},{"KY":"en"},{"KZ":"kk"},{"LA":"lo"},{"LB":"ar"},{"LC":"en"},{"LI":"de"},{"LK":"si"},{"LR":"en"},{"LS":"en"},{"LT":"lt"},{"LU":"fr"},{"LV":"lv"},{"LY":"ar"},{"MA":"ar"},{"MC":"fr"},{"MD":"ro"},{"ME":"sr"},{"MF":"en"},{"MG":"fr"},{"MH":"en"},{"MK":"mk"},{"ML":"fr"},{"MM":"my"},{"MN":"mn"},{"MO":"zh"},{"MP":"en"},{"MQ":"fr"},{"MR":"ar"},{"MS":"en"},{"MT":"mt"},{"MU":"en"},{"MV":"dv"},{"MW":"en"},{"MX":"es"},{"MY":"ms"},{"MZ":"pt"},{"NA":"en"},{"NC":"fr"},{"NE":"fr"},{"NF":"en"},{"NG":"en"},{"NI":"es"},{"NL":"nl"},{"NO":"no"},{"NP":"ne"},{"NR":"en"},{"NU":"en"},{"NZ":"en"},{"OM":"ar"},{"PA":"es"},{"PE":"es"},{"PF":"fr"},{"PG":"en"},{"PH":"en"},{"PK":"en"},{"PL":"pl"},{"PM":"fr"},{"PN":"en"},{"PR":"es"},{"PS":"ar"},{"PT":"pt"},{"PW":"en"},{"PY":"es"},{"QA":"ar"},{"RE":"fr"},{"RO":"ro"},{"RS":"sr"},{"RU":"ru"},{"RW":"rw"},{"SA":"ar"},{"SB":"en"},{"SC":"fr"},{"SD":"ar"},{"SE":"sv"},{"SG":"en"},{"SH":"en"},{"SI":"sl"},{"SJ":"no"},{"SK":"sk"},{"SL":"en"},{"SM":"it"},{"SN":"fr"},{"SO":"so"},{"SR":"nl"},{"SS":"en"},{"ST":"pt"},{"SV":"es"},{"SX":"nl"},{"SY":"ar"},{"SZ":"en"},{"TC":"en"},{"TD":"fr"},{"TF":"fr"},{"TG":"fr"},{"TH":"th"},{"TJ":"tg"},{"TK":"en"},{"TL":"pt"},{"TM":"tk"},{"TN":"ar"},{"TO":"en"},{"TR":"tr"},{"TT":"en"},{"TV":"en"},{"TW":"zh"},{"TZ":"sw"},{"UA":"uk"},{"UG":"en"},{"UM":"en"},{"US":"en"},{"UY":"es"},{"UZ":"uz"},{"VA":"it"},{"VC":"en"},{"VE":"es"},{"VG":"en"},{"VI":"en"},{"VN":"vi"},{"VU":"bi"},{"WF":"fr"},{"WS":"sm"},{"XK":"sq"},{"YE":"ar"},{"YT":"fr"},{"ZA":"af"},{"ZM":"en"},{"ZW":"en"}] -------------------------------------------------------------------------------- /components/Libs/CountryList.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import WindowFloat from './WindowFloat'; 3 | import TextBox from './TextBox'; 4 | import Bold from './Bold'; 5 | 6 | 7 | export default (props)=> 8 | { 9 | 10 | var [search, setSearch] = useState(null) 11 | 12 | var countrylist = null; 13 | 14 | if(props.countries) 15 | { 16 | var cnt = Object.values(props.countries).sort((a,b)=> 17 | { 18 | return a.dialCode.length-b.dialCode.length 19 | }) 20 | 21 | var cn = ["United States","United Kingdom", "China", "Russia", "United Arab Emirates","Iran","Canada", "Australia"].reverse() 22 | 23 | var notinc = cnt.filter(c=>{ 24 | if(c.country == "United States") return false; 25 | if(c.country == "Canada") return false; 26 | if(c.country == "United Kingdom") return false; 27 | if(c.country == "Russia") return false; 28 | if(c.country == "China") return false; 29 | if(c.country == "United Arab Emirates") return false; 30 | if(c.country == "Iran") return false; 31 | if(c.country == "Australia") return false; 32 | return true 33 | }) 34 | 35 | for(var cc of cn) 36 | { 37 | notinc.unshift(cnt.filter(c=> c.country == cc)[0]); 38 | } 39 | 40 | cnt = notinc 41 | 42 | if(search) 43 | { 44 | cnt = cnt.filter(c=>{ 45 | if(c.dialCode.includes(search)) 46 | { 47 | return true 48 | } 49 | if(c.country.toLowerCase().startsWith(search.toLowerCase())) 50 | { 51 | return true 52 | } 53 | return false; 54 | }) 55 | } 56 | 57 | 58 | 59 | 60 | countrylist = cnt.map((c,i)=>{ 61 | if(i < 8) 62 | { 63 | return
{ 64 | props.on?props.on(c.code):null 65 | props.onclose?props.onclose():null 66 | }}>
68 | {c.dialCode} {c.country} 69 |
70 | } 71 | return null; 72 | }) 73 | 74 | countrylist = countrylist.filter(x=> x); 75 | } 76 | 77 | 78 | return 79 |
80 | 81 | 82 | 83 | {props.searchtitle} 84 | 85 | 86 | 87 | setSearch(t)}/> 88 | 89 | 90 |
10?{overflow:'hidden', overflowY:'scroll', height:'60vh'}:null}> 91 | {countrylist} 92 |
93 |
94 |
95 | } -------------------------------------------------------------------------------- /components/Libs/CurrencyChooserFloat.tsx: -------------------------------------------------------------------------------- 1 | import WindowFloat from './WindowFloat' 2 | import PayConfig from '../PayConfig'; 3 | import Flag from './Flag' 4 | export default (props) => { 5 | const P = PayConfig(); 6 | 7 | var changecur = async (unitkey) => { 8 | let json = await (await fetch("/api/user/changecur", { 9 | method: "POST", 10 | body: JSON.stringify({ 11 | newunit: unitkey, 12 | email: props.email 13 | }) 14 | })).json() 15 | 16 | if (json.code == 0) { 17 | props.onchange?.(unitkey) 18 | props.onclose?.(); 19 | global.reloadsession(); 20 | } 21 | } 22 | 23 | return { props.onclose?.() }} maxWidth={310}> 24 | 25 | {Object.values(P.units).map(u => { 26 | if (!P.userallowedunits.includes(u.key)) { 27 | return null 28 | } 29 | return
30 | { changecur(u.key) }}> 31 | 32 | 33 | 34 | {u.name + " (" + u.fullname + ")"} 35 | 36 |
37 | })} 38 |
39 | } -------------------------------------------------------------------------------- /components/Libs/DropDown.tsx: -------------------------------------------------------------------------------- 1 | 2 | export default (props:{id:string, text:string, state:any, children:any})=> 3 | { 4 | 5 | return <> 6 |
{return false}} 9 | onClick={()=> 10 | { 11 | if(document.getElementById("dropdown_body_"+ props.id).style.maxHeight == "500px") 12 | { 13 | document.getElementById("dropdown_body_"+ props.id).style.transition = "all 0.2s cubic-bezier(0, 1, 0, 1)"; 14 | document.getElementById("dropdown_body_"+ props.id).style.maxHeight = "0px"; 15 | document.getElementById("dropdown_title_"+ props.id).style.transform = null; 16 | } 17 | else 18 | { 19 | document.getElementById("dropdown_body_"+ props.id).style.transition = "all 0.3s ease-out"; 20 | document.getElementById("dropdown_body_"+ props.id).style.maxHeight = "500px"; 21 | document.getElementById("dropdown_title_"+ props.id).style.transform = "rotate(180deg)"; 22 | } 23 | }} 24 | > 25 | {props.text} 26 |
28 | received transaction count
29 |
30 | 31 | 32 |
33 | {props.children} 34 |
35 | 36 | 37 | 38 | } -------------------------------------------------------------------------------- /components/Libs/FindEmojies.ts: -------------------------------------------------------------------------------- 1 | export default (sentence:string):Array => { 2 | if (!sentence) { 3 | return [] 4 | } 5 | const regex = /\p{RI}\p{RI}|\p{Emoji}(\p{EMod}+|\u{FE0F}\u{20E3}?|[\u{E0020}-\u{E007E}]+\u{E007F})?(\u{200D}\p{Emoji}(\p{EMod}+|\u{FE0F}\u{20E3}?|[\u{E0020}-\u{E007E}]+\u{E007F})?)+|\p{EPres}(\p{EMod}+|\u{FE0F}\u{20E3}?|[\u{E0020}-\u{E007E}]+\u{E007F})?|\p{Emoji}(\p{EMod}+|\u{FE0F}\u{20E3}?|[\u{E0020}-\u{E007E}]+\u{E007F})/gu 6 | const matches = sentence.match(regex)?.filter(x => x.length > 0) || []; 7 | let em1 = matches ? matches : []; 8 | const regex2 = /[\u{1F600}-\u{1F64F}\u{1F300}-\u{1F5FF}\u{1F680}-\u{1F6FF}\u{1F1E0}-\u{1F1FF}\u{1F92C}]/gu; 9 | const matches2 = sentence.match(regex2)?.filter(x => x.length > 0) || []; 10 | let em2 = matches2 ? matches2 : []; 11 | 12 | for (let x of em1) { 13 | if (!em2.includes(x)) { 14 | em2.push(x) 15 | } 16 | } 17 | let set = new Set(matches ? matches : []) 18 | return Array.from(set) 19 | } -------------------------------------------------------------------------------- /components/Libs/FirstTimeComponentLoad.ts: -------------------------------------------------------------------------------- 1 | import Router from "next/router" 2 | export default (callback)=> 3 | { 4 | if(typeof window != "undefined") 5 | { 6 | if(!global.currentpage) 7 | { 8 | global.currentpage = Router.asPath 9 | callback(); 10 | } 11 | else 12 | { 13 | if(global.currentpage != Router.asPath) 14 | { 15 | global.currentpage = Router.asPath 16 | callback(); 17 | } 18 | } 19 | } 20 | } 21 | 22 | 23 | -------------------------------------------------------------------------------- /components/Libs/Flag.tsx: -------------------------------------------------------------------------------- 1 | import { CSSProperties, useState } from 'react'; 2 | 3 | export default (props:{ccode?:string, style:CSSProperties, onclick?:()=>{}, })=> 4 | { 5 | var [countries, setCountries] = useState(null); 6 | if(typeof window != "undefined") 7 | { 8 | if(!window.countries) 9 | { 10 | var getCountries = async ()=> 11 | { 12 | window.countries = await (await fetch(global.cdn("/files/countries.json"))).json(); 13 | setCountries(window.countries) 14 | } 15 | getCountries(); 16 | } 17 | else { 18 | if(!countries) 19 | { 20 | countries = window.countries 21 | } 22 | } 23 | } 24 | 25 | var getCountry = (ccode)=> 26 | { 27 | if(typeof window != "undefined") 28 | { 29 | return window.countries?Object.values(countries).filter(c=> (c as any).code.toLowerCase() == ccode.toLowerCase())[0]:null; 30 | } 31 | return null 32 | } 33 | 34 | if(!props.ccode) 35 | { 36 | return null 37 | } 38 | 39 | if(props.ccode.length == 2) 40 | { 41 | return {props.onclick?.()}}> 43 |
45 |
46 | } 47 | else 48 | { 49 | return {props.onclick?.()}}/> 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /components/Libs/FormBackMaker.ts: -------------------------------------------------------------------------------- 1 | import Router from 'next/router' 2 | export default 3 | { 4 | MakeBackableForm:(name)=> 5 | { 6 | if(!global.currennturl) 7 | { 8 | global.onback = {} 9 | global.currennturl= window.location.href; 10 | 11 | setInterval(()=> 12 | { 13 | if(global.currennturl.includes("#") && (window.location.href != global.currennturl) && global.onform) 14 | { 15 | if(typeof global.onback[global.onform] == "function") 16 | { 17 | global.onback[global.onform](); 18 | } 19 | global.onform = null; 20 | } 21 | global.currennturl= window.location.href; 22 | }, 200) 23 | } 24 | 25 | window.history.replaceState({ ...window.history.state, as: Router.asPath.split("#").join(""), url: Router.asPath.split("#").join("") }, '', Router.asPath.split("#").join("")) 26 | window.history.pushState({ ...window.history.state, as: window.location.href+"#", url: window.location.href }, '', window.location.href+"#") 27 | global.onform = name; 28 | 29 | var body = document.getElementsByTagName("body")[0] 30 | body.style.overflow = "hidden"; 31 | }, 32 | 33 | RemoveBackableForms:(name)=> 34 | { 35 | if(global.onform == name) 36 | { 37 | global.onform = null 38 | window.history.replaceState({ ...window.history.state, as: Router.asPath.split("#").join(""), url: Router.asPath.split("#").join("") }, '', Router.asPath.split("#").join("")) 39 | var body = document.getElementsByTagName("body")[0] 40 | body.style.overflowY = "auto"; 41 | } 42 | }, 43 | 44 | AddOnBack:(name, cb)=> 45 | { 46 | if(!global.onback) 47 | { 48 | global.onback = {} 49 | } 50 | 51 | global.onform = name; 52 | global.onback[name] = ()=> 53 | { 54 | cb(); 55 | } 56 | } 57 | 58 | 59 | } -------------------------------------------------------------------------------- /components/Libs/FormM.tsx: -------------------------------------------------------------------------------- 1 | 2 | import Component, { PageEl } from './Component'; 3 | import Icon2Titles from './Icon2Titles'; 4 | import TextEndAbbreviation from './TextEndAbbreviation' 5 | import Window from './Window' 6 | import WindowFloat from './WindowFloat'; 7 | 8 | 9 | export default p => Component(p, Page); 10 | const Page: PageEl = (props, state, refresh, getProps) => { 11 | 12 | getProps(async () => { }) 13 | let empty = true; 14 | 15 | return
16 |
17 | 18 | {!props.single || props.selected.length == 0 ?
e.currentTarget.style.backgroundColor = "#95b587aa"} 23 | onMouseDown={(e) => e.currentTarget.style.backgroundColor = "#5c8e58aa"} 24 | onMouseUp={(e) => e.currentTarget.style.backgroundColor = "#95b587aa"} 25 | onMouseLeave={(e) => e.currentTarget.style.backgroundColor = "#5c8e5855"} 26 | > 27 | { refresh({ form: "selected" }) }}> 28 | 29 | {props.addtext} 30 | 31 |
: null} 32 | {props.selected?.map(s => { 33 | return
{ 36 | props.onitemclick?.(s) 37 | }}> 38 | { 42 | e.preventDefault(); 43 | e.stopPropagation(); 44 | props.onremoveclick?.(s) 45 | }} /> 46 | { 47 | e.preventDefault(); 48 | e.stopPropagation(); 49 | props.onitemclick?.(s) 50 | }}> 51 | 56 | {TextEndAbbreviation(s.name || lang.loading, 30)} 57 | 58 |
59 | })} 60 | 61 | 62 | 63 | 64 | 65 |
66 |
67 | 68 | 69 | 70 | {state.form == "selected" ? { state.form = null; refresh() }}> 72 |
73 | {props.list?.map?.(src => { 74 | if(props.selected?.find(s=> s.name == src.name)) 75 | { 76 | return null 77 | } 78 | empty = false; 79 | return
80 | { 83 | if (!props.selected?.find(s => s.name == src.name)) { 84 | props.onadd?.(src) 85 | refresh({ form: null }) 86 | } 87 | }} 88 | /> 89 | 90 |
91 | })} 92 | {empty?{"No item found"}:null} 93 |
94 | 95 |
: null} 96 | 97 | 98 | 99 | 100 | 101 |
102 | } -------------------------------------------------------------------------------- /components/Libs/FormS.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import TextBox from "./TextBox"; 3 | import WindowFloat from "./WindowFloat"; 4 | import Icon2Titles from "./Icon2Titles"; 5 | 6 | export default (props) => { 7 | 8 | let items = props.items 9 | let selectedinit = {}; 10 | for (let k of props.selectedvalues) { 11 | let its = items.find(it => it.name == k || it.value == k) 12 | if(!its) 13 | { 14 | its = items.find(it => JSON.stringify(it.value) == JSON.stringify(k)) 15 | } 16 | if (its) 17 | selectedinit[its?.name] = its.value 18 | } 19 | let [state, setState]: [any, any] = useState({ selectedsyms: selectedinit }) 20 | 21 | if (((!state.searchedsyms) || state.searchedsyms.length == 0)) { 22 | state.searchedsyms = [...items.filter(s => state.selectedsyms[s.name])] 23 | for (let ss of items.slice(0, Math.min(10, items.length))) { 24 | if (!state.searchedsyms.find(s => s.value == ss.value)) { 25 | state.searchedsyms.push(ss) 26 | } 27 | } 28 | } 29 | else { 30 | let selecteds = state.searchedsyms.filter(s => state.selectedsyms[s.name]) 31 | let notselecteds = state.searchedsyms.filter(s => !state.selectedsyms[s.name]) 32 | state.searchedsyms = [...selecteds, ...notselecteds] 33 | } 34 | 35 | 36 | return { props.onclose?.() }}> 37 | { 38 | if (txt == "") { 39 | if (Object.keys(state.selectedsyms).length > 0) { 40 | state.searchedsyms = items.filter((s, i) => state.selectedsyms[s.name]) 41 | } 42 | else { 43 | state.searchedsyms = items.filter((_, i) => i < 10) 44 | } 45 | 46 | let i = 0; 47 | while (i <= items.length - 1 && (state.searchedsyms.filter(s => !state.selectedsyms[s.name])).length < 15) { 48 | if (!state.selectedsyms[items[i].name]) { 49 | state.searchedsyms.push(items[i]) 50 | } 51 | i++; 52 | } 53 | } 54 | else { 55 | state.searchedsyms = items.filter(s => (s.name.toLowerCase().startsWith(txt.toLowerCase()))).filter((_, i) => i < 30) 56 | } 57 | setState({ ...state }) 58 | }} /> 59 | 60 |
61 | {state.searchedsyms?.map?.((sym, i) => { 62 | let s = sym; 63 | return
64 | { 67 | if (state.selectedsyms[s.name]) { 68 | if (props.asktoremove) { 69 | if (await confirmer(lang.delete, lang.delconf)) { 70 | props.onremoveitem?.(s.value) 71 | delete state.selectedsyms[s.name] 72 | } 73 | else { 74 | return; 75 | } 76 | } 77 | else { 78 | props.onremoveitem?.(s.value) 79 | delete state.selectedsyms[s.name] 80 | } 81 | 82 | } 83 | else { 84 | props.onadditem?.(s.value) 85 | state.selectedsyms[s.name] = s.value 86 | } 87 | props.on?.(Object.values(state.selectedsyms)) 88 | setState({ ...state }) 89 | }} 90 | /> 91 | 92 |
93 | })} 94 |
95 | 96 |
97 | } -------------------------------------------------------------------------------- /components/Libs/FormV.tsx: -------------------------------------------------------------------------------- 1 | import WindowFloat from "./WindowFloat"; 2 | 3 | export default (props:{title:string, items:Array<{name:string|number, value:any, image?:string, icon?:string}> 4 | onhelp?:any, onclose?:any, on?:any, strvalue:string}) => { 5 | 6 | let btnbg = "#c9ceb1" 7 | let optstyle = { height: 35, width: "100%", margin: 2, borderRadius: 3, backgroundColor: btnbg } 8 | 9 | return { props.onclose?.(); }} 10 | onhelp={props.onhelp?(()=>{props.onhelp?.()}):null}> 11 | { 12 | props.items.map((item, i) => { 13 | let it = item; 14 | if(typeof it != "object") 15 | { 16 | it = {name:it, value:it} 17 | } 18 | let itp = props.items[i + 1]; 19 | if(itp && typeof itp != "object") 20 | { 21 | itp = {name:itp, value:itp} 22 | } 23 | let Img = null; 24 | if(item.image || item.icon) 25 | { 26 | Img = 27 | } 28 | if (i % 2 == 0) { 29 | return 30 | { props.on?.(it.name, it.value) }}> 32 | {Img}{(it.name).toLocaleString(lang.region)} 33 | 34 | {itp ? { props.on?.(itp.name,itp.value) }}> 36 | {Img}{(itp.name).toLocaleString(lang.region)} 37 | : null} 38 | 39 | } 40 | return null; 41 | }) 42 | } 43 | 44 | 45 | } -------------------------------------------------------------------------------- /components/Libs/GridBtn.tsx: -------------------------------------------------------------------------------- 1 | import { Grid } from "@mui/material"; 2 | import Component, { PageEl } from '../Libs/Component'; 3 | export default p => Component(p, Page); 4 | const Page: PageEl = (props, state, refresh, getProps):JSX.Element => { 5 | return 6 | props.on?.()}> 8 | 9 | {props.title} 10 | 11 | 12 | } -------------------------------------------------------------------------------- /components/Libs/HandRankExplore.tsx: -------------------------------------------------------------------------------- 1 | 2 | import { useState } from 'react'; 3 | 4 | const vote = async (item, dislike = false)=> 5 | { 6 | if(!dislike) //liked 7 | { 8 | if(item.liked) return 9 | item.likes ++; 10 | item.dislikes -- 11 | if(item.likes < 0) item.likes = 0; 12 | if(item.dislikes < 0) item.dislikes = 0; 13 | item.liked = true; 14 | item.disliked = false; 15 | } 16 | else 17 | { 18 | if(item.disliked) return 19 | item.likes --; 20 | item.dislikes ++ 21 | if(item.likes < 0) item.likes = 0; 22 | if(item.dislikes < 0) item.dislikes = 0 23 | item.liked = false; 24 | item.disliked = true; 25 | } 26 | 27 | fetch("/api/explore/vote",{ 28 | method:"POST", 29 | body:JSON.stringify({ 30 | like:!dislike, 31 | dislike:dislike, 32 | expid:item.expid, 33 | }) 34 | }).then(async r=>{ 35 | let json = await r.json(); 36 | if(json.code == 0) 37 | { 38 | } 39 | }) 40 | } 41 | 42 | import Component, { PageEl } from './Component'; 43 | export default p => Component(p, Page); 44 | const Page: PageEl = (props, state, refresh, getProps):JSX.Element => { 45 | var [item, setItem] = useState(props.item) 46 | props.item.likes = item.likes; 47 | props.item.dislikes = item.dislikes; 48 | props.item.liked = item.liked; 49 | props.item.disliked = item.disliked; 50 | 51 | 52 | var percent = 19;//props.item.likes 53 | var color = null 54 | if(percent >= 90) 55 | { 56 | color = "green" 57 | } 58 | else if(percent >= 70) 59 | { 60 | color = "#447d00" 61 | } 62 | else if(percent >= 50) 63 | { 64 | color = "#428c00" 65 | } 66 | 67 | 68 | return 69 | 70 | {props.notitle?null:{lang.rank}} 71 | 72 | 1000 ? 20:0)}}> 73 | 74 | 75 | 76 | { 77 | if(!global.user.loggedin) 78 | { 79 | props.loginrequired?.() 80 | return 81 | } 82 | e.target.className = styles.nopale 83 | document.getElementById(item.expid+"_lr").className = null; 84 | vote(item) 85 | setItem(JSON.parse(JSON.stringify(item))) 86 | props.onrefresh?.(); 87 | props.onlike?.() 88 | }} /> {(item.likes || 0).toLocaleString(lang.region)} 89 | 90 | 91 | 92 | { 93 | if(!global.user.loggedin) 94 | { 95 | props.loginrequired?.() 96 | return 97 | } 98 | e.target.className = styles.nopaler 99 | document.getElementById(item.expid+"_lg").className = null; 100 | vote(item, true) 101 | setItem(JSON.parse(JSON.stringify(item))) 102 | props.onrefresh?.(); 103 | props.ondislike?.() 104 | }}/> {(item.dislikes||0).toLocaleString(lang.region)} 105 | 106 | 107 | 108 | 109 | 110 | } -------------------------------------------------------------------------------- /components/Libs/HashTrack.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link' 2 | import Copy from './Copy' 3 | import Bold from './Bold' 4 | 5 | import Component, { PageEl } from './Component'; 6 | export default p => Component(p, Page); 7 | const Page: PageEl = (props, state, refresh, getProps):JSX.Element => { 8 | return
9 | {props.title} 10 |
{props.body} 11 |  payment type 12 |    payment type{ 13 | Copy(props.copyval||props.body) 14 | alerter("Hash link copied to clipboard.") 15 | }}/> 16 |
17 |
18 | } -------------------------------------------------------------------------------- /components/Libs/Icon2CurrencySelectFloat.tsx: -------------------------------------------------------------------------------- 1 | import WindowFloat from './WindowFloat'; 2 | import Icon2Titles from './Icon2Titles'; 3 | 4 | export default (props)=>{ 5 | return {props.onclose?.()}}> 6 | {Object.keys(global.user.wallets).map(k => { 7 | if(!global.user.wallets[k].donations || global.user.wallets[k].donations.length == 0) 8 | { 9 | return null; 10 | } 11 | let wallet = global.user.wallets[k]; 12 | let unit = wallet.unit; 13 | let amount = unit.tolocalstr(wallet?.balance); 14 | return {props.on?.(k)}} 20 | /> 21 | })} 22 | 23 | 24 | } -------------------------------------------------------------------------------- /components/Libs/Icon2Titles.tsx: -------------------------------------------------------------------------------- 1 | import { CSSProperties } from 'react' 2 | import Bold from './Bold' 3 | 4 | 5 | export default (props:{title?:any, raw1?:boolean, title1?:any, title2?:any, 6 | price1?:number, raw?:boolean, icon?:any, image?:any, nohover?:boolean, 7 | on?:()=>void, percent?:number, roundicon?:boolean, style?:CSSProperties, percentColor?:string, 8 | nobold?:boolean,unbold?:boolean, f1?:string, f2?:string, righticons?:any, onclose?:()=>{}, 9 | }) => { 10 | var alt = "icon" 11 | if (props.title && !props.raw1) { 12 | alt = props.title1?.toLowerCase() + "'s icon" 13 | } 14 | else if (props.price1 && !props.raw) { 15 | alt = "price " + props.price1 + "'s icon" 16 | } 17 | else { 18 | alt = "icon2title's icon" 19 | } 20 | let image = props.icon || props.image; 21 | 22 | let unbold = props.nobold || props.unbold; 23 | 24 | 25 | return props.on?.()}> 28 | 29 | {props.percent ?
: null} 30 | 31 | 32 | 33 | {typeof image == "string" ? {props.title1 : 35 | image} 36 | 37 | 38 | {props.raw ? 39 | {props.title1 ? props.title1 : null} 40 | {props.title2 ? props.title2 : null} 41 | : (unbold ? 42 | 43 | {typeof props.title1 == "string" ? {props.title1} : props.title1} 44 | {typeof props.title2 == "string" ? {props.title2} : props.title2} 45 | : 46 | 47 | {typeof props.title1 == "string" ? {props.title1} : props.title1} 48 | {typeof props.title2 == "string" ? {props.title2} : props.title2} 49 | )} 50 | 51 | 52 | {props.righticons || props.onclose ? 58 | {props.righticons} 59 | 60 | {props.onclose ? {alt} { props.onclose?.() }} /> : null} 62 | : null} 63 | 64 | 65 |
66 | } -------------------------------------------------------------------------------- /components/Libs/Icon2TitlesWide.tsx: -------------------------------------------------------------------------------- 1 | import Bold from './Bold' 2 | 3 | 4 | export default (props:{title1?:any, price1?:string,width?:number|string, 5 | title2?:any,roundicon?:boolean, on?:()=>void 6 | height?:number|string, icon?:any, image?:any, 7 | bgtransparent?:boolean, f1?:string|number, f2?:string|number, 8 | })=> 9 | { 10 | var alt = "icon" 11 | if(props.title1) 12 | { 13 | alt = props.title1.toLowerCase()+"'s icon" 14 | } 15 | else if(props.price1) 16 | { 17 | alt = "price "+props.price1+ "'s icon" 18 | } 19 | 20 | return
{props.on?.()}} > 22 |
23 | {props.title1+"'s 24 |
25 |    26 |
27 | {props.title1?{props.title1}:null} 28 | {props.title2?{props.title2}:null} 29 |
30 | 31 |
32 | {props.title1+"'s 33 |
34 |
35 | } -------------------------------------------------------------------------------- /components/Libs/Icon3Titles.tsx: -------------------------------------------------------------------------------- 1 | import { CSSProperties } from 'react' 2 | import Bold from './Bold' 3 | 4 | export default (props:{ 5 | title1?:any, title2?:any, title3?:any, price1?:any, unbold?:boolean, nobold?:boolean, 6 | icon?:any, image?:any,bgtransparent?:boolean, mb?:number, style?:CSSProperties, 7 | on?:()=>void,onclose?:()=>void, special?:any, specialcolor?:string, specialtextcolor?:string,image2?:string, 8 | roundicon?:boolean, unit1?:any, righticons?:any,lineHeight?:string|number, 9 | 10 | }) => { 11 | var alt = "icon" 12 | if (props.title1) { 13 | alt = typeof props.title1 == "string" ? (props.title1.toLowerCase() + "'s icon") : "object's icon" 14 | } 15 | else if (props.price1) { 16 | alt = "price " + props.price1 + "'s icon" 17 | } 18 | 19 | let unbold = props.nobold || props.unbold; 20 | 21 | let title1 = null 22 | let title2 = null 23 | let title3 = null 24 | 25 | if (typeof props.title1 == "string") { 26 | title1 =

{unbold ? props.title1 : {props.title1}}

27 | // title1 = {unbold ? props.title1 : {props.title1}} 28 | } 29 | else { 30 | title1 = props.title1 31 | } 32 | 33 | if (typeof props.title2 == "string") { 34 | title2 =

{props.title2}

35 | } 36 | else { 37 | title2 = props.title2 38 | } 39 | 40 | if (typeof props.title3 == "string") { 41 | title3 =

{props.title3}

42 | } 43 | else { 44 | title3 = props.title3 45 | } 46 | 47 | 48 | let icon = props.icon || props.image 49 | 50 | 51 | return { props.on?.() }} 52 | style={{ marginBottom: props.mb, width: "100%", ...props.style }} > 53 | 54 | 55 | 56 | 57 | {props.image2 ? 58 | 59 | : null} 60 | {typeof icon == "string" ? {alt} : icon} 64 | {props.special ? 65 | {props.special} : null} 66 | 67 | 68 | 69 | 70 | {!props.unit1 && props.title1 ? title1 : null} 71 | 72 | {props.unit1 != undefined ?

73 | 74 | {props.title1 == "0" ? "0.00" : props.title1} 75 |  {props.unit1}

: null} 76 | 77 | {props.unit1 ? {props.title2} : null} 78 | {!props.unit1 && props.title2 ? title2 : null} 79 | {props.title3 ? title3 : null} 80 |
81 | 82 |
83 | {props.righticons || props.onclose ? 89 | {props.righticons} 90 | 91 | {props.onclose ? { props.onclose?.() }} /> : null} 93 | : null} 94 | 95 |
96 | } -------------------------------------------------------------------------------- /components/Libs/ItemList.tsx: -------------------------------------------------------------------------------- 1 | import Window from './Window' 2 | 3 | export default (props:{trigger:number, items:Array, title:string, 4 | head?:any, foot?:any, 5 | })=> 6 | { 7 | 8 | var couples = [] 9 | var uniquekey= Math.random()*100; 10 | var wstyle= null 11 | if(props.trigger == 400) 12 | { 13 | wstyle = styles.itemlist400w 14 | } 15 | else if(props.trigger == 600) 16 | { 17 | wstyle = styles.itemlist600w 18 | } 19 | else if(props.trigger == 800) 20 | { 21 | wstyle = styles.itemlist800w 22 | } 23 | else if(props.trigger == 1024) 24 | { 25 | wstyle = styles.itemlist1024w 26 | } 27 | 28 | var sstyle= null 29 | if(props.trigger == 400) 30 | { 31 | sstyle = styles.itemlist400s 32 | } 33 | else if(props.trigger == 600) 34 | { 35 | sstyle = styles.itemlist600s 36 | } 37 | else if(props.trigger == 800) 38 | { 39 | sstyle = styles.itemlist800s 40 | } 41 | else if(props.trigger == 1024) 42 | { 43 | sstyle = styles.itemlist1024s 44 | } 45 | 46 | 47 | for(let i = 0; i < props.items.length; i+=2) 48 | { 49 | if((i + 1) < props.items.length) 50 | { 51 | couples.push(
52 | {props.items[i]} 53 |   54 | {props.items[i+1]} 55 |
) 56 | } 57 | else 58 | { 59 | couples.push(
60 | {props.items[i]} 61 |
) 62 | } 63 | } 64 | return <> 65 | 66 | 67 | {props.head} 68 |
69 | 70 | {couples} 71 | 72 |
{props.items.map(x=>x)}
73 | {props.foot} 74 | 75 |
76 |
77 | 78 | 79 | 80 | } -------------------------------------------------------------------------------- /components/Libs/ItemListFloat.tsx: -------------------------------------------------------------------------------- 1 | import WindowFloat from './WindowFloat' 2 | 3 | export default (props:{trigger:number, items:Array, title:string,onclose?:()=>void, 4 | head?:any, foot?:any, onhelp?:()=>void 5 | })=> 6 | { 7 | 8 | var couples = [] 9 | 10 | var wstyle= null 11 | if(props.trigger == 400) 12 | { 13 | wstyle = styles.itemlist400w 14 | } 15 | else if(props.trigger == 600) 16 | { 17 | wstyle = styles.itemlist600w 18 | } 19 | else if(props.trigger == 800) 20 | { 21 | wstyle = styles.itemlist800w 22 | } 23 | else if(props.trigger == 1024) 24 | { 25 | wstyle = styles.itemlist1024w 26 | } 27 | 28 | var sstyle= null 29 | if(props.trigger == 400) 30 | { 31 | sstyle = styles.itemlist400s 32 | } 33 | else if(props.trigger == 600) 34 | { 35 | sstyle = styles.itemlist600s 36 | } 37 | else if(props.trigger == 800) 38 | { 39 | sstyle = styles.itemlist800s 40 | } 41 | else if(props.trigger == 1024) 42 | { 43 | sstyle = styles.itemlist1024s 44 | } 45 | 46 | 47 | for(let i = 0; i < props.items.length; i+=2) 48 | { 49 | if((i + 1) < props.items.length) 50 | { 51 | couples.push(
52 | {props.items[i]} 53 |   54 | {props.items[i+1]} 55 |
) 56 | } 57 | else 58 | { 59 | couples.push(
60 | {props.items[i]} 61 |
) 62 | } 63 | } 64 | return <> 65 | 66 | {props.onclose?.()}} onhelp={props.onhelp}> 67 | 68 | {props.head} 69 |
70 | 71 | {couples} 72 | 73 |
{props.items.map(x=>x)}
74 | {props.foot} 75 | 76 |
77 |
78 | 79 | 80 | 81 | } -------------------------------------------------------------------------------- /components/Libs/Langs.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | "ar": "العربية", "zh": "中國人", "en": "english", "fa": "فارسی", 3 | "ru": "русский", "de": "deutsch", "fr": "français", "es": "español", "ja": "日本語", "ko": "한국어", 4 | "pt": "português", "tr": "Türkçe", "ur": "اُردُو", "id": "bahasa" 5 | } -------------------------------------------------------------------------------- /components/Libs/LinkHashtags.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link'; 2 | import FindEmojies from './FindEmojies'; 3 | 4 | function findHashTags(sentence) { 5 | if(!sentence) 6 | { 7 | return { single: [], double: [] } 8 | } 9 | const regex = /(?:^|\s)(#[\p{L}\p{Mn}\p{Pc}\p{Nd}_]+)|(?:^|\s)(##[\p{L}\p{Mn}\p{Pc}\p{Nd}_]+)/gu; 10 | const matches = sentence.match(regex); 11 | const hashTags = { single: [], double: [] }; 12 | if (matches) { 13 | matches.forEach(match => { 14 | const trimmedMatch = match.trim(); 15 | if (trimmedMatch.startsWith("##")) { 16 | hashTags.double.push(trimmedMatch); 17 | } else { 18 | hashTags.single.push(trimmedMatch); 19 | } 20 | }); 21 | } 22 | return hashTags; 23 | } 24 | 25 | export default (sentence, style?, unqid?) => { 26 | let tags = findHashTags(sentence) 27 | let emojies = FindEmojies(sentence) 28 | let uniquekey = new Date().getTime() + Math.random() * 1000; 29 | let retobj = sentence 30 | 31 | tags.single.sort((a,b)=> b.length - a.length) 32 | tags.double.sort((a,b)=> b.length - a.length) 33 | 34 | for (let emoji of emojies) { 35 | let array = retobj 36 | let text: string = emoji as string 37 | var arr = array; 38 | if (typeof arr == "string") { 39 | arr = [array] 40 | } 41 | 42 | var temparr = []; 43 | for (let a = 0; a < arr.length; a++) { 44 | var x = arr[a]; 45 | if (typeof x == "string" && x.includes(text)) { 46 | var p = x.split(text) 47 | for (let i = 0; i < p.length; i++) { 48 | temparr.push(p[i]) 49 | if (p.length - 1 != i) { 50 | temparr.push({emoji) 52 | } 53 | } 54 | } 55 | else { 56 | temparr.push(x) 57 | } 58 | } 59 | retobj = temparr 60 | } 61 | 62 | 63 | for (let tag of tags.double) { 64 | let array = retobj 65 | let text = tag 66 | let onlytag = text.replace(/#/g, "").replace(/_+/g, "-").replace(/\s+/, "-") 67 | var arr = array; 68 | if (typeof arr == "string") { 69 | arr = [array] 70 | } 71 | 72 | var temparr = []; 73 | for (let a = 0; a < arr.length; a++) { 74 | var x = arr[a]; 75 | if (typeof x == "string" && x.includes(text)) { 76 | var p = x.split(text) 77 | for (let i = 0; i < p.length; i++) { 78 | temparr.push(p[i]) 79 | if (p.length - 1 != i) { 80 | temparr.push( { 82 | document.getElementById("wind").scrollTo({ 83 | top: 0, 84 | behavior: 'smooth' // This creates a smooth scrolling effect, omit for instant scroll 85 | }); 86 | }}>{text}) 87 | } 88 | } 89 | } 90 | else { 91 | temparr.push(x) 92 | } 93 | } 94 | retobj = temparr 95 | } 96 | 97 | 98 | 99 | 100 | for (let tag of tags.single) { 101 | let array = retobj 102 | let text = tag 103 | let onlytag = text.replace(/#/g, "").replace(/_+/g, "-").replace(/\s+/, "-") 104 | var arr = array; 105 | if (typeof arr == "string") { 106 | arr = [array] 107 | } 108 | 109 | var temparr = []; 110 | for (let a = 0; a < arr.length; a++) { 111 | var x = arr[a]; 112 | if (typeof x == "string" && x.includes(text)) { 113 | var p = x.split(text) 114 | for (let i = 0; i < p.length; i++) { 115 | temparr.push(p[i]) 116 | if (p.length - 1 != i) { 117 | let isexplore = false; 118 | if (typeof window != "undefined") 119 | isexplore = window.location.pathname.includes("/e/") || window.location.pathname.includes("/explore"); 120 | else 121 | isexplore = global.user.path.includes("/e/") || global.user.path.includes("/explore"); 122 | 123 | temparr.push({text}) 124 | } 125 | } 126 | } 127 | else { 128 | temparr.push(x) 129 | } 130 | } 131 | retobj = temparr 132 | } 133 | 134 | return retobj 135 | 136 | } -------------------------------------------------------------------------------- /components/Libs/Lorem.tsx: -------------------------------------------------------------------------------- 1 | 2 | export default (len)=>{ 3 | return `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Dui vivamus arcu felis bibendum ut tristique et egestas quis. Amet massa vitae tortor condimentum lacinia. Eu mi bibendum neque egestas. Integer vitae justo eget magna fermentum iaculis. Tempor id eu nisl nunc mi ipsum faucibus vitae aliquet. Habitasse platea dictumst vestibulum rhoncus est pellentesque elit ullamcorper. Lobortis mattis aliquam faucibus purus in. Magna eget est lorem ipsum dolor sit. Tempus urna et pharetra pharetra massa massa ultricies. Tellus in metus vulputate eu scelerisque. Ac orci phasellus egestas tellus rutrum tellus pellentesque eu tincidunt. Nunc pulvinar sapien et ligula. Consectetur adipiscing elit pellentesque habitant morbi tristique senectus et netus. Dui id ornare arcu odio ut sem nulla pharetra diam. 4 | 5 | Lectus nulla at volutpat diam ut venenatis tellus in metus. Diam maecenas sed enim ut. Ipsum faucibus vitae aliquet nec ullamcorper sit amet risus nullam. Vitae semper quis lectus nulla at volutpat diam ut. Accumsan lacus vel facilisis volutpat est velit egestas. Vulputate dignissim suspendisse in est. Metus aliquam eleifend mi in nulla posuere sollicitudin aliquam ultrices. Augue mauris augue neque gravida. Eleifend donec pretium vulputate sapien nec sagittis aliquam. Semper viverra nam libero justo laoreet sit. Malesuada fames ac turpis egestas integer eget aliquet nibh praesent. In hac habitasse platea dictumst quisque sagittis purus sit. Malesuada fames ac turpis egestas. Sem nulla pharetra diam sit. Dictum sit amet justo donec. Fusce ut placerat orci nulla pellentesque. Enim blandit volutpat maecenas volutpat blandit aliquam etiam. 6 | 7 | Vitae elementum curabitur vitae nunc. Ultrices mi tempus imperdiet nulla. Gravida cum sociis natoque penatibus et magnis dis parturient. Orci nulla pellentesque dignissim enim sit amet venenatis. Fermentum et sollicitudin ac orci phasellus. Metus aliquam eleifend mi in nulla posuere sollicitudin. Odio ut enim blandit volutpat maecenas volutpat. A pellentesque sit amet porttitor. Sit amet cursus sit amet dictum. Mauris sit amet massa vitae tortor condimentum lacinia quis. Nunc lobortis mattis aliquam faucibus purus in massa tempor nec. Nec tincidunt praesent semper feugiat nibh sed pulvinar proin. Nunc faucibus a pellentesque sit amet porttitor eget dolor. Rhoncus dolor purus non enim praesent elementum facilisis leo vel. 8 | 9 | Duis at tellus at urna condimentum mattis pellentesque id. Enim ut sem viverra aliquet eget sit amet. Aliquam ultrices sagittis orci a scelerisque purus semper. Eget nullam non nisi est sit. Nibh praesent tristique magna sit amet purus gravida quis blandit. Arcu vitae elementum curabitur vitae nunc sed velit. Nisl purus in mollis nunc sed. Eleifend mi in nulla posuere sollicitudin aliquam ultrices sagittis orci. Amet venenatis urna cursus eget. Vel pharetra vel turpis nunc. Non nisi est sit amet facilisis magna etiam tempor. Duis convallis convallis tellus id interdum. Ultrices in iaculis nunc sed augue. Lobortis feugiat vivamus at augue eget arcu dictum. 10 | 11 | Amet volutpat consequat mauris nunc. Sit amet mattis vulputate enim. Tristique nulla aliquet enim tortor. Egestas egestas fringilla phasellus faucibus. Pulvinar sapien et ligula ullamcorper malesuada proin. Feugiat vivamus at augue eget arcu dictum varius duis. Sit amet cursus sit amet dictum sit amet justo. Integer feugiat scelerisque varius morbi enim nunc. Feugiat scelerisque varius morbi enim nunc faucibus a pellentesque. Odio facilisis mauris sit amet massa. Risus viverra adipiscing at in tellus integer feugiat scelerisque.`.substring(0,len) 12 | } 13 | -------------------------------------------------------------------------------- /components/Libs/NewUpload.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react" 2 | import Bold from './Bold' 3 | import Copy from './Copy' 4 | import UploadSingleBox from './UploadSingleBox' 5 | import WindowFloat from './WindowFloat' 6 | 7 | export default (props:{extensionfilter?:any, defaultValue?:string, onclose?:()=>void, 8 | ondone?:(d?:string)=>void 9 | })=>{ 10 | let [upload, setUpload] = useState({}) 11 | let [cpicon, setCpIcon] = useState(global.cdn("/files/copy.svg")) 12 | return props.onclose?.()} z={260}> 13 | {setUpload({uploadval: n})}} value={upload.uploadval} reload={()=>{setCpIcon(global.cdn("/files/copy.svg"))}} 18 | lefticon={cpicon} onlefticon={()=>{Copy(upload.uploadval); setCpIcon(global.cdn("/files/ok.svg"))}}/> 19 | 20 | { 21 | props.ondone?.(typeof upload.uploadval == "string"?upload.uploadval:null) 22 | }}>{lang.finish} 23 | 24 | } -------------------------------------------------------------------------------- /components/Libs/Num2EN.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable eqeqeq */ 2 | export default (input) => { 3 | 4 | const a = ['', 'One ', 'Two ', 'Three ', 'Four ', 'Five ', 'Six ', 'Seven ', 'Eight ', 'Nine ', 'Ten ', 'Eleven ', 5 | 'Twelve ', 'Thirteen ', 'Fourteen ', 'Fifteen ', 'Sixteen ', 'Seventeen ', 'Eighteen ', 'Nineteen '] 6 | const b = ['', '', 'Twenty', 'Thirty', 'Forty', 'Fifty', 'Sixty', 'Seventy', 'Eighty', 'Ninety'] 7 | 8 | const regex = /^(\d{2})(\d{2})(\d{2})(\d{1})(\d{2})$/ 9 | 10 | const getLT20 = (n) => a[Number(n)] 11 | const getGT20 = (n) => b[n[0]] + ' ' + a[n[1]] 12 | 13 | const num = Number(input) 14 | if (isNaN(num)) return '' 15 | if (num === 0) return 'zero' 16 | 17 | const numStr = num.toString() 18 | if (numStr.length > 9) { 19 | throw new Error('overflow') // Does not support converting more than 9 digits yet 20 | } 21 | 22 | const [_, n1, n2, n3, n4, n5]: Array = ('000000000' + numStr).substr(-9).match(regex) // left pad zeros 23 | 24 | let str = '' 25 | str += n1 != 0 ? (getLT20(n1) || getGT20(n1)) + 'Billion ' : '' 26 | str += n2 != 0 ? (getLT20(n2) || getGT20(n2)) + 'Million ' : '' 27 | str += n3 != 0 ? (getLT20(n3) || getGT20(n3)) + 'Thousand ' : '' 28 | str += n4 != 0 ? getLT20(n4) + 'Hundred ' : '' 29 | str += n5 != 0 && str != '' ? 'and ' : '' 30 | str += n5 != 0 ? (getLT20(n5) || getGT20(n5)) : '' 31 | 32 | return str.trim() 33 | } 34 | 35 | -------------------------------------------------------------------------------- /components/Libs/Num2FA.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @type {string} 4 | */ 5 | const delimiter = ' و '; 6 | 7 | /** 8 | * 9 | * @type {string} 10 | */ 11 | const zero = 'صفر'; 12 | 13 | /** 14 | * 15 | * @type {string} 16 | */ 17 | const negative = 'منفی '; 18 | 19 | /** 20 | * 21 | * @type {*[]} 22 | */ 23 | const letters = [ 24 | ['', 'یک', 'دو', 'سه', 'چهار', 'پنج', 'شش', 'هفت', 'هشت', 'نه'], 25 | ['ده', 'یازده', 'دوازده', 'سیزده', 'چهارده', 'پانزده', 'شانزده', 'هفده', 'هجده', 'نوزده', 'بیست'], 26 | ['', '', 'بیست', 'سی', 'چهل', 'پنجاه', 'شصت', 'هفتاد', 'هشتاد', 'نود'], 27 | ['', 'یکصد', 'دویست', 'سیصد', 'چهارصد', 'پانصد', 'ششصد', 'هفتصد', 'هشتصد', 'نهصد'], 28 | ['', ' هزار', ' میلیون', ' میلیارد', ' بیلیون', ' بیلیارد', ' تریلیون', ' تریلیارد', 29 | ' کوآدریلیون', ' کادریلیارد', ' کوینتیلیون', ' کوانتینیارد', ' سکستیلیون', ' سکستیلیارد', ' سپتیلیون', 30 | ' سپتیلیارد', ' اکتیلیون', ' اکتیلیارد', ' نانیلیون', ' نانیلیارد', ' دسیلیون', ' دسیلیارد' 31 | ], 32 | ]; 33 | 34 | /** 35 | * Decimal suffixes for decimal part 36 | * @type {string[]} 37 | */ 38 | const decimalSuffixes = [ 39 | '', 40 | 'دهم', 41 | 'صدم', 42 | 'هزارم', 43 | 'ده‌هزارم', 44 | 'صد‌هزارم', 45 | 'میلیونوم', 46 | 'ده‌میلیونوم', 47 | 'صدمیلیونوم', 48 | 'میلیاردم', 49 | 'ده‌میلیاردم', 50 | 'صد‌‌میلیاردم' 51 | ]; 52 | 53 | /** 54 | * Clear number and split to 3 sections 55 | * @param {*} num 56 | */ 57 | const prepareNumber = (num) => { 58 | let out = num; 59 | if (typeof out === 'number') { 60 | out = out.toString(); 61 | } 62 | 63 | //make first part 3 chars 64 | if (out.length % 3 === 1) { 65 | out = `00${out}`; 66 | } else if (out.length % 3 === 2) { 67 | out = `0${out}`; 68 | } 69 | // Explode to array 70 | return out.replace(/\d{3}(?=\d)/g, '$&*').split('*'); 71 | }; 72 | 73 | //tinyNumToWord convert 3tiny parts to word 74 | const tinyNumToWord = (num) => { 75 | // return zero 76 | if (parseInt(num, 0) === 0) { 77 | return ''; 78 | } 79 | const parsedInt = parseInt(num, 0); 80 | if (parsedInt < 10) { 81 | return letters[0][parsedInt]; 82 | } 83 | if (parsedInt <= 20) { 84 | return letters[1][parsedInt - 10]; 85 | } 86 | if (parsedInt < 100) { 87 | const one = parsedInt % 10; 88 | const ten = (parsedInt - one) / 10; 89 | if (one > 0) { 90 | return letters[2][ten] + delimiter + letters[0][one]; 91 | } 92 | return letters[2][ten]; 93 | } 94 | const one = parsedInt % 10; 95 | const hundreds = (parsedInt - (parsedInt % 100)) / 100; 96 | const ten = (parsedInt - ((hundreds * 100) + one)) / 10; 97 | const out = [letters[3][hundreds]]; 98 | const secondPart = ((ten * 10) + one); 99 | 100 | if (secondPart === 0) { 101 | return out.join(delimiter); 102 | } 103 | 104 | if (secondPart < 10) { 105 | out.push(letters[0][secondPart]); 106 | } else if (secondPart <= 20) { 107 | out.push(letters[1][secondPart - 10]); 108 | } else { 109 | out.push(letters[2][ten]); 110 | if (one > 0) { 111 | out.push(letters[0][one]); 112 | } 113 | } 114 | 115 | return out.join(delimiter); 116 | }; 117 | 118 | 119 | /** 120 | * Convert Decimal part 121 | * @param decimalPart 122 | * @returns {string} 123 | * @constructor 124 | */ 125 | const convertDecimalPart = (decimalPart) => { 126 | // Clear right zero 127 | decimalPart = decimalPart.replace(/0*$/, ""); 128 | 129 | if (decimalPart === '') { 130 | return ''; 131 | } 132 | 133 | if (decimalPart.length > 11) { 134 | decimalPart = decimalPart.substr(0, 11); 135 | } 136 | return ' ممیز ' + Num2persian(decimalPart) + ' ' + decimalSuffixes[decimalPart.length]; 137 | }; 138 | 139 | /** 140 | * Main function 141 | * @param input 142 | * @returns {string} 143 | * @constructor 144 | */ 145 | const Num2persian = (input:string):string => { 146 | // Clear Non digits 147 | input = input.toString().replace(/[^0-9.-]/g, ''); 148 | let isNegative = false; 149 | const floatParse = parseFloat(input); 150 | // return zero if this isn't a valid number 151 | if (isNaN(floatParse)) { 152 | return zero; 153 | } 154 | // check for zero 155 | if (floatParse === 0){ 156 | return zero; 157 | } 158 | // set negative flag:true if the number is less than 0 159 | if (floatParse < 0){ 160 | isNegative = true; 161 | input = input.replace(/-/g, ''); 162 | } 163 | 164 | // Declare Parts 165 | let decimalPart = ''; 166 | let integerPart = input; 167 | let pointIndex = input.indexOf('.'); 168 | // Check for float numbers form string and split Int/Dec 169 | if (pointIndex > -1) { 170 | integerPart = input.substring(0, pointIndex); 171 | decimalPart = input.substring(pointIndex + 1, input.length); 172 | } 173 | 174 | if (integerPart.length > 66) { 175 | return 'خارج از محدوده'; 176 | } 177 | 178 | // Split to sections 179 | const slicedNumber = prepareNumber(integerPart); 180 | // Fetch Sections and convert 181 | const out = []; 182 | for (let i = 0; i < slicedNumber.length; i += 1) { 183 | const converted = tinyNumToWord(slicedNumber[i]); 184 | if (converted !== '') { 185 | out.push(converted + letters[4][slicedNumber.length - (i + 1)]); 186 | } 187 | } 188 | 189 | // Convert Decimal part 190 | if (decimalPart.length > 0) { 191 | decimalPart = convertDecimalPart(decimalPart); 192 | } 193 | 194 | return (isNegative?negative:'') + out.join(delimiter) + decimalPart; 195 | }; 196 | 197 | 198 | export default Num2persian 199 | -------------------------------------------------------------------------------- /components/Libs/NumAbbrev.ts: -------------------------------------------------------------------------------- 1 | 2 | export default (num:number, digits:number = 1):string => { 3 | const lookup = [ 4 | { value: 1, symbol: "" }, 5 | { value: 1e3, symbol: "k" }, 6 | { value: 1e6, symbol: "M" }, 7 | { value: 1e9, symbol: "G" }, 8 | { value: 1e12, symbol: "T" }, 9 | { value: 1e15, symbol: "P" }, 10 | { value: 1e18, symbol: "E" } 11 | ]; 12 | const rx = /\.0+$|(\.[0-9]*[1-9])0+$/; 13 | var item = lookup.slice().reverse().find(function(item) { 14 | return num >= item.value; 15 | }); 16 | return item ? (num / item.value).toLocaleString(lang.region,{maximumFractionDigits:digits}).replace(rx, "$1") + item.symbol : "0"; 17 | } 18 | -------------------------------------------------------------------------------- /components/Libs/OpeningDetail.tsx: -------------------------------------------------------------------------------- 1 | export default (props)=> 2 | { 3 | return
4 | {props.open?props.children:null} 5 |
6 | } -------------------------------------------------------------------------------- /components/Libs/OpeningTitle.tsx: -------------------------------------------------------------------------------- 1 | 2 | export default (props) => { 3 | var toggleThin1 = () => { 4 | var em = document.getElementById(props.name + '_detail_' + props.id); 5 | var temp = window.getComputedStyle(em).getPropertyValue("max-height"); 6 | if (temp == "0px") { 7 | props.onflip(true) 8 | closeAllOtherThins(props.name + '_detail_' + props.id); 9 | document.getElementById(props.name + '_detail_' + props.id).className = styles.openheight; 10 | } 11 | else { 12 | 13 | document.getElementById(props.name + '_detail_' + props.id).className = styles.closeheight; 14 | setTimeout(() => { 15 | props.onflip(false) 16 | }, 300); 17 | } 18 | } 19 | 20 | var closeAllOtherThins = (except) => { 21 | var els = document.getElementsByTagName("div"); 22 | Array.from(els).forEach(el => { 23 | var id = el.getAttribute("id"); 24 | if (id) { 25 | if (id.includes(props.name + "_detail_")) { 26 | if (id != except) { 27 | el.className = styles.closeheight 28 | } 29 | } 30 | } 31 | }); 32 | } 33 | 34 | let el = null 35 | return
{ 36 | props.onclick?.(); toggleThin1(); 37 | 38 | // if (props.savescroll) { 39 | // setTimeout(() => { 40 | // document.getElementById(props.id + "_scroller").scrollIntoView({ behavior: "smooth", block: "start" }) 41 | 42 | // // var element = document.getElementById(props.id + "_scroller") 43 | // // var headerOffset = 10; 44 | // // var elementPosition = element.getBoundingClientRect().top; 45 | // // var offsetPosition = elementPosition + window.pageYOffset - headerOffset; 46 | // // global.parentdiv.scrollTo({ 47 | // // top: offsetPosition, 48 | // // behavior: "smooth" 49 | // // }); 50 | 51 | // }, 400); 52 | // } 53 | 54 | }} > 55 |
56 | {props.children} 57 |
58 | } -------------------------------------------------------------------------------- /components/Libs/PhoneBox.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import CountryList from './CountryList'; 3 | import Bold from './Bold'; 4 | 5 | export default (props:{defaultCChar?:string, 6 | title?:string, 7 | sup?:string, 8 | defaultPhone?:string, 9 | onccode:(string)=>void, 10 | oncchar:(string)=>void, 11 | readOnly?:boolean, 12 | onok?:()=>void, 13 | on?:(string)=>void, 14 | id:string, 15 | placeholder?:string, 16 | clist:{title:string, title2:string,} 17 | 18 | }) => { 19 | var [countries, setCountries] = useState(null); 20 | var [clist, setClist] = useState(false); 21 | var [ccode, setCCode] = useState(props.defaultCChar ? props.defaultCChar?.toLowerCase?.() : "us"); 22 | 23 | //var cntx = localStorage.getItem("countries"); 24 | var country = null; 25 | if (typeof window != "undefined") { 26 | if (!window.countries) { 27 | var getCountries = async () => { 28 | window.countries = await (await fetch(global.cdn("/files/countries.json"))).json(); 29 | setCountries(window.countries) 30 | } 31 | getCountries(); 32 | } 33 | else { 34 | if (!countries) { 35 | countries = window.countries 36 | } 37 | } 38 | var country:any = window.countries ? Object.values(countries).filter(c => (c as any).code.toLowerCase() == ccode.toLowerCase())[0] : null; 39 | 40 | } 41 | 42 | 43 | return <> 44 | 45 | {clist ? { setCCode(cc); props.onccode ? props.onccode(countries[cc].dialCode) : null; props.oncchar ? props.oncchar(countries[cc].code) : null }} 47 | onclose={() => { setClist(false) }} /> : null} 48 | 49 |
50 | {props.title}{props.sup} 51 |
52 | {country ? <>
{ 53 | setClist(true) 54 | }} 55 | dangerouslySetInnerHTML={{ __html: country.flag }} 56 | 57 | >
  : "null"} 58 | { 59 | setClist(true) 60 | }}>{country ? country.dialCode : ""}   61 | { 65 | if (e.code == "Enter" || e.code == "NumpadEnter" || e.key == "Enter") { 66 | props.onok?.(); 67 | } 68 | }} 69 | placeholder={props.placeholder} onChange={(e) => { props.on ? props.on(e.target.value) : null }} /> 70 |
71 |
72 | } -------------------------------------------------------------------------------- /components/Libs/PhoneEditFloat.tsx: -------------------------------------------------------------------------------- 1 | import Bold from './Bold'; 2 | import PhoneBox from './PhoneBox'; 3 | import WindowFloat from './WindowFloat' 4 | 5 | export default (props: { 6 | defaultCCode?: string, defaultCChar?: string, defaultPhone?: string, 7 | pattern?: string, errorstr?: string, title: string, title2: string, placeholder?: string, clist?: { title: string, title2: string, }, 8 | on?: (v: { ccode: string, phone: string, cchar: string }) => void, onclose?: () => void, explain?: string 9 | 10 | }) => { 11 | 12 | var ccode = props.defaultCCode || "+1"; 13 | var cchar = props.defaultCChar || "US"; 14 | var phone = props.defaultPhone || ""; 15 | 16 | var onok = () => { 17 | if (props.pattern) { 18 | var rx = new RegExp(props.pattern) 19 | if (!rx.test(phone)) { 20 | alerter(props.errorstr) 21 | return; 22 | } 23 | } 24 | if (phone.length > 6) { 25 | if (phone.startsWith('0')) { 26 | phone = phone.slice(1); 27 | } 28 | props.on?.({ ccode: ccode, phone: phone, cchar: cchar }) 29 | } 30 | else { 31 | alerter(props.errorstr) 32 | } 33 | } 34 | 35 | return { props.onclose?.() }}> 36 | 37 | { ccode = cc }} 46 | oncchar={(char) => { cchar = char }} 47 | onok={() => onok()} 48 | on={(p) => { 49 | if (p.startsWith("0")) { 50 | p = p.substr(1) 51 | } 52 | phone = p 53 | }} 54 | 55 | /> 56 | 57 | 58 | {props.explain} 59 | 60 | 61 |
62 | { onok() }} >{lang.confirm}   63 |
64 | 65 |
66 | } -------------------------------------------------------------------------------- /components/Libs/PriceRaw.tsx: -------------------------------------------------------------------------------- 1 | export default (props)=> 2 | { 3 | return <> 4 | } -------------------------------------------------------------------------------- /components/Libs/PriceTextBox.tsx: -------------------------------------------------------------------------------- 1 | 2 | export default (props:{ 3 | on?:(number)=>void, 4 | fractions:number, 5 | readOnly?:boolean, 6 | title?:string, 7 | explain:number, 8 | explainstr?:string, 9 | unit?:string, 10 | onlefticon?:()=>void 11 | lefticon?:string, 12 | defaultValue?:string, 13 | righttext?:any 14 | }) => { 15 | var region = lang.region || "en-US" 16 | var rand = Math.random(); 17 | var update = (el) => { 18 | var amount = parseFloat(el.value.split(",").join("")); 19 | props.on ? props.on(amount) : null; 20 | document.getElementById("pricebox").innerText = amount.toLocaleString(region, 21 | { maximumFractionDigits: props.fractions, minimumFractionDigits: props.fractions }) 22 | } 23 | return <>
24 | {props.title} {props.explain != undefined && !props.readOnly ? <>( { 26 | var el = document.getElementById("price" + rand) as HTMLInputElement; 27 | el.value = props.explain.toString() 28 | update(el) 29 | }}>{props.explainstr}: {props.explain.toLocaleString(region, 30 | { maximumFractionDigits: props.fractions, minimumFractionDigits: props.fractions })} {props.unit} ) : null} 31 |
32 | 33 | {props.lefticon ? <> { props.onlefticon ? props.onlefticon() : null }} /> : null} 35 | 36 | 37 | { 49 | if ((!/[0-9]/.test(event.key)) && (!/\./.test(event.key))) { 50 | event.preventDefault(); 51 | } 52 | }} 53 | 54 | onKeyUp={(event) => { 55 | if (event.currentTarget.value.length > 0) { 56 | setTimeout(() => { 57 | update(event.target); 58 | }, 20); 59 | } 60 | }} 61 | /> 62 | 63 |   {props.righttext}  64 |
65 |
66 | 67 | 68 | 69 | {lang.amount}: 70 | {!props.defaultValue ? (0).toLocaleString(lang.region) : parseFloat(props.defaultValue).toLocaleString(lang.region)} 71 | {props.unit} 72 | 73 | 74 | 75 | 76 | } -------------------------------------------------------------------------------- /components/Libs/ProfileImage.tsx: -------------------------------------------------------------------------------- 1 | import Cropper from 'react-easy-crop' 2 | import Upload from './Upload' 3 | import { useState } from 'react'; 4 | import WindowFloat from './WindowFloat'; 5 | import Circle from './Circle'; 6 | 7 | export default (props) => { 8 | // var pimage = null 9 | 10 | var [crp, setCrp] = useState({ 11 | imageSrc: global.user.image || global.cdn("/files/user.svg"), 12 | // imageSrc:global.cdn("/files/user.svg"), 13 | crop: { x: 0, y: 0 }, 14 | zoom: 1, 15 | aspect: 1, 16 | portion: 1, 17 | refw: 1, 18 | }) 19 | // var functions: any = {} 20 | var refreshcrp = () => { 21 | setCrp(JSON.parse(JSON.stringify(crp))) 22 | } 23 | var onCropChange = (crop) => { 24 | crp.crop = crop; 25 | refreshcrp(); 26 | } 27 | 28 | var onCropComplete = (croppedArea, croppedAreaPixels) => { 29 | // console.log(croppedAreaPixels.width / croppedAreaPixels.height) 30 | } 31 | 32 | var onZoomChange = (zoom) => { 33 | crp.zoom = zoom; 34 | refreshcrp(); 35 | } 36 | 37 | return <> 38 | props.onclose?.()}> 39 | 40 |
41 | { 49 | crp.portion = media.naturalWidth / media.naturalHeight 50 | crp.refw = media.width, 51 | refreshcrp(); 52 | }} 53 | onCropChange={onCropChange} 54 | onCropComplete={onCropComplete} 55 | onZoomChange={onZoomChange} 56 | /> 57 |
58 | 59 | 60 | { 67 | if (st.length == 0) return 68 | if (st[0].percent < 100) { 69 | crp.imageSrc = global.cdn("/files/picload.svg"); 70 | refreshcrp(); 71 | } 72 | else { 73 | crp.imageSrc = st[0].url; 74 | refreshcrp() 75 | } 76 | 77 | // global.uploaders["profile-image"].clear() 78 | }} 79 | /> 80 | 81 | 82 | 83 | { 84 | global.uploaders["profile-image"].open() 85 | }}> 86 | {lang.uploadnewpic} 87 | 88 | 89 | { 90 | if (!crp.imageSrc) { 91 | alerter("there is no image to send."); 92 | return; 93 | } 94 | let json = await (await fetch('/api/user/profilepic', { 95 | method: "POST", 96 | body: JSON.stringify({ 97 | url: crp.imageSrc, 98 | zoom: crp.zoom, 99 | x: crp.crop.x, 100 | y: crp.crop.y, 101 | portion: crp.portion, 102 | refw: crp.refw, 103 | }) 104 | })).json() 105 | 106 | if (json.code == 0) { 107 | window.location.reload(); 108 | props.onclose?.() 109 | } 110 | else { 111 | alerter(JSON.stringify(json)) 112 | } 113 | }}> 114 | {lang.confirm} 115 | 116 | 117 | {/* { 118 | functions.open(); 119 | }}> 120 | 121 | received transaction count 122 |   {lang.upload} 123 | */} 124 | 125 | 126 |
127 | 128 | } -------------------------------------------------------------------------------- /components/Libs/ReplacePro.tsx: -------------------------------------------------------------------------------- 1 | export default (array:any[] | string, text:string, obj:any):any[] => 2 | { 3 | let uniquekey = new Date().getTime(); 4 | var arr = array; 5 | if(typeof arr == "string") 6 | { 7 | arr = [array as any] 8 | } 9 | 10 | var temparr = []; 11 | for(let a = 0; a < arr.length; a++) 12 | { 13 | var x = arr[a]; 14 | if(typeof x == "string" && x.includes(text)) 15 | { 16 | var p = x.split(text) 17 | for(let i = 0; i < p.length; i++) 18 | { 19 | temparr.push(p[i]) 20 | if(p.length - 1 != i) 21 | { 22 | temparr.push(obj) 23 | } 24 | } 25 | } 26 | else 27 | { 28 | temparr.push(x) 29 | } 30 | } 31 | return temparr 32 | } -------------------------------------------------------------------------------- /components/Libs/ReplaceWordRegex.ts: -------------------------------------------------------------------------------- 1 | export default (text:string, oldword:string, newword:string ) => { 2 | let exp = text; 3 | exp = exp.replace(new RegExp(" " + oldword + " ", "gi"), " " + newword + " ") 4 | exp = exp.replace(new RegExp(" " + oldword + "\\\\", "gi"), " " + newword + "\\") 5 | exp = exp.replace(new RegExp("\\\\" + oldword + " ", "gi"), "\\\\" + newword + " ") 6 | exp = exp.replace(new RegExp(" " + oldword + "/", "gi"), " " + newword + "/") 7 | exp = exp.replace(new RegExp("/" + oldword + " ", "gi"), "/" + newword + " ") 8 | exp = exp.replace(new RegExp("‌" + oldword + " ", "gi"), "‌" + newword + " ") 9 | exp = exp.replace(new RegExp("‌" + oldword + "‌", "gi"), "‌" + newword + "‌") 10 | exp = exp.replace(new RegExp(" " + oldword + "‌", "gi"), " " + newword + "‌") 11 | exp = exp.replace(new RegExp("\\(" + oldword + "\\)", "gi"), "(" + newword + ")") 12 | exp = exp.replace(new RegExp(" " + oldword + "\\.", "gi"), " " + newword + ".") 13 | exp = exp.replace(new RegExp("\\(" + oldword + "\\.", "gi"), "(" + newword + ".") 14 | exp = exp.replace(new RegExp(" " + oldword + "$", "gi"), " " + newword) 15 | exp = exp.replace(new RegExp("^" + oldword + " ", "gi"), " " + newword) 16 | exp = exp.replace(new RegExp(" " + oldword + ",", "gi"), " " + newword + ",") 17 | exp = exp.replace(new RegExp("," + oldword + " ", "gi"), "," + newword + " ") 18 | exp = exp.replace(new RegExp(" " + oldword + "،", "gi"), " " + newword + "،") 19 | exp = exp.replace(new RegExp("،" + oldword + " ", "gi"), "،" + newword + " ") 20 | return exp; 21 | } 22 | 23 | export const Includes = (text:string, word)=>{ 24 | return new RegExp(" " + word + " ", "gi").test(text) 25 | || new RegExp(" " + word + "\\\\", "gi").test(text) 26 | || new RegExp("\\\\" + word + " ", "gi").test(text) 27 | || new RegExp("/" + word + " ", "gi").test(text) 28 | || new RegExp(" " + word + "/", "gi").test(text) 29 | || new RegExp("‌" + word + " ", "gi").test(text) 30 | || new RegExp("‌" + word + "‌", "gi").test(text) 31 | || new RegExp(" " + word + "‌", "gi").test(text) 32 | || new RegExp("\\(" + word + "\\)", "gi").test(text) 33 | || new RegExp(" " + word + "\\.", "gi").test(text) 34 | || new RegExp("\\(" + word + "\\.", "gi").test(text) 35 | || new RegExp(" " + word + "$", "gi").test(text) 36 | || new RegExp("^" + word + " ", "gi").test(text) 37 | || new RegExp(" " + word + ",", "gi").test(text) 38 | || new RegExp("," + word + " ", "gi").test(text) 39 | || new RegExp(" " + word + "،", "gi").test(text) 40 | || new RegExp("،" + word + " ", "gi").test(text) 41 | } -------------------------------------------------------------------------------- /components/Libs/Search.tsx: -------------------------------------------------------------------------------- 1 | import Router from 'next/router' 2 | import { useState, useEffect } from 'react' 3 | export default (props:{ 4 | defaultValue?:string, 5 | on?:(string)=>void, 6 | mainpage?:boolean, 7 | title?:string, 8 | lbtntext?:string, 9 | onplus?:()=>void, 10 | lefticon?:any, 11 | lefticondisable?:boolean, placeholder?:string, 12 | onbtnl?:()=>void,onlefticon?:()=>void, 13 | }) => { 14 | var [clicked, setClicked] = useState(false) 15 | 16 | useEffect(() => { 17 | if (!props.defaultValue && !Router.query.s && (document.getElementById("searchinput") as HTMLInputElement).value) { 18 | (document.getElementById("searchinput") as HTMLInputElement).value = "" 19 | } 20 | }) 21 | var onsearch = (txt) => { 22 | if (props.on) { 23 | props.on(txt) 24 | } 25 | else { 26 | if (props.mainpage) { 27 | Router.push(global.root + "/" + txt) 28 | } 29 | else { 30 | if (txt == "") { 31 | delete Router.query.s 32 | Router.push({ pathname: Router.pathname, query: Router.query }) 33 | } 34 | else { 35 | Router.query.s = txt 36 | Router.push({ pathname: Router.pathname, query: Router.query }) 37 | } 38 | } 39 | 40 | } 41 | } 42 | return
43 | 44 |
45 | {props.title} 46 | 47 | {props.lbtntext ? <> { props.onbtnl?.() }}>{props.lbtntext} 48 |
: null} 49 |   50 | 51 | {props.onplus ? <> 52 | new icon { 54 | props.onplus?.() 55 | }} /> 56 | 57 | : null} 58 | 59 | {props.lefticon ? <> 60 | search option's icon { 63 | props.onlefticon?.() 64 | }} /> 65 | 66 | : null} 67 | 68 | 69 | 70 | 71 |
72 | 73 | { 78 | 79 | if ((document.getElementById("searchinput") as HTMLInputElement).value?.length > 0) { 80 | if (props.mainpage) { 81 | Router.push(global.root) 82 | } 83 | else { 84 | delete Router.query.s 85 | Router.push({ pathname: Router.pathname, query: Router.query }) 86 | } 87 | } 88 | }}> 89 | search close's icon { 92 | 93 | }} /> 94 | 95 | { if (!clicked) { e.target.select(); e.preventDefault(); setClicked(true) } }} 97 | placeholder={props.placeholder} type='text' defaultValue={props.defaultValue} 98 | onBlur={() => { setClicked(false) }} 99 | 100 | spellCheck={false} onKeyDown={(event) => { 101 | // console.log(event) 102 | if (event.key == "Enter" || event.key == "NumpadEnter") { 103 | onsearch(event.target.value) 104 | } 105 | }} />
106 |  go for search { 108 | onsearch((document.getElementById("searchinput") as HTMLInputElement).value) 109 | }} /> 110 |
111 |
112 |
113 | } -------------------------------------------------------------------------------- /components/Libs/SerialGenerator.ts: -------------------------------------------------------------------------------- 1 | 2 | export default (len:number):string =>{ 3 | var chars = "0123456789ABCDEFGHJKLMNOPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; 4 | var randomstring = ''; 5 | for (var i=0; i { 6 | const env = process.env.NODE_ENV 7 | 8 | if (servitem.timequota == 0) { 9 | return { expiredate: new Date(0), expiretick: 0, expired: false } 10 | } 11 | var now = servitem.lockdate || new Date().getTime(); 12 | var expdate = (servitem.lockdate ? (new Date().getTime() - servitem.lockdate) : 0) + 13 | servitem.regdate + (servitem.timequota + (servitem.extimequota || 0)) * 86400000; 14 | if (env == "development") { 15 | expdate -= (expdate % 10000) 16 | } 17 | return { expiredate: new Date(expdate), expiretick: expdate, expired: servitem ? (now - expdate > 0) : false } 18 | } 19 | -------------------------------------------------------------------------------- /components/Libs/TextArea.tsx: -------------------------------------------------------------------------------- 1 | import { CSSProperties } from 'react' 2 | import Bold from './Bold' 3 | export default (props:{ 4 | bold?:boolean, 5 | title?:string, 6 | defaultValue?:string, 7 | placeholder?:string, 8 | readonly?:boolean, 9 | readOnly?:boolean, 10 | minHeight?:number|string, 11 | style?:CSSProperties 12 | on?:(string)=>void, 13 | selectonclick?:boolean, 14 | })=> 15 | { 16 | var uniqekey = Math.random()*100 17 | return
18 |
{props.bold?{props.title}:props.title}
19 |