diff --git a/src/App.tsx b/src/App.tsx index 48722d5..a5aa4d7 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,10 +5,11 @@ import PublicLinksPage from './routes/PublicLinksPage'; import AdminReviewPage from './routes/AdminReviewPage'; import DevLoginPage from './routes/DevLoginPage'; import LinkDetailPage from './routes/LinkDetailPage'; +import LegalPage from './routes/LegalPage'; import UserMenu from './components/UserMenu'; import { useCurrentUser } from './lib/auth'; -type RouteId = 'home' | 'my-links' | 'admin' | 'login' | 'dev-login' | 'profile' | 'settings' | 'link-detail'; +type RouteId = 'home' | 'my-links' | 'admin' | 'login' | 'dev-login' | 'profile' | 'settings' | 'terms' | 'privacy' | 'link-detail'; const NAV_TABS: readonly { id: RouteId; label: string }[] = [ { id: 'my-links', label: 'My Links' }, @@ -18,7 +19,7 @@ function readRouteFromHash(): RouteId { const hash = window.location.hash; if (!hash || hash === '#/' || hash === '#') return 'home'; if (hash.match(/^#\/links\//)) return 'link-detail'; - const match = hash.match(/^#\/(my-links|admin|login|dev-login|profile|settings)/); + const match = hash.match(/^#\/(my-links|admin|login|dev-login|profile|settings|terms|privacy)/); return (match?.[1] as RouteId) ?? 'home'; } @@ -99,6 +100,8 @@ export default function App() { {route === 'dev-login' ? : null} {route === 'profile' ? : null} {route === 'settings' ? : null} + {route === 'terms' ? : null} + {route === 'privacy' ? : null} {route === 'link-detail' && linkDetailId ? ( + {provider.id === 'google' ? G : null} {provider.label} ))} diff --git a/src/routes/LegalPage.tsx b/src/routes/LegalPage.tsx new file mode 100644 index 0000000..0728d27 --- /dev/null +++ b/src/routes/LegalPage.tsx @@ -0,0 +1,91 @@ +type LegalPageProps = { + kind: 'terms' | 'privacy'; +}; + +const updated = 'June 20, 2026'; + +export default function LegalPage({ kind }: LegalPageProps) { + const isTerms = kind === 'terms'; + + return ( +
+

Heygo

+

{isTerms ? 'Terms of Service' : 'Privacy Policy'}

+

Last updated: {updated}

+ + {isTerms ? : } +
+ ); +} + +function TermsContent() { + return ( + <> +

1. Using Heygo

+

+ Heygo lets you create, manage, and share shortlinks. You are responsible for + the links, descriptions, and content you create or submit. +

+ +

2. Accounts

+

+ You must use accurate account information and keep access to your account + secure. Activity from your signed-in account is treated as your activity. +

+ +

3. Acceptable use

+

+ Do not use Heygo for unlawful, harmful, deceptive, abusive, infringing, or + security-compromising content. We may remove links or restrict access when + needed to protect users or the service. +

+ +

4. Service changes

+

+ Heygo is provided as available. Features may change, pause, or stop, and we + are not liable for indirect losses or unavailable links. +

+ +

5. Contact

+

+ Questions about these terms can be sent to the service owner or administrator. +

+ + ); +} + +function PrivacyContent() { + return ( + <> +

1. Information we collect

+

+ We store account details from sign-in providers, such as your email, name, + profile image, provider account ID, session records, and links you create. +

+ +

2. How we use information

+

+ We use this information to sign you in, manage your links, protect private + links, review public-link submissions, and operate the service. +

+ +

3. Cookies and sessions

+

+ Heygo uses secure session cookies to keep you signed in and to authorize + private or admin actions. +

+ +

4. Sharing

+

+ We do not sell personal information. Public links and approved public + submissions may be visible to anyone with access to the public site. +

+ +

5. Retention and deletion

+

+ We keep account, session, and link records as needed to provide the service. + Contact the service owner or administrator to request deletion. +

+ + ); +} diff --git a/src/routes/LoginPage.tsx b/src/routes/LoginPage.tsx index 49690a7..a91bfe1 100644 --- a/src/routes/LoginPage.tsx +++ b/src/routes/LoginPage.tsx @@ -2,17 +2,14 @@ import ProviderButtons from '../components/ProviderButtons'; export default function LoginPage() { return ( -
-

Sign in to Heygo

-

- Manage your private shortlinks and browse the public directory. Private link management - requires a signed-in session. -

+
+ +

Sign in or create an account

-
-

- Don't want to sign in? You can still browse the{' '} - public links. +

+ By logging in, you agree to our{' '} + Terms of Service and{' '} + Privacy Policy.

); diff --git a/src/styles.css b/src/styles.css index ffc7c22..e7b152a 100644 --- a/src/styles.css +++ b/src/styles.css @@ -180,8 +180,108 @@ code { width: 100%; } -.login-panel { - max-width: 440px; +.login-panel { max-width: 440px; } + +.auth-page { + align-items: center; + background: + radial-gradient(circle at 50% 0%, rgba(99,102,241,0.12), transparent 34%), + var(--surface); + border: 1px solid var(--border); + border-radius: 12px; + box-shadow: 0 18px 50px rgba(15,23,42,0.08), 0 2px 12px rgba(15,23,42,0.04); + display: flex; + flex-direction: column; + margin-top: clamp(1rem, 8vh, 4.5rem); + max-width: 420px; + padding: 2.25rem 2rem 1.5rem; + text-align: center; + width: min(100%, 420px); +} + +.auth-mark { + align-items: center; + background: var(--text); + border-radius: 10px; + color: white; + display: flex; + font-family: 'Syne', ui-sans-serif, sans-serif; + font-size: 1.35rem; + font-weight: 800; + height: 44px; + justify-content: center; + margin-bottom: 1.1rem; + width: 44px; +} + +.auth-page h1 { + color: var(--text); + font-size: 1.45rem; + font-weight: 750; + line-height: 1.18; + margin: 0; +} + +.auth-copy { + color: var(--muted); + font-size: 0.92rem; + margin: 0.75rem 0 0; + max-width: 32ch; +} + +.auth-legal, +.auth-secondary { + color: var(--muted); + font-size: 0.78rem; + line-height: 1.45; + margin: 0; + max-width: 34ch; +} + +.auth-legal { + border-top: 1px solid var(--border); + margin-top: 0.95rem; + padding-top: 1rem; +} + +.auth-legal a, +.auth-secondary a { + font-size: inherit; + font-weight: 650; +} + +.auth-secondary { + margin-top: 0.85rem; +} + +.legal-page { + max-width: 760px; + padding: 2.25rem 2.5rem; +} + +.legal-kicker { + color: var(--accent-text); + font-family: 'Syne', ui-sans-serif, sans-serif; + font-size: 0.82rem; + font-weight: 800; + letter-spacing: 0; + margin: 0 0 0.35rem; +} + +.legal-page h1 { + font-size: 1.8rem; + line-height: 1.15; + margin: 0 0 0.35rem; +} + +.legal-page h2 { + font-size: 1rem; + margin: 1.55rem 0 0.45rem; +} + +.legal-page p { + color: var(--muted); + margin: 0; } .panel-header { @@ -279,30 +379,33 @@ code, display: flex; flex-direction: column; gap: 0.625rem; - margin: 1.25rem 0; + margin: 1.35rem 0 0; + width: 100%; } .provider-button { align-items: center; - background: var(--surface); + background: #0F172A; border: 1px solid var(--border-strong); - border-radius: var(--radius-sm); - color: var(--text); + border-radius: 8px; + color: white; display: flex; - font-weight: 500; + font-weight: 650; font-size: 0.9375rem; gap: 0.625rem; justify-content: center; - padding: 0.7rem 1rem; + min-height: 44px; + padding: 0.72rem 1rem; text-decoration: none; - transition: background 0.15s, border-color 0.15s, box-shadow 0.15s; + transition: background 0.15s, border-color 0.15s, box-shadow 0.15s, transform 0.15s; } .provider-button:hover { - background: #F8FAFF; - border-color: var(--accent); - box-shadow: 0 0 0 3px var(--accent-soft); - color: var(--text); + background: #1E293B; + border-color: #1E293B; + box-shadow: 0 8px 22px rgba(15,23,42,0.18); + color: white; text-decoration: none; + transform: translateY(-1px); } .provider-button.is-disabled { color: var(--muted); @@ -310,6 +413,18 @@ code, opacity: 0.6; } +.provider-button__icon { + align-items: center; + background: white; + border-radius: 50%; + color: #334155; + display: flex; + font-weight: 800; + height: 22px; + justify-content: center; + width: 22px; +} + .provider-note { color: var(--muted); font-size: 0.8125rem;