Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 39 additions & 61 deletions src/app/create/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
const [content, setContent] = useState("");
const hasDeadline = true; // mandatory 7-day deadline for all storylines

const { state, error, receipt, execute, reset } = usePublish();

Check warning on line 48 in src/app/create/page.tsx

View workflow job for this annotation

GitHub Actions / lint-and-typecheck

'reset' is assigned a value but never used
const { valid, charCount } = validateContentLength(content);
const titleValid = title.trim().length > 0;
const genreValid = genre.length > 0;
Expand All @@ -57,15 +57,10 @@
if (!isConnected) {
return (
<div className="flex min-h-[calc(100vh-2.75rem)] flex-col items-center justify-center gap-4 px-6">
<div className="glow-border rounded-lg border border-border px-8 py-10 text-center">
<p className="text-lg font-bold text-foreground">Begin your story</p>
<p className="mt-2 text-sm text-muted">
Connect your wallet to create a storyline.
</p>
<div className="mt-4">
<ConnectWallet />
</div>
</div>
<p className="text-muted text-sm">
Connect your wallet to create a storyline.
</p>
<ConnectWallet />
</div>
);
}
Expand All @@ -91,29 +86,22 @@

return (
<div className="flex min-h-[calc(100vh-2.75rem)] flex-col items-center justify-center gap-6 px-6">
<div className="glow-border rounded-lg border border-border px-8 py-10 text-center">
<h1 className="text-2xl font-bold text-accent">
Storyline created!
</h1>
<p className="mt-2 text-sm text-muted">
Your story is now live on-chain.
</p>
<div className="mt-6 flex justify-center gap-3">
{newStorylineId != null && (
<Link
href={`/story/${newStorylineId}`}
className="border-accent text-accent hover:bg-accent hover:text-background rounded border px-4 py-2 text-sm transition-colors"
>
View your story
</Link>
)}
<h1 className="text-accent text-2xl font-bold">Storyline created!</h1>
<div className="flex gap-3">
{newStorylineId != null && (
<Link
href="/"
className="border-border text-muted hover:text-foreground rounded border px-4 py-2 text-sm transition-colors"
href={`/story/${newStorylineId}`}
className="border-accent text-accent hover:bg-accent hover:text-background rounded border px-4 py-2 text-sm transition-colors"
>
Go home
View your story
</Link>
</div>
)}
<Link
href="/"
className="border-border text-muted hover:text-foreground rounded border px-4 py-2 text-sm transition-colors"
>
Go home
</Link>
</div>
</div>
);
Expand All @@ -122,16 +110,10 @@
const busy = state !== "idle" && state !== "error";

return (
<div className="animate-in mx-auto max-w-2xl px-6 py-12">
{/* Manuscript header */}
<div className="mb-8">
<h1 className="text-2xl font-bold tracking-tight text-foreground">
<span className="text-accent">New</span> Storyline
</h1>
<p className="mt-1 text-xs text-muted">
Open a fresh manuscript. Your words become tokens.
</p>
</div>
<div className="mx-auto max-w-2xl px-6 py-12">
<h1 className="text-accent text-2xl font-bold tracking-tight">
Create Storyline
</h1>

<form
onSubmit={(e) => {
Expand All @@ -151,25 +133,25 @@
metadata: { genre, language },
});
}}
className="space-y-6"
className="mt-8 space-y-6"
>
{/* Title — large, prominent */}
{/* Title */}
<div>
<label className="mb-2 block text-sm text-foreground">Title</label>
<label className="text-foreground mb-2 block text-sm">Title</label>
<input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
disabled={busy}
placeholder="The title of your story..."
className="w-full rounded border border-border bg-surface px-4 py-3 text-lg font-bold text-foreground placeholder:font-normal placeholder:text-muted/50 focus:border-accent-dim focus:outline-none disabled:opacity-50"
placeholder="Enter storyline title"
className="border-border bg-surface text-foreground placeholder:text-muted w-full rounded border px-3 py-2 text-sm focus:border-accent focus:outline-none disabled:opacity-50"
/>
</div>

{/* Genre + Language */}
<div className="grid grid-cols-2 gap-4">
<div>
<label className="mb-2 block text-sm text-foreground">Genre</label>
<label className="text-foreground mb-2 block text-sm">Genre</label>
<DropdownSelect
value={genre}
onChange={setGenre}
Expand All @@ -179,9 +161,7 @@
/>
</div>
<div>
<label className="mb-2 block text-sm text-foreground">
Language
</label>
<label className="text-foreground mb-2 block text-sm">Language</label>
<DropdownSelect
value={language}
onChange={setLanguage}
Expand All @@ -191,46 +171,44 @@
</div>
</div>

{/* Content — manuscript style */}
{/* Content */}
<div>
<label className="mb-2 block text-sm text-foreground">
<label className="text-foreground mb-2 block text-sm">
Opening Chapter
</label>
<textarea
value={content}
onChange={(e) => setContent(e.target.value)}
disabled={busy}
rows={16}
placeholder="Begin your genesis plot..."
className="manuscript-lines w-full resize-y rounded border border-border bg-surface px-4 py-3 text-sm leading-[1.85] text-foreground placeholder:text-muted/50 focus:border-accent-dim focus:outline-none disabled:opacity-50"
rows={12}
placeholder="Write the genesis plot (500–10,000 characters)"
className="border-border bg-surface text-foreground placeholder:text-muted w-full resize-y rounded border px-3 py-2 text-sm leading-relaxed focus:border-accent focus:outline-none disabled:opacity-50"
/>
<div className="mt-1 flex justify-between text-xs">
<span
className={
content.length > 0 && !valid ? "text-error" : "text-muted"
}
>
{charCount.toLocaleString()} / {MIN_CONTENT_LENGTH.toLocaleString()}
&ndash;
{charCount.toLocaleString()} / {MIN_CONTENT_LENGTH.toLocaleString()}–
{MAX_CONTENT_LENGTH.toLocaleString()} chars
</span>
</div>
</div>

{/* Deadline info */}
<p className="text-xs text-muted">
All storylines have a 7-day deadline — the story sunsets if no new
plot is added within 7 days.
<p className="text-muted text-xs">
All storylines have a 7-day deadline — the story sunsets if no new plot is added within 7 days.
</p>

{/* Status */}
{state === "error" && (
<div className="rounded border border-error/30 px-3 py-2 text-xs text-error">
<div className="border-error/30 text-error rounded border px-3 py-2 text-xs">
{error}
</div>
)}
{busy && (
<div className="glow-border rounded border border-border px-3 py-2 text-xs text-muted">
<div className="border-border text-muted rounded border px-3 py-2 text-xs">
{STATE_LABELS[state]}
</div>
)}
Expand All @@ -239,7 +217,7 @@
<button
type="submit"
disabled={!canSubmit || busy}
className="w-full rounded border border-accent py-3 text-sm font-medium text-accent transition-colors hover:bg-accent hover:text-background disabled:opacity-50"
className="border-accent text-accent hover:bg-accent hover:text-background w-full rounded border py-2.5 text-sm font-medium transition-colors disabled:opacity-50"
>
{busy ? STATE_LABELS[state] : "Publish Storyline"}
</button>
Expand Down
10 changes: 5 additions & 5 deletions src/app/dashboard/reader/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,11 @@ export default function ReaderDashboard() {
const hasPrev = page > 0;

return (
<div className="animate-in mx-auto max-w-3xl px-4 py-12 sm:px-6">
<h1 className="text-2xl font-bold tracking-tight text-foreground">
<span className="text-accent">Reader</span> Dashboard
<div className="mx-auto max-w-2xl px-6 py-12">
<h1 className="text-accent text-2xl font-bold tracking-tight">
Reader Dashboard
</h1>
<p className="mt-2 text-sm text-muted">
<p className="text-muted mt-2 text-sm">
<WriterIdentityClient address={address!} />
</p>

Expand Down Expand Up @@ -169,7 +169,7 @@ export default function ReaderDashboard() {

function DonationRow({ donation, decimals }: { donation: Donation; decimals: number }) {
return (
<div className="flex items-center justify-between rounded-lg border border-border px-3 py-2.5 text-xs transition-colors hover:border-border-subtle">
<div className="border-border flex items-center justify-between rounded border px-3 py-2 text-xs">
<div className="text-muted flex gap-3">
<span>
Story #{donation.storyline_id}
Expand Down
10 changes: 5 additions & 5 deletions src/app/dashboard/writer/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,11 @@ export default function WriterDashboard() {
}

return (
<div className="animate-in mx-auto max-w-3xl px-4 py-12 sm:px-6">
<h1 className="text-2xl font-bold tracking-tight text-foreground">
<span className="text-accent">Writer</span> Dashboard
<div className="mx-auto max-w-2xl px-6 py-12">
<h1 className="text-accent text-2xl font-bold tracking-tight">
Writer Dashboard
</h1>
<p className="mt-2 text-sm text-muted">
<p className="text-muted mt-2 text-sm">
<WriterIdentityClient address={address!} />
{" — "}
{storylines.length}{" "}
Expand Down Expand Up @@ -94,7 +94,7 @@ export default function WriterDashboard() {

function StorylineDetail({ storyline, writerAddress }: { storyline: Storyline; writerAddress: Address }) {
return (
<div className="glow-border rounded-lg border border-border px-4 py-4">
<div className="border-border rounded border px-4 py-4">
<div className="flex items-start justify-between gap-3">
<Link
href={`/story/${storyline.storyline_id}`}
Expand Down
128 changes: 1 addition & 127 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,22 @@
:root {
--bg: #0a0a0a;
--bg-surface: #111111;
--bg-surface-2: #161616;
--text: #e0e0e0;
--text-muted: #737373;
--accent: #00ff88;
--accent-dim: #00cc6a;
--accent-glow: rgba(0, 255, 136, 0.08);
--border: #1e1e1e;
--border-subtle: #181818;
--border: #2a2a2a;
--error: #ff4444;
--glow-sm: 0 0 20px rgba(0, 255, 136, 0.06);
--glow-md: 0 0 40px rgba(0, 255, 136, 0.08);
--glow-lg: 0 0 80px rgba(0, 255, 136, 0.1);
}

@theme inline {
--color-background: var(--bg);
--color-foreground: var(--text);
--color-surface: var(--bg-surface);
--color-surface-2: var(--bg-surface-2);
--color-muted: var(--text-muted);
--color-accent: var(--accent);
--color-accent-dim: var(--accent-dim);
--color-accent-glow: var(--accent-glow);
--color-border: var(--border);
--color-border-subtle: var(--border-subtle);
--color-error: var(--error);
--font-mono: var(--font-geist-mono);
}
Expand Down Expand Up @@ -55,120 +46,3 @@ select {
padding-right: 2.5rem;
}

/* ─── Shelf section ─── */
.shelf-row {
display: flex;
gap: 1rem;
overflow-x: auto;
scroll-snap-type: x mandatory;
scrollbar-width: none;
-ms-overflow-style: none;
padding-bottom: 0.5rem;
}
.shelf-row::-webkit-scrollbar {
display: none;
}
.shelf-row > * {
scroll-snap-align: start;
flex-shrink: 0;
}

/* ─── Book cover card ─── */
.book-card {
position: relative;
display: flex;
flex-direction: column;
justify-content: flex-end;
border-radius: 4px;
overflow: hidden;
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.book-card:hover {
transform: translateY(-4px);
box-shadow: var(--glow-md);
}
.book-card::before {
content: "";
position: absolute;
inset: 0;
opacity: 0.5;
z-index: 0;
transition: opacity 0.2s ease;
}
.book-card:hover::before {
opacity: 0.65;
}
.book-card > * {
position: relative;
z-index: 1;
}

/* ─── Spine edge effect ─── */
.book-spine {
position: relative;
}
.book-spine::before {
content: "";
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 3px;
background: linear-gradient(
180deg,
var(--accent) 0%,
var(--accent-dim) 50%,
transparent 100%
);
opacity: 0.4;
border-radius: 4px 0 0 4px;
}

/* ─── Ambient glow for featured items ─── */
.glow-border {
box-shadow: var(--glow-sm);
border-color: rgba(0, 255, 136, 0.15);
}
.glow-border:hover {
box-shadow: var(--glow-md);
border-color: rgba(0, 255, 136, 0.25);
}

/* ─── Reading area ─── */
.reading-area {
font-size: 0.9375rem;
line-height: 1.85;
letter-spacing: 0.01em;
color: var(--text);
}
.reading-area::first-line {
font-variant: small-caps;
letter-spacing: 0.05em;
}

/* ─── Generative pattern overlay ─── */
.gen-pattern {
background-image:
radial-gradient(circle at 20% 80%, var(--accent-glow) 0%, transparent 50%),
radial-gradient(circle at 80% 20%, rgba(0, 200, 106, 0.04) 0%, transparent 50%);
}

/* ─── Page transition ─── */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
}
.animate-in {
animation: fadeIn 0.3s ease-out;
}

/* ─── Manuscript lines (create page) ─── */
.manuscript-lines {
background-image: repeating-linear-gradient(
transparent,
transparent 1.85rem,
rgba(42, 42, 42, 0.3) 1.85rem,
rgba(42, 42, 42, 0.3) calc(1.85rem + 1px)
);
background-position: 0 0.25rem;
}
Loading
Loading