diff options
Diffstat (limited to 'src/app/create')
| -rw-r--r-- | src/app/create/page.styles.ts | 168 | ||||
| -rw-r--r-- | src/app/create/page.tsx | 207 |
2 files changed, 0 insertions, 375 deletions
diff --git a/src/app/create/page.styles.ts b/src/app/create/page.styles.ts deleted file mode 100644 index b54e095..0000000 --- a/src/app/create/page.styles.ts +++ /dev/null @@ -1,168 +0,0 @@ -import styled from "styled-components"; - -export const Content = styled.div` - max-width: 600px; - margin: 40px auto; - padding: 0 24px 60px; -`; - -export const Heading = styled.h1` - font-size: 22px; - font-weight: 800; - margin: 0 0 4px; -`; - -export const Subheading = styled.p` - font-size: 13px; - color: #909090; - margin: 0 0 32px; -`; - -export const Form = styled.div` - display: flex; - flex-direction: column; - gap: 14px; -`; - -export const FieldGroup = styled.div` - display: flex; - flex-direction: column; - gap: 5px; -`; - -export const Label = styled.label` - font-size: 12px; - font-weight: 600; - color: #606060; - text-transform: uppercase; - letter-spacing: 0.5px; -`; - -export const Input = styled.input` - height: 40px; - padding: 0 12px; - border: 1px solid #d4d4d4; - border-radius: 8px; - font-size: 14px; - color: #1a1a1a; - background-color: #fff; - transition: border-color 0.15s; - &:focus { - outline: none; - border-color: #1a1a1a; - } - &::placeholder { - color: #b0b0b0; - } -`; - -export const Divider = styled.div` - height: 1px; - background-color: #e5e5e5; - margin: 6px 0; -`; - -export const Row = styled.div` - display: grid; - grid-template-columns: 1fr 1fr; - gap: 12px; -`; - -export const GenerateButton = styled.button` - height: 42px; - padding: 0 24px; - border-radius: 10px; - border: none; - background-color: #1a1a1a; - color: #fff; - font-size: 14px; - font-weight: 600; - cursor: pointer; - transition: background-color 0.15s; - margin-top: 6px; - &:hover { - background-color: #333; - } -`; - -export const ModeButton = styled.button<{ $active: boolean }>` - height: 42px; - padding: 0 24px; - border-radius: 10px; - border: none; - cursor: pointer; - font-size: 14px; - font-weight: 600; - background-color: ${(p) => (p.$active ? "#1a1a1a" : "#e5e5e5")}; - color: ${(p) => (p.$active ? "#fff" : "#1a1a1a")}; - transition: background-color 0.15s; -`; - -export const OutputSection = styled.div` - margin-top: 32px; - display: flex; - flex-direction: column; - gap: 14px; -`; - -export const OutputLabel = styled.div` - font-size: 12px; - font-weight: 600; - color: #606060; - text-transform: uppercase; - letter-spacing: 0.5px; - margin-bottom: 5px; -`; - -export const CodeBox = styled.div` - position: relative; - background-color: #f0f0f0; - border: 1px solid #d4d4d4; - border-radius: 10px; - padding: 14px 48px 14px 14px; - font-family: "Courier New", monospace; - font-size: 13px; - color: #1a1a1a; - word-break: break-all; - line-height: 1.5; -`; - -export const CopyButton = styled.button<{ $copied: boolean }>` - position: absolute; - top: 10px; - right: 10px; - width: 30px; - height: 30px; - border-radius: 6px; - border: none; - background-color: ${(p) => (p.$copied ? "#22c55e" : "#d4d4d4")}; - color: ${(p) => (p.$copied ? "#fff" : "#606060")}; - font-size: 13px; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - transition: background-color 0.15s, color 0.15s; - &:hover { - background-color: ${(p) => (p.$copied ? "#16a34a" : "#c0c0c0")}; - color: #1a1a1a; - } -`; - -export const OpenLink = styled.a` - display: inline-flex; - align-items: center; - gap: 6px; - font-size: 13px; - font-weight: 500; - color: #1a1a1a; - text-decoration: none; - border: 1px solid #d4d4d4; - border-radius: 8px; - padding: 8px 14px; - background-color: #fff; - transition: background-color 0.15s; - &:hover { - background-color: #f0f0f0; - } -`; diff --git a/src/app/create/page.tsx b/src/app/create/page.tsx deleted file mode 100644 index 744ab95..0000000 --- a/src/app/create/page.tsx +++ /dev/null @@ -1,207 +0,0 @@ -"use client"; -import { useState } from "react"; -import { MdLibraryMusic } from "react-icons/md"; -import { FaCopy, FaCheck, FaExternalLinkAlt } from "react-icons/fa"; -import { Root, Navbar, Logo, LogoIcon, NavLink } from "../styles/shared"; -import { - Content, - Heading, - Subheading, - Form, - FieldGroup, - Label, - Input, - Divider, - Row, - GenerateButton, - OutputSection, - OutputLabel, - CodeBox, - CopyButton, - OpenLink, -} from "./page.styles"; - -interface TypingPayload { - file1?: string; - lrc?: string; - offset?: number; - title?: string; - artist?: string; - skip_backing?: boolean; -} - -export default function CreatePage() { - const [lrc, setLrc] = useState(""); - const [file1, setFile1] = useState(""); - const [offset, setOffset] = useState(""); - - const [typingTitle, setTypingTitle] = useState(""); - const [typingArtist, setTypingArtist] = useState(""); - const [skipBacking, setSkipBacking] = useState(true); - - const [code, setCode] = useState<string | null>(null); - const [copiedCode, setCopiedCode] = useState(false); - const [copiedUrl, setCopiedUrl] = useState(false); - - const resetCopyStates = () => { - setCopiedCode(false); - setCopiedUrl(false); - }; - - const generate = () => { - const payload: TypingPayload = {}; - if (file1.trim()) payload.file1 = file1.trim(); - if (lrc.trim()) payload.lrc = lrc.trim(); - if (offset.trim() !== "") payload.offset = Number(offset); - if (typingTitle.trim()) payload.title = typingTitle.trim(); - if (typingArtist.trim()) payload.artist = typingArtist.trim(); - payload.skip_backing = skipBacking; - - setCode(btoa(JSON.stringify(payload))); - resetCopyStates(); - }; - - const copy = (text: string, which: "code" | "url") => { - navigator.clipboard.writeText(text); - if (which === "code") { - setCopiedCode(true); - setTimeout(() => setCopiedCode(false), 2000); - } else { - setCopiedUrl(true); - setTimeout(() => setCopiedUrl(false), 2000); - } - }; - - const shareUrl = code ? `${window.location.origin}/game?code=${code}` : ""; - - return ( - <Root> - <Navbar> - <Logo href="/typing"> - <LogoIcon> - <MdLibraryMusic /> - </LogoIcon> - LRC-Type - </Logo> - <NavLink href="/typing">← Back</NavLink> - </Navbar> - - <Content> - <Heading>Create a Code</Heading> - <Subheading> - Generate a shareable code for your typing game session. - </Subheading> - - <Form> - <FieldGroup> - <Label>Primary Media</Label> - <Input - type="url" - placeholder="https://example.com/song.mp4" - value={file1} - onChange={(e) => setFile1(e.target.value)} - /> - </FieldGroup> - - <FieldGroup> - <Label>LRC Lyrics</Label> - <Input - type="url" - placeholder="https://example.com/song.lrc" - value={lrc} - onChange={(e) => setLrc(e.target.value)} - /> - </FieldGroup> - - <FieldGroup> - <Label title="Offset in milliseconds. Increase this value if the main audio is ahead of the lyrics."> - LRC Offset (ms) - </Label> - <Input - type="number" - placeholder="0" - value={offset} - onChange={(e) => setOffset(e.target.value)} - step="25" - /> - </FieldGroup> - - <Divider /> - - <Row> - <FieldGroup> - <Label>Title</Label> - <Input - type="text" - placeholder="Song Title" - value={typingTitle} - onChange={(e) => setTypingTitle(e.target.value)} - /> - </FieldGroup> - <FieldGroup> - <Label>Artist</Label> - <Input - type="text" - placeholder="Artist Name" - value={typingArtist} - onChange={(e) => setTypingArtist(e.target.value)} - /> - </FieldGroup> - </Row> - - <Row> - <FieldGroup> - <Label title="When enabled, lyrics inside parentheses are treated as backing lyrics and skipped."> - Skip Backing - </Label> - <Input - type="checkbox" - checked={skipBacking} - onChange={(e) => setSkipBacking(e.target.checked)} - style={{ width: "18px", height: "18px", marginTop: "10px" }} - /> - </FieldGroup> - </Row> - - <GenerateButton onClick={generate}>Generate Code</GenerateButton> - </Form> - - {code && ( - <OutputSection> - <div> - <OutputLabel>Code</OutputLabel> - <CodeBox> - {code} - <CopyButton - $copied={copiedCode} - onClick={() => copy(code, "code")} - aria-label="Copy code" - > - {copiedCode ? <FaCheck /> : <FaCopy />} - </CopyButton> - </CodeBox> - </div> - - <div> - <OutputLabel>Share URL</OutputLabel> - <CodeBox> - {shareUrl} - <CopyButton - $copied={copiedUrl} - onClick={() => copy(shareUrl, "url")} - aria-label="Copy URL" - > - {copiedUrl ? <FaCheck /> : <FaCopy />} - </CopyButton> - </CodeBox> - </div> - - <OpenLink href={shareUrl} target="_blank" rel="noopener noreferrer"> - <FaExternalLinkAlt /> Open in Typing Game - </OpenLink> - </OutputSection> - )} - </Content> - </Root> - ); -} |
