1
Fork 0
mirror of https://github.com/Steffo99/festa.git synced 2024-12-22 22:54:22 +00:00

Do more prototyping!

This commit is contained in:
Steffo 2022-05-27 02:46:30 +02:00
parent 91359e7299
commit e1409f3545
Signed by: steffo
GPG key ID: 6965406171929D01
21 changed files with 264 additions and 103 deletions

View file

@ -0,0 +1,28 @@
import * as React from "react"
export interface InputSlug extends React.HTMLProps<HTMLInputElement> {
onSlugChange?: (val: string) => void,
}
export function InputSlug(props: InputSlug) {
const [text, setText] = React.useState("")
const handleChange = React.useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
props.onChange?.(event)
let slug = event.target.value.toLowerCase().replaceAll(/[^a-z0-9]/g, "-")
props.onSlugChange?.(slug)
setText(slug)
},
[]
)
return (
<input
type="text"
value={text}
onChange={handleChange}
{...props}
/>
)
}

View file

@ -1,31 +1,50 @@
import { Trans, useTranslation } from "next-i18next" import { Trans, useTranslation } from "next-i18next"
import { LoginContext } from "../contexts/login" import { LoginContext } from "../contexts/login"
import { useDefinedContext } from "../hooks/useDefinedContext" import { useDefinedContext } from "../utils/definedContext"
import { InputSlug } from "./InputEventSlug"
import { LoginButton } from "./LoginButton" import { LoginButton } from "./LoginButton"
import { TelegramUserLink } from "./TelegramUserLink" import { LogoutLink } from "./LogoutLink"
import { TelegramUser } from "./TelegramUser"
export function Intro() { export function Intro() {
const {t} = useTranslation("common") const {t} = useTranslation("common")
const [login, setLogin] = useDefinedContext(LoginContext) const [login, _] = useDefinedContext(LoginContext)
const loginMessage = login ? ( const loginMessage = login ? <>
<Trans i18nKey="introTelegramLoggedIn"> <Trans i18nKey="introTelegramLoggedIn">
Sei connesso come <TelegramUserLink u={login}/>! introTelegramLoggedIn(1: <TelegramUser u={login}/>)
</Trans> </Trans>
) : ( <br/>
<Trans i18nKey="introTelegramLogin"> <LogoutLink/>
Effettua il login con Telegram per iniziare a creare il tuo evento. </> : <>
</Trans> {t("introTelegramLogin")}
) </>
const input = login ? <>
<p>
{t("introCreateEvent")}
</p>
<form>
{window.location.protocol}//
{window.location.host}/events/
<InputSlug
placeholder={t("introCreateEventSlugPlaceholder")}
/>
<button aria-label="Continue" className="input-square input-positive">
</button>
</form>
</> : <>
<LoginButton
botName="festaappbot"
/>
</>
return <> return <>
<p> <p>
{loginMessage} {loginMessage}
</p> </p>
<LoginButton {input}
botName="festaappbot"
/>
</> </>
} }

View file

@ -1,17 +1,12 @@
import * as React from 'react'; import * as React from 'react';
import {LoginContext} from "../contexts/login" import {LoginContext} from "../contexts/login"
import OriginalTelegramLoginButton from 'react-telegram-login' import OriginalTelegramLoginButton from 'react-telegram-login'
import { useDefinedContext } from '../hooks/useDefinedContext'; import { useDefinedContext } from '../utils/definedContext';
export function LoginButton(props: any) { export function LoginButton(props: any) {
const [login, setLogin] = useDefinedContext(LoginContext) const [login, setLogin] = useDefinedContext(LoginContext)
return React.useMemo(() => ( return (
login ?
<button onClick={() => setLogin(null)} className="btn-telegram">
Log out
</button>
:
<div className="container-btn-telegram"> <div className="container-btn-telegram">
<OriginalTelegramLoginButton <OriginalTelegramLoginButton
dataOnauth={setLogin} dataOnauth={setLogin}
@ -19,7 +14,5 @@ export function LoginButton(props: any) {
{...props} {...props}
/> />
</div> </div>
),
[login]
) )
} }

16
components/LogoutLink.tsx Normal file
View file

@ -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 (
<small>
<a href="javascript:void(0)" onClick={() => setLogin(null)}>
{t("introTelegramLogout")}
</a>
</small>
)
}

View file

@ -1,6 +1,6 @@
import Image from "next/image"; import Image from "next/image";
import { PostcardContext } from "../contexts/postcard"; import { PostcardContext } from "../contexts/postcard";
import { useDefinedContext } from "../hooks/useDefinedContext"; import { useDefinedContext } from "../utils/definedContext";
export function Postcard() { export function Postcard() {
const [postcard, _] = useDefinedContext(PostcardContext) const [postcard, _] = useDefinedContext(PostcardContext)

View file

@ -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 ?
<img
src={u.photo_url}
className="avatar-telegram-inline"
/>
:
null
}

View file

@ -1,24 +1,28 @@
import { UserData } from "../utils/telegram"; import { UserData } from "../utils/telegram";
import { TelegramAvatar } from "./TelegramAvatar";
interface TelegramUserLinkProps { interface TelegramUserLinkProps {
u: UserData u: UserData
} }
export function TelegramUserLink({u}: TelegramUserLinkProps) { export function TelegramUser({u}: TelegramUserLinkProps) {
if(u.username) return ( if(u.username) return (
<a href={`https://t.me/${u.username}`}> <a href={`https://t.me/${u.username}`}>
<TelegramAvatar u={u}/>
{u.username} {u.username}
</a> </a>
) )
else if(u.last_name) return ( else if(u.last_name) return (
<span> <span>
<TelegramAvatar u={u}/>
{u.first_name} {u.last_name} {u.first_name} {u.last_name}
</span> </span>
) )
else return ( else return (
<span> <span>
u.first_name <TelegramAvatar u={u}/>
{u.first_name}
</span> </span>
) )
} }

View file

@ -1,14 +0,0 @@
import { LoginContext } from "../contexts/login";
import { useDefinedContext } from "../hooks/useDefinedContext";
export function UserAvatar() {
const [login, _] = useDefinedContext(LoginContext)
return login ?
<img
src={login?.photo_url}
className="avatar-telegram"
/>
:
null
}

View file

@ -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" import * as Telegram from "../utils/telegram"

View file

@ -1,4 +1,4 @@
import { createStateContext } from "../hooks/useStateContext"; import { createStateContext } from "../utils/stateContext";
import { StaticImageData } from "next/image"; import { StaticImageData } from "next/image";
import * as Telegram from "../utils/telegram" import * as Telegram from "../utils/telegram"

View file

@ -10,11 +10,13 @@
}, },
"dependencies": { "dependencies": {
"@prisma/client": "3.14.0", "@prisma/client": "3.14.0",
"classnames": "^2.3.1",
"next": "12.1.6", "next": "12.1.6",
"next-i18next": "^11.0.0", "next-i18next": "^11.0.0",
"prisma": "^3.14.0", "prisma": "^3.14.0",
"react": "18.1.0", "react": "18.1.0",
"react-dom": "18.1.0", "react-dom": "18.1.0",
"react-storage-hooks": "^4.0.1",
"react-telegram-login": "^1.1.2" "react-telegram-login": "^1.1.2"
}, },
"devDependencies": { "devDependencies": {

View file

@ -4,21 +4,47 @@ import '../styles/postcard.css'
import "../styles/index.css" import "../styles/index.css"
import type { AppProps } from 'next/app' import type { AppProps } from 'next/app'
import { LoginContext } from '../contexts/login' import { LoginContext } from '../contexts/login'
import { useState } from 'react' import { useEffect, useState } from 'react'
import * as Telegram from "../utils/telegram" import * as Telegram from "../utils/telegram"
import defaultPostcard from "../public/postcards/adi-goldstein-Hli3R6LKibo-unsplash.jpg" import defaultPostcard from "../public/postcards/adi-goldstein-Hli3R6LKibo-unsplash.jpg"
import { Postcard } from '../components/Postcard' import { Postcard } from '../components/Postcard'
import { PostcardContext } from '../contexts/postcard' import { PostcardContext } from '../contexts/postcard'
import { StaticImageData } from 'next/image' import { StaticImageData } from 'next/image'
import { appWithTranslation } from 'next-i18next' 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 App = ({ Component, pageProps }: AppProps): JSX.Element => {
const loginHook = useState<Telegram.LoginData | null>(null) const [login, setLogin] = useState<Telegram.LoginData | null>(null)
const postcardHook = useState<string | StaticImageData>(defaultPostcard) const [postcard, setPostcard] = useState<string | StaticImageData>(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 ( return (
<PostcardContext.Provider value={postcardHook}> <PostcardContext.Provider value={[postcard, setPostcard]}>
<LoginContext.Provider value={loginHook}> <LoginContext.Provider value={[login, setLogin]}>
<Postcard/> <Postcard/>
<Component {...pageProps} /> <Component {...pageProps} />
</LoginContext.Provider> </LoginContext.Provider>

View file

@ -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?"
}

View file

@ -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": ""
}

View file

@ -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; padding: 0;
margin: 0; margin: 0;
background-color: var(--background);
font-family: sans-serif; 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 { h1, h2, h3, h4, h5, h6 {
margin: 0; 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 { a {
color: #4444ff; color: var(--anchor);
} }
a:visited { a:visited {
color: #aa44ff; color: var(--anchor-visited);
}
} }
@media (prefers-color-scheme: dark) { a:active {
body { color: var(--anchor-active);
background-color: black;
color: white;
text-shadow: 1px 1px 1px black;
} }
h1, h2, h3, h4, h5, h6 { input, button {
text-shadow: 2px 2px 2px black; 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;
} }
a { input[type="text"] {
color: #8888ff; border-style: inset;
} }
a:visited { input[type="submit"], button {
color: #aa88ff; 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);
} }

View file

@ -21,10 +21,8 @@
border-radius: 20px; border-radius: 20px;
} }
.avatar-telegram { .avatar-telegram-inline {
width: 40px; height: 1em;
height: 40px;
border-radius: 20px; border-radius: 20px;
margin-right: 3px;
margin-left: 4px;
} }

View file

@ -1,6 +1,6 @@
import * as React from "react" import * as React from "react"
import { useContext } 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. * Create a new defined context (see {@link createDefinedContext}) containing the tuple returned by {@link React.useState} for the given type.

View file

@ -1,6 +1,6 @@
import nodecrypto from "crypto" import nodecrypto from "crypto"
import { ParsedUrlQuery } from "querystring" import { ParsedUrlQuery } from "querystring"
import * as QueryString from "./querystring" import * as QueryString from "./queryString"
/** /**
* Serializable Telegram user data without any technical information. * Serializable Telegram user data without any technical information.

View file

@ -391,6 +391,11 @@ chalk@^4.0.0:
ansi-styles "^4.1.0" ansi-styles "^4.1.0"
supports-color "^7.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: color-convert@^2.0.1:
version "2.0.1" version "2.0.1"
resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 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" resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== 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: react-telegram-login@^1.1.2:
version "1.1.2" version "1.1.2"
resolved "https://registry.npmjs.org/react-telegram-login/-/react-telegram-login-1.1.2.tgz#28b9bdd68bb2710afca19354ac1f9428092836f0" resolved "https://registry.npmjs.org/react-telegram-login/-/react-telegram-login-1.1.2.tgz#28b9bdd68bb2710afca19354ac1f9428092836f0"