diff --git a/components/InputEventSlug.tsx b/components/InputEventSlug.tsx new file mode 100644 index 0000000..a881c1a --- /dev/null +++ b/components/InputEventSlug.tsx @@ -0,0 +1,28 @@ +import * as React from "react" + +export interface InputSlug extends React.HTMLProps { + onSlugChange?: (val: string) => void, +} + +export function InputSlug(props: InputSlug) { + const [text, setText] = React.useState("") + + const handleChange = React.useCallback((event: React.ChangeEvent) => { + props.onChange?.(event) + + let slug = event.target.value.toLowerCase().replaceAll(/[^a-z0-9]/g, "-") + props.onSlugChange?.(slug) + setText(slug) + }, + [] + ) + + return ( + + ) +} \ No newline at end of file diff --git a/components/Intro.tsx b/components/Intro.tsx index 5cf882b..7638435 100644 --- a/components/Intro.tsx +++ b/components/Intro.tsx @@ -1,31 +1,50 @@ import { Trans, useTranslation } from "next-i18next" import { LoginContext } from "../contexts/login" -import { useDefinedContext } from "../hooks/useDefinedContext" +import { useDefinedContext } from "../utils/definedContext" +import { InputSlug } from "./InputEventSlug" import { LoginButton } from "./LoginButton" -import { TelegramUserLink } from "./TelegramUserLink" +import { LogoutLink } from "./LogoutLink" +import { TelegramUser } from "./TelegramUser" export function Intro() { const {t} = useTranslation("common") - const [login, setLogin] = useDefinedContext(LoginContext) + const [login, _] = useDefinedContext(LoginContext) - const loginMessage = login ? ( + const loginMessage = login ? <> - Sei connesso come ! + introTelegramLoggedIn(1: ) - ) : ( - - Effettua il login con Telegram per iniziare a creare il tuo evento. - - ) - +
+ + : <> + {t("introTelegramLogin")} + + + const input = login ? <> +

+ {t("introCreateEvent")} +

+
+ {window.location.protocol}// + {window.location.host}/events/ + + + + : <> + + return <>

{loginMessage}

- + {input} } \ No newline at end of file diff --git a/components/LoginButton.tsx b/components/LoginButton.tsx index b367625..54f1ee5 100644 --- a/components/LoginButton.tsx +++ b/components/LoginButton.tsx @@ -1,25 +1,18 @@ import * as React from 'react'; import {LoginContext} from "../contexts/login" import OriginalTelegramLoginButton from 'react-telegram-login' -import { useDefinedContext } from '../hooks/useDefinedContext'; +import { useDefinedContext } from '../utils/definedContext'; export function LoginButton(props: any) { const [login, setLogin] = useDefinedContext(LoginContext) - return React.useMemo(() => ( - login ? - - : -
- -
- ), - [login] + return ( +
+ +
) } \ No newline at end of file diff --git a/components/LogoutLink.tsx b/components/LogoutLink.tsx new file mode 100644 index 0000000..46f5269 --- /dev/null +++ b/components/LogoutLink.tsx @@ -0,0 +1,16 @@ +import { useTranslation } from "next-i18next" +import { LoginContext } from "../contexts/login" +import { useDefinedContext } from "../utils/definedContext" + +export function LogoutLink() { + const [login, setLogin] = useDefinedContext(LoginContext) + const {t} = useTranslation("common") + + return ( + + setLogin(null)}> + {t("introTelegramLogout")} + + + ) +} \ No newline at end of file diff --git a/components/Postcard.tsx b/components/Postcard.tsx index cd59473..f6d2eda 100644 --- a/components/Postcard.tsx +++ b/components/Postcard.tsx @@ -1,6 +1,6 @@ import Image from "next/image"; import { PostcardContext } from "../contexts/postcard"; -import { useDefinedContext } from "../hooks/useDefinedContext"; +import { useDefinedContext } from "../utils/definedContext"; export function Postcard() { const [postcard, _] = useDefinedContext(PostcardContext) diff --git a/components/TelegramAvatar.tsx b/components/TelegramAvatar.tsx new file mode 100644 index 0000000..aa9406f --- /dev/null +++ b/components/TelegramAvatar.tsx @@ -0,0 +1,21 @@ +import { LoginContext } from "../contexts/login"; +import { useDefinedContext } from "../utils/definedContext"; +import { UserData } from "../utils/telegram"; + + +export interface TelegramAvatarProps { + u: UserData +} + + +export function TelegramAvatar({u}: TelegramAvatarProps) { + const [login, _] = useDefinedContext(LoginContext) + + return login ? + + : + null +} \ No newline at end of file diff --git a/components/TelegramUserLink.tsx b/components/TelegramUser.tsx similarity index 61% rename from components/TelegramUserLink.tsx rename to components/TelegramUser.tsx index ead5bbf..49dd72b 100644 --- a/components/TelegramUserLink.tsx +++ b/components/TelegramUser.tsx @@ -1,24 +1,28 @@ import { UserData } from "../utils/telegram"; +import { TelegramAvatar } from "./TelegramAvatar"; interface TelegramUserLinkProps { u: UserData } -export function TelegramUserLink({u}: TelegramUserLinkProps) { +export function TelegramUser({u}: TelegramUserLinkProps) { if(u.username) return ( + {u.username} ) else if(u.last_name) return ( + {u.first_name} {u.last_name} ) else return ( - u.first_name + + {u.first_name} ) } \ No newline at end of file diff --git a/components/UserAvatar.tsx b/components/UserAvatar.tsx deleted file mode 100644 index 4c32a66..0000000 --- a/components/UserAvatar.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { LoginContext } from "../contexts/login"; -import { useDefinedContext } from "../hooks/useDefinedContext"; - -export function UserAvatar() { - const [login, _] = useDefinedContext(LoginContext) - - return login ? - - : - null -} \ No newline at end of file diff --git a/contexts/login.tsx b/contexts/login.tsx index 778f2de..6421d86 100644 --- a/contexts/login.tsx +++ b/contexts/login.tsx @@ -1,4 +1,5 @@ -import { createStateContext } from "../hooks/useStateContext"; +import { useStorageState } from "react-storage-hooks"; +import { createStateContext } from "../utils/stateContext"; import * as Telegram from "../utils/telegram" diff --git a/contexts/postcard.tsx b/contexts/postcard.tsx index feec34a..77632cd 100644 --- a/contexts/postcard.tsx +++ b/contexts/postcard.tsx @@ -1,4 +1,4 @@ -import { createStateContext } from "../hooks/useStateContext"; +import { createStateContext } from "../utils/stateContext"; import { StaticImageData } from "next/image"; import * as Telegram from "../utils/telegram" diff --git a/package.json b/package.json index d88e03f..304bfd6 100644 --- a/package.json +++ b/package.json @@ -10,11 +10,13 @@ }, "dependencies": { "@prisma/client": "3.14.0", + "classnames": "^2.3.1", "next": "12.1.6", "next-i18next": "^11.0.0", "prisma": "^3.14.0", "react": "18.1.0", "react-dom": "18.1.0", + "react-storage-hooks": "^4.0.1", "react-telegram-login": "^1.1.2" }, "devDependencies": { diff --git a/pages/_app.tsx b/pages/_app.tsx index f35d416..1baa3a8 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -4,21 +4,47 @@ import '../styles/postcard.css' import "../styles/index.css" import type { AppProps } from 'next/app' import { LoginContext } from '../contexts/login' -import { useState } from 'react' +import { useEffect, useState } from 'react' import * as Telegram from "../utils/telegram" import defaultPostcard from "../public/postcards/adi-goldstein-Hli3R6LKibo-unsplash.jpg" import { Postcard } from '../components/Postcard' import { PostcardContext } from '../contexts/postcard' import { StaticImageData } from 'next/image' import { appWithTranslation } from 'next-i18next' +import { useStorageState } from 'react-storage-hooks' + +const dummyStorage = { + getItem: () => null, + setItem: () => {}, + removeItem: () => {}, +}; const App = ({ Component, pageProps }: AppProps): JSX.Element => { - const loginHook = useState(null) - const postcardHook = useState(defaultPostcard) + const [login, setLogin] = useState(null) + const [postcard, setPostcard] = useState(defaultPostcard) + + // Ha ha ha. Fooled you again, silly SSR! + const thatStorageOverThere = typeof sessionStorage !== "undefined" ? sessionStorage : undefined + + useEffect( + () => { + if(thatStorageOverThere === undefined) return + + const raw = sessionStorage.getItem("login") + if(raw === null) return + + const parsed = JSON.parse(raw) as Telegram.LoginData + const response = new Telegram.LoginResponse(parsed) + if(!response.isRecent) return + + setLogin(parsed) + }, + [thatStorageOverThere] + ) return ( - - + + diff --git a/public/locales/it-IT/common.json b/public/locales/it-IT/common.json index 1e5703e..9e26dfe 100644 --- a/public/locales/it-IT/common.json +++ b/public/locales/it-IT/common.json @@ -1,6 +1 @@ -{ - "siteTitle": "Festa", - "siteSubtitle": "Organizza il tuo evento ora!", - "introTelegramLogin": "Effettua il login con Telegram per iniziare a creare il tuo evento.", - "introTelegramLoggedIn": "Sei connesso come <1/>! Non sei tu?" -} \ No newline at end of file +{} \ No newline at end of file diff --git a/public/locales/it-IT/common.json.disabled b/public/locales/it-IT/common.json.disabled new file mode 100644 index 0000000..f1e29c3 --- /dev/null +++ b/public/locales/it-IT/common.json.disabled @@ -0,0 +1,8 @@ +{ + "siteTitle": "Festa", + "siteSubtitle": "Organizza il tuo evento ora!", + "introTelegramLogin": "Effettua il login con Telegram per iniziare a creare il tuo evento.", + "introTelegramLoggedIn": "Sei connesso come <1/>!", + "introTelegramLogout": "Non sei tu?", + "introCreateEvent": "" +} \ No newline at end of file diff --git a/styles/globals.css b/styles/globals.css index 9338580..2606d1a 100644 --- a/styles/globals.css +++ b/styles/globals.css @@ -1,7 +1,43 @@ -html, body { +@media (prefers-color-scheme: light) { + body { + --background: #fafafa; + --foreground: black; + --border: darkgray; + + --anchor: #4444ff; + --anchor-visited: #aa44ff; + --anchor-active: #ff4444; + + --positive: #008800; + --negative: #880000; + } +} + +@media (prefers-color-scheme: dark) { + body { + --background: #050505; + --foreground: white; + --border: darkgray; + + --anchor: #8888ff; + --anchor-visited: #aa88ff; + --anchor-active: #ff8888; + + --positive: #88ff88; + --negative: #ff8888; + } +} + + +body { padding: 0; margin: 0; + + background-color: var(--background); + font-family: sans-serif; + color: var(--foreground); + text-shadow: 1px 1px 1px var(--background); } * { @@ -10,43 +46,61 @@ html, body { h1, h2, h3, h4, h5, h6 { margin: 0; + text-shadow: 2px 2px 2px var(--background); } -@media (prefers-color-scheme: light) { - body { - background-color: white; - color: black; - } - - h1, h2, h3, h4, h5, h6 { - text-shadow: 1px 1px 1px white; - } - - a { - color: #4444ff; - } - - a:visited { - color: #aa44ff; - } +a { + color: var(--anchor); } -@media (prefers-color-scheme: dark) { - body { - background-color: black; - color: white; - text-shadow: 1px 1px 1px black; - } - - h1, h2, h3, h4, h5, h6 { - text-shadow: 2px 2px 2px black; - } - - a { - color: #8888ff; - } - - a:visited { - color: #aa88ff; - } +a:visited { + color: var(--anchor-visited); } + +a:active { + color: var(--anchor-active); +} + +input, button { + padding: 8px; + margin: 2px 4px; + + color: var(--foreground); + background-color: var(--background); + + border-width: 2px; + border-color: var(--border); + border-radius: 16px; + + font-size: medium; + height: 40px; + + vertical-align: middle; +} + +input[type="text"] { + border-style: inset; +} + +input[type="submit"], button { + border-style: outset; +} + +input[type="submit"]:active, button:active { + border-style: inset; +} + +.input-square { + width: 40px; + height: 40px; +} + +.input-positive { + border-color: var(--positive); + color: var(--positive); +} + +.input-negative { + border-color: var(--negative); + color: var(--negative); +} \ No newline at end of file diff --git a/styles/telegram.css b/styles/telegram.css index 56f41bb..44f91bc 100644 --- a/styles/telegram.css +++ b/styles/telegram.css @@ -21,10 +21,8 @@ border-radius: 20px; } -.avatar-telegram { - width: 40px; - height: 40px; +.avatar-telegram-inline { + height: 1em; border-radius: 20px; - - margin-left: 4px; + margin-right: 3px; } diff --git a/hooks/useDefinedContext.tsx b/utils/definedContext.tsx similarity index 100% rename from hooks/useDefinedContext.tsx rename to utils/definedContext.tsx diff --git a/utils/querystring.ts b/utils/queryString.ts similarity index 100% rename from utils/querystring.ts rename to utils/queryString.ts diff --git a/hooks/useStateContext.tsx b/utils/stateContext.tsx similarity index 88% rename from hooks/useStateContext.tsx rename to utils/stateContext.tsx index 5565d79..f1f49df 100644 --- a/hooks/useStateContext.tsx +++ b/utils/stateContext.tsx @@ -1,6 +1,6 @@ import * as React from "react" import { useContext } from "react" -import { createDefinedContext } from "./useDefinedContext" +import { createDefinedContext } from "./definedContext" /** * Create a new defined context (see {@link createDefinedContext}) containing the tuple returned by {@link React.useState} for the given type. diff --git a/utils/telegram.ts b/utils/telegram.ts index 57f977f..3436082 100644 --- a/utils/telegram.ts +++ b/utils/telegram.ts @@ -1,6 +1,6 @@ import nodecrypto from "crypto" import { ParsedUrlQuery } from "querystring" -import * as QueryString from "./querystring" +import * as QueryString from "./queryString" /** * Serializable Telegram user data without any technical information. diff --git a/yarn.lock b/yarn.lock index 460632f..016377b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -391,6 +391,11 @@ chalk@^4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +classnames@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" + integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== + color-convert@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" @@ -1504,6 +1509,11 @@ react-is@^16.13.1, react-is@^16.7.0: resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +react-storage-hooks@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/react-storage-hooks/-/react-storage-hooks-4.0.1.tgz#e30ed5cda48c77c431ecc02ec3824bd615f5b7fb" + integrity sha512-fetDkT5RDHGruc2NrdD1iqqoLuXgbx6AUpQSQLLkrCiJf8i97EtwJNXNTy3+GRfsATLG8TZgNc9lGRZOaU5yQA== + react-telegram-login@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/react-telegram-login/-/react-telegram-login-1.1.2.tgz#28b9bdd68bb2710afca19354ac1f9428092836f0"