chore: legacy cleanup
Signed-off-by: Dmytro Stanchiev <git@dmytros.dev>
This commit is contained in:
@@ -24,8 +24,8 @@ function ErrorMessage() {
|
|||||||
|
|
||||||
export default function AuthErrorPage() {
|
export default function AuthErrorPage() {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center py-20">
|
<div className="flex items-center justify-center px-4 py-20">
|
||||||
<div className="glass-strong rounded-2xl p-8 w-full max-w-sm space-y-6">
|
<div className="w-full max-w-sm space-y-6 rounded-[10px] bg-card p-8 shadow-[0_0_0_1px_rgba(0,0,0,0.08),0_12px_40px_rgba(0,0,0,0.12)]">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<AlertTriangle className="h-8 w-8 text-destructive mx-auto mb-3" />
|
<AlertTriangle className="h-8 w-8 text-destructive mx-auto mb-3" />
|
||||||
<h1 className="text-lg font-semibold">Authentication Error</h1>
|
<h1 className="text-lg font-semibold">Authentication Error</h1>
|
||||||
@@ -39,7 +39,7 @@ export default function AuthErrorPage() {
|
|||||||
</Suspense>
|
</Suspense>
|
||||||
|
|
||||||
<Button variant="outline" asChild className="w-full">
|
<Button variant="outline" asChild className="w-full">
|
||||||
<Link href="/">Go back to Homepage</Link>
|
<Link href="/">Return to timeline</Link>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -144,16 +144,18 @@ export function SignInForm({ providers }: SignInFormProps) {
|
|||||||
initial={{ opacity: 0, y: 16 }}
|
initial={{ opacity: 0, y: 16 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
transition={{ duration: 0.3 }}
|
transition={{ duration: 0.3 }}
|
||||||
className="glass-strong p-8 max-w-sm w-full"
|
className="w-full max-w-sm rounded-[10px] bg-card p-8 shadow-[0_0_0_1px_rgba(0,0,0,0.08),0_12px_40px_rgba(0,0,0,0.12)]"
|
||||||
>
|
>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-center gap-2 mb-2">
|
<div className="flex items-center justify-center gap-2 mb-2">
|
||||||
<CalendarDays className="h-6 w-6 text-primary" aria-hidden="true" />
|
<CalendarDays className="h-6 w-6 text-primary" aria-hidden="true" />
|
||||||
<h1 className="text-xl font-semibold tracking-tight">Local iCal</h1>
|
<h1 className="text-xl font-semibold tracking-[-0.04em]">
|
||||||
|
Local Calendar
|
||||||
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p className="text-sm text-muted-foreground text-center mb-7">
|
<p className="text-sm text-muted-foreground text-center mb-7">
|
||||||
Sign in to unlock AI-powered event creation
|
Sign in to keep AI capture and your event timeline in sync
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{/* Provider buttons */}
|
{/* Provider buttons */}
|
||||||
@@ -193,7 +195,7 @@ export function SignInForm({ providers }: SignInFormProps) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Divider + guest link */}
|
{/* Divider + guest link */}
|
||||||
<div className="mt-6 pt-5 border-t border-border/50 text-center">
|
<div className="mt-6 border-t border-border/60 pt-5 text-center">
|
||||||
<Link
|
<Link
|
||||||
href="/"
|
href="/"
|
||||||
className="text-xs text-muted-foreground hover:text-foreground transition-colors"
|
className="text-xs text-muted-foreground hover:text-foreground transition-colors"
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ export default function SignOutPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center py-20">
|
<div className="flex items-center justify-center px-4 py-20">
|
||||||
<div className="glass-strong rounded-2xl p-8 w-full max-w-sm space-y-6">
|
<div className="w-full max-w-sm space-y-6 rounded-[10px] bg-card p-8 shadow-[0_0_0_1px_rgba(0,0,0,0.08),0_12px_40px_rgba(0,0,0,0.12)]">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<LogOut className="h-8 w-8 text-muted-foreground mx-auto mb-3" />
|
<LogOut className="h-8 w-8 text-muted-foreground mx-auto mb-3" />
|
||||||
<h1 className="text-lg font-semibold">Sign Out</h1>
|
<h1 className="text-lg font-semibold">Sign Out</h1>
|
||||||
@@ -37,7 +37,7 @@ export default function SignOutPage() {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="rounded-lg bg-muted/40 px-4 py-3 text-center">
|
<div className="rounded-[8px] bg-muted px-4 py-3 text-center shadow-[inset_0_0_0_1px_rgba(0,0,0,0.05)]">
|
||||||
<div className="text-xs text-muted-foreground mb-0.5">
|
<div className="text-xs text-muted-foreground mb-0.5">
|
||||||
Signed in as
|
Signed in as
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -227,99 +227,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@layer utilities {
|
@layer utilities {
|
||||||
.glass-surface {
|
|
||||||
background: linear-gradient(
|
|
||||||
180deg,
|
|
||||||
oklch(1 0 0 / 0.78),
|
|
||||||
oklch(0.985 0.003 247 / 0.92)
|
|
||||||
);
|
|
||||||
border: 1px solid oklch(0.89 0.005 247 / 0.95);
|
|
||||||
border-radius: calc(var(--radius) + 0.5rem);
|
|
||||||
box-shadow: 0 10px 30px oklch(0.3 0.01 260 / 0.08);
|
|
||||||
backdrop-filter: blur(18px) saturate(1.08);
|
|
||||||
}
|
|
||||||
.dark .glass-surface {
|
|
||||||
background: linear-gradient(
|
|
||||||
180deg,
|
|
||||||
oklch(0.23 0.015 265 / 0.72),
|
|
||||||
oklch(0.18 0.012 265 / 0.88)
|
|
||||||
);
|
|
||||||
border-color: oklch(1 0 0 / 0.09);
|
|
||||||
box-shadow: 0 18px 40px oklch(0 0 0 / 0.35);
|
|
||||||
}
|
|
||||||
.glass-panel {
|
|
||||||
background: linear-gradient(
|
|
||||||
180deg,
|
|
||||||
oklch(1 0 0 / 0.84),
|
|
||||||
oklch(0.992 0.002 247 / 0.96)
|
|
||||||
);
|
|
||||||
border: 1px solid oklch(0.89 0.005 247 / 0.95);
|
|
||||||
border-radius: calc(var(--radius) + 0.75rem);
|
|
||||||
box-shadow: 0 14px 36px oklch(0.3 0.01 260 / 0.08);
|
|
||||||
backdrop-filter: blur(20px) saturate(1.08);
|
|
||||||
}
|
|
||||||
.dark .glass-panel {
|
|
||||||
background: linear-gradient(
|
|
||||||
180deg,
|
|
||||||
oklch(0.22 0.014 265 / 0.78),
|
|
||||||
oklch(0.17 0.012 265 / 0.9)
|
|
||||||
);
|
|
||||||
border-color: oklch(1 0 0 / 0.1);
|
|
||||||
box-shadow: 0 22px 48px oklch(0 0 0 / 0.36);
|
|
||||||
}
|
|
||||||
.glass-subtle {
|
|
||||||
background: oklch(0.98 0.003 247 / 0.72);
|
|
||||||
border: 1px solid oklch(0.9 0.004 247 / 0.95);
|
|
||||||
border-radius: calc(var(--radius) + 0.5rem);
|
|
||||||
backdrop-filter: blur(14px);
|
|
||||||
}
|
|
||||||
.dark .glass-subtle {
|
|
||||||
background: oklch(0.25 0.012 265 / 0.42);
|
|
||||||
border-color: oklch(1 0 0 / 0.08);
|
|
||||||
}
|
|
||||||
/* Light: subtle card with border; Dark: glass panel */
|
|
||||||
.glass {
|
|
||||||
background: oklch(1 0 0 / 0.7);
|
|
||||||
border: 1px solid oklch(0.87 0.005 247);
|
|
||||||
border-radius: var(--radius);
|
|
||||||
}
|
|
||||||
.dark .glass {
|
|
||||||
background: oklch(1 0 0 / 0.04);
|
|
||||||
border-color: oklch(1 0 0 / 0.07);
|
|
||||||
backdrop-filter: blur(12px);
|
|
||||||
}
|
|
||||||
.glass-card {
|
|
||||||
background: linear-gradient(
|
|
||||||
180deg,
|
|
||||||
oklch(1 0 0 / 0.72),
|
|
||||||
oklch(0.99 0.002 247 / 0.94)
|
|
||||||
);
|
|
||||||
border: 1px solid oklch(0.9 0.005 247 / 0.95);
|
|
||||||
border-radius: calc(var(--radius) + 0.25rem);
|
|
||||||
box-shadow: 0 8px 20px oklch(0.3 0.01 260 / 0.06);
|
|
||||||
backdrop-filter: blur(16px) saturate(1.06);
|
|
||||||
}
|
|
||||||
.dark .glass-card {
|
|
||||||
background: linear-gradient(
|
|
||||||
180deg,
|
|
||||||
oklch(0.24 0.015 265 / 0.52),
|
|
||||||
oklch(0.18 0.012 265 / 0.72)
|
|
||||||
);
|
|
||||||
border-color: oklch(1 0 0 / 0.08);
|
|
||||||
box-shadow: 0 14px 32px oklch(0 0 0 / 0.26);
|
|
||||||
}
|
|
||||||
.glass-strong {
|
|
||||||
background: oklch(0.995 0.001 247 / 0.97);
|
|
||||||
border: 1px solid oklch(0.88 0.006 247);
|
|
||||||
border-radius: var(--radius);
|
|
||||||
box-shadow: 0 2px 8px oklch(0.3 0.01 260 / 0.08);
|
|
||||||
}
|
|
||||||
.dark .glass-strong {
|
|
||||||
backdrop-filter: blur(20px) saturate(1.2);
|
|
||||||
background: oklch(1 0 0 / 0.07);
|
|
||||||
border-color: oklch(1 0 0 / 0.1);
|
|
||||||
box-shadow: 0 4px 20px oklch(0 0 0 / 0.3);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@utility scrollbar-none {
|
@utility scrollbar-none {
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ const geistMono = Geist_Mono({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Local iCal",
|
title: "Local Calendar",
|
||||||
description: "Local iCal editor for calendar events",
|
description: "Event timeline console with AI capture",
|
||||||
creator: "Dmytro Stanchiev",
|
creator: "Dmytro Stanchiev",
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -43,7 +43,8 @@ export default function RootLayout({
|
|||||||
closeButton
|
closeButton
|
||||||
richColors
|
richColors
|
||||||
toastOptions={{
|
toastOptions={{
|
||||||
className: "glass-strong",
|
className:
|
||||||
|
"rounded-[10px] bg-card text-card-foreground shadow-[0_0_0_1px_rgba(0,0,0,0.08),0_12px_40px_rgba(0,0,0,0.12)]",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import type { MetadataRoute } from "next";
|
|||||||
|
|
||||||
export default function manifest(): MetadataRoute.Manifest {
|
export default function manifest(): MetadataRoute.Manifest {
|
||||||
return {
|
return {
|
||||||
name: "local-ical PWA",
|
name: "Local Calendar",
|
||||||
short_name: "local-ical",
|
short_name: "local-cal",
|
||||||
description: "Local iCal editor with AI features",
|
description: "Event timeline console with AI capture",
|
||||||
start_url: "/",
|
start_url: "/",
|
||||||
display: "standalone",
|
display: "standalone",
|
||||||
background_color: "#ffffff",
|
background_color: "#ffffff",
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ export const DragDropContainer = ({
|
|||||||
animate={{ opacity: 1 }}
|
animate={{ opacity: 1 }}
|
||||||
exit={{ opacity: 0 }}
|
exit={{ opacity: 0 }}
|
||||||
transition={{ duration: 0.15 }}
|
transition={{ duration: 0.15 }}
|
||||||
className="absolute inset-0 z-40 rounded-xl border-2 border-dashed border-primary/50 bg-primary/5 backdrop-blur-sm flex items-center justify-center"
|
className="absolute inset-0 z-40 flex items-center justify-center rounded-[10px] border-2 border-dashed border-primary/40 bg-background/92"
|
||||||
>
|
>
|
||||||
<div className="flex flex-col items-center gap-2 text-primary">
|
<div className="flex flex-col items-center gap-2 text-primary">
|
||||||
<FileUp className="h-8 w-8" />
|
<FileUp className="h-8 w-8" />
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ const ServerLocationInput = ({
|
|||||||
value={value}
|
value={value}
|
||||||
/>
|
/>
|
||||||
{showSuggestions ? (
|
{showSuggestions ? (
|
||||||
<div className="absolute left-0 right-0 top-[calc(100%+0.375rem)] z-20 rounded-md border border-border/60 bg-background/95 p-1 shadow-lg backdrop-blur-sm">
|
<div className="absolute left-0 right-0 top-[calc(100%+0.375rem)] z-20 rounded-[10px] bg-popover p-1.5 shadow-[0_0_0_1px_rgba(0,0,0,0.08),0_8px_24px_rgba(0,0,0,0.08)]">
|
||||||
<div className="space-y-1" role="listbox">
|
<div className="space-y-1" role="listbox">
|
||||||
{suggestions.map((suggestion) => {
|
{suggestions.map((suggestion) => {
|
||||||
const suggestionKey =
|
const suggestionKey =
|
||||||
@@ -198,7 +198,7 @@ const ServerLocationInput = ({
|
|||||||
return (
|
return (
|
||||||
<div key={suggestionKey}>
|
<div key={suggestionKey}>
|
||||||
<button
|
<button
|
||||||
className="w-full rounded-sm px-3 py-2 text-left text-sm text-foreground transition hover:bg-accent hover:text-accent-foreground"
|
className="w-full rounded-[6px] px-3 py-2 text-left text-sm text-foreground transition hover:bg-accent hover:text-accent-foreground"
|
||||||
onClick={() => handleSuggestionSelect(suggestion)}
|
onClick={() => handleSuggestionSelect(suggestion)}
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -69,12 +69,12 @@ export function SettingsPanel({
|
|||||||
</Label>
|
</Label>
|
||||||
<p className="text-sm leading-relaxed text-muted-foreground">
|
<p className="text-sm leading-relaxed text-muted-foreground">
|
||||||
When enabled, a single AI-generated event will be created
|
When enabled, a single AI-generated event will be created
|
||||||
directly instead of opening the review modal.
|
directly instead of waiting on extra review steps.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<Label
|
<Label
|
||||||
htmlFor="settings-skip-ai-review"
|
htmlFor="settings-skip-ai-review"
|
||||||
className="min-h-11 cursor-pointer justify-between rounded-xl border border-border/60 bg-muted/35 px-3 py-2"
|
className="min-h-11 cursor-pointer justify-between rounded-[8px] bg-muted px-3 py-2 shadow-[inset_0_0_0_1px_rgba(0,0,0,0.05)]"
|
||||||
>
|
>
|
||||||
<span className="text-sm font-medium text-foreground">
|
<span className="text-sm font-medium text-foreground">
|
||||||
{settings.skipAiReview
|
{settings.skipAiReview
|
||||||
@@ -115,7 +115,7 @@ export function SettingsPanel({
|
|||||||
</div>
|
</div>
|
||||||
<Label
|
<Label
|
||||||
htmlFor="settings-ai-enabled"
|
htmlFor="settings-ai-enabled"
|
||||||
className="min-h-11 cursor-pointer justify-between rounded-xl border border-border/60 bg-muted/35 px-3 py-2"
|
className="min-h-11 cursor-pointer justify-between rounded-[8px] bg-muted px-3 py-2 shadow-[inset_0_0_0_1px_rgba(0,0,0,0.05)]"
|
||||||
>
|
>
|
||||||
<span className="text-sm font-medium text-foreground">
|
<span className="text-sm font-medium text-foreground">
|
||||||
{settings.aiEnabled
|
{settings.aiEnabled
|
||||||
@@ -151,7 +151,7 @@ export function SettingsPanel({
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<dl className="grid gap-3 sm:grid-cols-2 lg:grid-cols-1">
|
<dl className="grid gap-3 sm:grid-cols-2 lg:grid-cols-1">
|
||||||
<div className="rounded-xl border border-border/60 bg-muted/35 p-3">
|
<div className="rounded-[8px] bg-muted p-3 shadow-[inset_0_0_0_1px_rgba(0,0,0,0.05)]">
|
||||||
<dt className="text-xs font-semibold uppercase tracking-[0.18em] text-muted-foreground">
|
<dt className="text-xs font-semibold uppercase tracking-[0.18em] text-muted-foreground">
|
||||||
Direct create preference
|
Direct create preference
|
||||||
</dt>
|
</dt>
|
||||||
@@ -161,7 +161,7 @@ export function SettingsPanel({
|
|||||||
: `${valuePrefix}: off`}
|
: `${valuePrefix}: off`}
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
<div className="rounded-xl border border-border/60 bg-muted/35 p-3">
|
<div className="rounded-[8px] bg-muted p-3 shadow-[inset_0_0_0_1px_rgba(0,0,0,0.05)]">
|
||||||
<dt className="text-xs font-semibold uppercase tracking-[0.18em] text-muted-foreground">
|
<dt className="text-xs font-semibold uppercase tracking-[0.18em] text-muted-foreground">
|
||||||
AI integrations
|
AI integrations
|
||||||
</dt>
|
</dt>
|
||||||
|
|||||||
68
tests/legacy-design-migration.test.ts
Normal file
68
tests/legacy-design-migration.test.ts
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import { describe, expect, test } from "bun:test";
|
||||||
|
import { readFileSync } from "node:fs";
|
||||||
|
|
||||||
|
const read = (path: string) => readFileSync(path, "utf8");
|
||||||
|
|
||||||
|
describe("legacy design migration", () => {
|
||||||
|
test("global styles remove obsolete glass helpers once console surfaces take over", () => {
|
||||||
|
const source = read("src/app/globals.css");
|
||||||
|
|
||||||
|
expect(source).not.toContain(".glass-surface");
|
||||||
|
expect(source).not.toContain(".glass-panel");
|
||||||
|
expect(source).not.toContain(".glass-subtle");
|
||||||
|
expect(source).not.toContain(".glass-card");
|
||||||
|
expect(source).not.toContain(".glass-strong");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("layout metadata and toast surface use redesign language", () => {
|
||||||
|
const layout = read("src/app/layout.tsx");
|
||||||
|
const manifest = read("src/app/manifest.ts");
|
||||||
|
|
||||||
|
expect(layout).not.toContain("Local iCal");
|
||||||
|
expect(layout).not.toContain("editor for calendar events");
|
||||||
|
expect(layout).not.toContain("glass-strong");
|
||||||
|
expect(manifest).not.toContain("local-ical");
|
||||||
|
expect(manifest).not.toContain("Local iCal editor");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("auth screens use console surfaces instead of old glass cards", () => {
|
||||||
|
const signIn = read("src/app/auth/signin/sign-in-form.tsx");
|
||||||
|
const signOut = read("src/app/auth/signout/page.tsx");
|
||||||
|
const errorPage = read("src/app/auth/error/page.tsx");
|
||||||
|
|
||||||
|
expect(signIn).not.toContain("glass-strong");
|
||||||
|
expect(signOut).not.toContain("glass-strong");
|
||||||
|
expect(errorPage).not.toContain("glass-strong");
|
||||||
|
expect(signIn).not.toContain("rounded-2xl");
|
||||||
|
expect(signOut).not.toContain("rounded-2xl");
|
||||||
|
expect(errorPage).not.toContain("rounded-2xl");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("auth and app copy use timeline-first language", () => {
|
||||||
|
const signIn = read("src/app/auth/signin/sign-in-form.tsx");
|
||||||
|
const errorPage = read("src/app/auth/error/page.tsx");
|
||||||
|
const settings = read("src/components/settings-panel.tsx");
|
||||||
|
|
||||||
|
expect(signIn).not.toContain("Local iCal");
|
||||||
|
expect(signIn).not.toContain("event creation");
|
||||||
|
expect(errorPage).not.toContain("Homepage");
|
||||||
|
expect(settings).not.toContain("review modal");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("overlay surfaces use console framing instead of blur-heavy legacy treatments", () => {
|
||||||
|
const autocomplete = read("src/components/location-autocomplete.tsx");
|
||||||
|
const dragDrop = read("src/components/drag-drop-container.tsx");
|
||||||
|
|
||||||
|
expect(autocomplete).not.toContain("backdrop-blur-sm");
|
||||||
|
expect(autocomplete).toContain("rounded-[10px]");
|
||||||
|
expect(dragDrop).not.toContain("rounded-xl");
|
||||||
|
expect(dragDrop).not.toContain("backdrop-blur-sm");
|
||||||
|
expect(dragDrop).toContain("rounded-[10px]");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("settings internal rows drop the old bordered mini-card treatment", () => {
|
||||||
|
const settings = read("src/components/settings-panel.tsx");
|
||||||
|
|
||||||
|
expect(settings).not.toContain("rounded-xl border border-border/60 bg-muted/35");
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user