34 Commits

Author SHA1 Message Date
jeanGaston abd3daea7e chore: bump version to 1.0.3
Publish Docker image / build-and-push (push) Successful in 4m23s
v1.0.3
2026-07-30 17:35:59 +02:00
jeanGaston 0da6dc7810 fix(prisma): track migration SQL files in git
migration.sql was gitignored, so CI builds a Docker image from a
fresh clone with empty migration directories. prisma migrate deploy
then has nothing to apply, leaving the database schema-less on first
launch (P2021: table does not exist).
2026-07-30 17:32:40 +02:00
jeanGaston d8d152e249 chore: bump version to 1.0.2
Publish Docker image / build-and-push (push) Successful in 4m46s
v1.0.2
2026-07-30 16:40:56 +02:00
jeanGaston 75ea9b7416 fix(docker): fix data volume ownership on fresh bind mounts
/app/data is a bind mount, so the chown baked into the image is
overwritten by the host directory's ownership at runtime. On a fresh
prod deploy Docker creates ./data as root-owned, but the container ran
as the non-root nextjs user, so Prisma couldn't open lovelope.db
("unable to open database file").

Add an entrypoint that starts as root, chowns /app/data, then drops to
nextjs via su-exec before running migrations and starting the server.
2026-07-30 16:40:45 +02:00
jeanGaston cd36fc5723 docs: document the dev/tag release process in GIT_WORKFLOW.md
Spells out the two-channel CI trigger (dev branch for test builds, v*
tags for releases) as an actual step-by-step process: keeping dev in
sync with main/master, bumping package.json, tagging, and the
required Gitea repo secrets/variables.
2026-07-30 16:35:45 +02:00
jeanGaston 3987a4e43e chore: bump version to 1.0.1
Publish Docker image / build-and-push (push) Successful in 3m22s
v1.0.1
2026-07-30 15:47:12 +02:00
jeanGaston 5ca66f3ed7 chore: rename database file from askedout.db to lovelope.db
Publish Docker image / build-and-push (push) Successful in 3m34s
Leftover naming from before the app was renamed to lovelope. Renamed
the local data/askedout.db file to data/lovelope.db to match (data/
is gitignored, so this doesn't touch version control).
2026-07-30 15:46:21 +02:00
jeanGaston c36d146fef chore: bump version to 1.0.0 for first release
Publish Docker image / build-and-push (push) Successful in 3m39s
v1.0.0
2026-07-30 15:28:37 +02:00
jeanGaston 3ac68a88d0 docs: lead Quick start with the published GHCR image
Publish Docker image / build-and-push (push) Successful in 3m31s
Running the app no longer requires cloning the repo: pull the
published ghcr.io image directly via docker-compose. Move the
build-from-source flow (existing docker-compose.yml + Dockerfile) to
a secondary section for contributors.
2026-07-30 12:03:29 +02:00
jeanGaston 94b02198dd ci: build images from a dev branch and release tags, not every commit
Every push to master was triggering a build+push, since that's where
day-to-day commits land. Switch to two deliberate channels instead:
pushing to dev produces a rolling :dev tag for testing, and pushing a
v* tag produces :latest + the version tag for real releases. Plain
commits/merges to master/main no longer build anything on their own.
2026-07-30 12:03:20 +02:00
jeanGaston b6c769eecc chore: remove unused shadcn ui components and their Radix deps
Publish Docker image / build-and-push (push) Successful in 4m14s
badge.tsx, dialog.tsx, and separator.tsx were never imported anywhere
in the app. Drop them along with @radix-ui/react-dialog and
@radix-ui/react-separator, which had no other consumers.
2026-07-30 11:50:47 +02:00
jeanGaston bf8fef9190 ci: push to GHCR from the Gitea workflow instead of a separate one
The Gitea instance's act_runner is the CI that actually executes here;
GitHub Actions on the mirror isn't confirmed to run at all (and a
push-mirror lacking the "workflow" PAT scope can silently drop
.github/workflows changes anyway). Add a GHCR login/push to the
existing .gitea/workflows/docker-publish.yml job instead, so one
build produces tags on both the Gitea registry and ghcr.io. Drop the
now-redundant .github/workflows/docker-publish.yml.

Requires a new repo secret GHCR_TOKEN: a GitHub PAT with write:packages
scope (separate from REGISTRY_TOKEN, which is scoped to the Gitea
registry).
2026-07-30 11:50:38 +02:00
jeanGaston aacd5b890f chore: stop tracking local Claude Code tooling assets
Publish Docker image / build-and-push (push) Successful in 3m27s
.claude/skills/ui-styling was committed by accident in the initial
snapshot (93 files, ~5.7MB of font/skill assets unrelated to the app).
Untrack it and ignore /.claude going forward; files remain on disk.
2026-07-30 11:42:45 +02:00
jeanGaston 8fd2b26d9b ci: add GitHub Actions workflow to publish image to GHCR
Mirrors the existing .gitea/workflows/docker-publish.yml but targets
ghcr.io on the GitHub mirror. Simpler than the Gitea version since the
built-in GITHUB_TOKEN has native package-write rights on GHCR, no PAT
secret needed.
2026-07-30 11:42:23 +02:00
jeanGaston a4d734de76 chore: add MIT license
Restores the LICENSE content from Gitea's auto-generated initial
commit (overwritten by the force-push that unified history with the
pre-existing local project) and declares it in package.json.
2026-07-30 11:42:14 +02:00
jeanGaston 3a859a8060 fix(ci): lowercase image name for registry tag
Publish Docker image / build-and-push (push) Successful in 3m16s
github.repository preserves the owner's case (jeanGaston), but OCI
registries reject uppercase repository names. Compute a lowercased
IMAGE_NAME env var and use it for both tags instead.
2026-07-30 11:20:06 +02:00
jeanGaston b5b6898e47 fix(ci): auth to registry with a PAT instead of the built-in token
Publish Docker image / build-and-push (push) Failing after 11s
The auto-injected GITHUB_TOKEN isn't authorized against this Gitea
instance's container registry (401 unauthorized), so use a repo
secret backed by a personal access token with package scope instead.
2026-07-30 11:16:33 +02:00
jeanGaston b3f59780f2 fix(ci): rename registry variable to avoid reserved GITEA_ prefix
Publish Docker image / build-and-push (push) Failing after 9s
Gitea rejects variable/secret names starting with GITEA_ or GITHUB_
(reserved for system-injected values), which is why GITEA_REGISTRY
couldn't be created in repo settings.
2026-07-30 11:15:16 +02:00
jeanGaston 7bd8d543b1 fix(ci): use ubuntu-latest runner label instead of nonexistent docker label
Publish Docker image / build-and-push (push) Failing after 1m7s
act_runner's default registration only exposes ubuntu-latest (and
similar ubuntu-* labels); "docker" isn't a real label unless a runner
was explicitly configured with it.
2026-07-30 10:58:50 +02:00
jeanGaston 395dcad6be ci: add Gitea Actions workflow to publish Docker image
Publish Docker image / build-and-push (push) Has been cancelled
Builds the existing Dockerfile and pushes it to the Gitea container
registry on pushes to main/master and version tags.
2026-07-30 10:41:36 +02:00
jeanGaston 1b4ddd043a fix(create): surface submit errors and fix keyboard overlap on mobile
The create-proposal submit had no error handling, so failures (e.g.
crypto.subtle unavailable outside a secure context) silently reset the
button with no feedback. Also set interactiveWidget so the mobile
keyboard resizes the layout instead of covering the sticky submit button.
2026-07-30 10:16:56 +02:00
jeanGaston 6ea31e8ac0 feat: allow a single activity proposition and add optional location field
Senders no longer need to fill in two activities to publish; one is
now enough (still capped at 5). Each activity can also specify a
place, which flows into the generated Google Calendar link and .ics
file when the recipient picks a slot.
2026-07-29 20:45:24 +02:00
jeanGaston 80bb4c9474 chore: remove stale *.old.tsx backups and fix Button/Card casing in git
The *.old.tsx files (page.old.tsx, layout.old.tsx, ManageClient.old.tsx,
etc.) were pre-refactor backups left alongside their replacements,
confirmed unreferenced by any import.

Also fixes a latent git-tracking bug: since the very first baseline
commit tracked these two files as Button.tsx/Card.tsx, and Windows'
case-insensitive filesystem means a same-path case change isn't
recorded as a rename by default, git's tree kept the capitalized path
forever even after they were rewritten to shadcn's lowercase
button.tsx/card.tsx content. This surfaced intermittently as a
TS1261 "differs only in casing" build error whenever git re-checked-out
the tree (e.g. after this branch's merge to master rewrote the working
copy back to the capitalized path). Fixed with a two-hop git mv so the
rename is actually recorded.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29 20:32:32 +02:00
jeanGaston 5a054357fc fix(logo): use linear easing between keyframes so motion doesn't stutter
easeInOut was applied per-segment across all 6 keyframe boundaries,
decelerating to zero velocity at each one - technically continuous
but visually reads as discrete steps rather than one fluid motion.
Switched to linear; the non-uniform spacing already baked into the
`times` array (tight around the crossing, wide at the ends) now does
the speed-shaping instead, without ever fully stopping mid-flight.

Verified by sampling translateX every animation frame: previously
would have shown velocity flattening at each keyframe boundary, now
shows a steady ~1px/16ms monotonic decrease start to finish.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29 20:29:07 +02:00
jeanGaston 4e779c847a fix(logo): resolve word superposition and reduce animation cost
The previous commit only masked the emoji row's crossing (via the
white flash timed to their fade). The text row ("love"/"envelope")
still animated opacity down while sitting fully centered on top of
each other, so the two words visibly superposed for a beat with no
flash to hide it there.

Fix applies the same technique to both rows: x and opacity now reach
their end state (centered / invisible) together, so there's no frame
where a glyph is both fully opaque and fully overlapping another.
Verified via a fresh screenshot mid-transition - no double-exposure.

Also addressed reported animation lag: dropped the rotate wobble
(one fewer animated property per element), cut keyframe count 8->7,
shortened 2.4s -> 1.8s, trimmed the flash's blur/spread, and added
willChange hints so all layers are promoted upfront rather than
mid-animation. Playwright rAF sampling over the full animation now
shows a flat 60fps with zero frames slower than 30fps.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29 20:21:08 +02:00
jeanGaston 63796d127e feat(logo): retime LoveFusion merge animation, add Hachi Maru Pop wordmark, emoji favicon
LoveFusion:
- Swapped sides per request: love (was heart) now enters from the
  left, envelope from the right, converging at center.
- Retimed the crossfade so opacity/scale start dropping the instant
  they reach center instead of dwelling there fully-opaque and
  overlapping - the previous timing had a visible window where the
  heart span rendered on top of the envelope span (DOM order stacking)
  before either had faded, which read as a glitch rather than a merge.
- The white flash now ramps up in sync with that fade (bigger too:
  w-8 base, larger blur/spread, peak scale 2.4 vs 1.8) so it's already
  bright enough to mask the crossing before the two glyphs are fully
  gone, then blooms back out into the merged emoji.
- Wordmark text ("love"/"envelope"/"lovelope.app") now renders in
  Hachi Maru Pop (next/font/google), scoped to this component only -
  the app's Bricolage Grotesque display font elsewhere is untouched.

Favicon:
- Replaced the envelope-outline SVG mark with 💌 on the same pink
  rounded-square backdrop, moved from public/icon.svg to
  src/app/icon.svg (Next's file-based icon convention, so it's
  auto-linked as <link rel="icon">). Tried next/og's ImageResponse
  first but it hit a Windows-specific "Invalid URL" bug in the
  Next 14.2.35-bundled @vercel/og font loader; a static SVG sidesteps
  it entirely and is simpler besides. manifest.webmanifest already
  pointed at /icon.svg so no change needed there - same URL, new
  source file.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29 20:14:02 +02:00
jeanGaston d8a8042a48 refactor(ui): swap Inter/Poppins for self-hosted Bricolage Grotesque + Instrument Sans
Pulled from the ui-styling skill's canvas-fonts pack (both OFL-licensed,
license files kept alongside in src/fonts/) instead of next/font/google,
per explicit choice to use the skill's bundled assets rather than a
Google Fonts pairing.

- Display (headings): Bricolage Grotesque (Regular + Bold) - warmer,
  more distinctive than Poppins while keeping the same bold/rounded
  energy for the "adorable" branding.
- Body: Instrument Sans (Regular/Italic/Bold/BoldItalic) - clean at
  form-field sizes.
- CSS variables renamed --font-inter/--font-poppins -> --font-sans/
  --font-display (decoupled from the specific font choice); updated
  in tailwind.config.ts and layout.tsx. Removed the redundant static
  fallback declarations in globals.css - next/font's `variable`
  option already injects these via the <html> className.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29 20:00:14 +02:00
jeanGaston b5902e3cac refactor(ui): mobile-first viewport fixes on ProposalPageClient
Swaps min-h-screen -> min-h-[100dvh] across all five screen states
(expired, key-missing, loading, answered, reveal) so mobile browser
chrome (address bar) doesn't clip full-bleed gradient screens.
Bottom padding on the main content column now respects
env(safe-area-inset-bottom) for iOS home-indicator devices.

This page intentionally keeps its own theme.* driven styling
(cardBg/cardBorder/textPrimary/buttonGradient from lib/themes.ts)
rather than shadcn Card/Button — those tokens ARE the per-proposal
color set this refactor was told to preserve exactly, so wrapping
them in the shadcn primitives would fight the dynamic theming
instead of composing with it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29 19:48:37 +02:00
jeanGaston 56b3e6c131 refactor(ui): rebuild ProposalForm, CreateClient, ManageClient on shadcn/ui
ProposalForm:
- Step tabs -> Radix Tabs (roving tabindex, arrow-key nav, proper
  ARIA) driven by the same `step` state as before.
- Evasive-no toggle -> Switch, wrapped in a <label> so the whole row
  (not just the small control) is tappable.
- All raw <input>/<textarea> -> Input/Textarea; buttonVariants
  'primary' -> 'default' to match the new variant names.
- New StepActions wrapper makes Back/Next/Publish sticky to the
  viewport bottom on mobile (safe-area aware) so the wizard never
  requires scrolling to find the next action; reverts to normal
  inline flow at sm+.

CreateClient / ManageClient:
- Card/Button/Input swapped to shadcn equivalents.
- Copy-link feedback moved from a per-button `copied` boolean +
  setTimeout to a single sonner toast call, removing the duplicated
  state pattern.
- ManageClient's delete confirmation moved from window.confirm() to
  an AlertDialog, matching the skill's accessible-primitives guidance
  and giving it proper focus trapping on mobile.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29 19:47:02 +02:00
jeanGaston 5f736525fb refactor(ui): mobile-first pass on shared chrome + shadcn Field wrapper
- Field.tsx re-added composing shadcn Label (no built-in equivalent
  in this CLI generation).
- Bumped Input/Textarea to h-12/rounded-xl/px-4 (44px+ touch targets,
  matches the app's existing rounded, roomy input style).
- Card padding restored to the old flat p-5 sm:p-6 default so most
  call sites (`<Card>children</Card>`) don't need CardContent
  wrapping; CardHeader/Content/Footer still exported for the few
  structured cards.
- Swapped literal pink-500/gray-100 focus/border colors for
  text-primary / border-border / ring-ring tokens in Footer and
  CalendarButtons so brand color flows from the CSS vars.
- min-h-screen -> min-h-[100dvh] on full-bleed screens (home,
  create, not-found) so mobile browser chrome doesn't clip content.
- Responsive type scale (text-4xl sm:text-5xl md:text-6xl, etc.)
  instead of a single jump at md:, so headings don't overflow on
  narrow phones.
- Root layout now mounts <Toaster> and uses bg-background/
  text-foreground (background token matches the previous gray-50).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29 19:42:48 +02:00
jeanGaston 9976542438 refactor: install shadcn/ui primitives (button, card, input, textarea, label, tabs, switch, dialog, alert-dialog, badge, separator, sonner)
Pinned the CLI to shadcn@2.3.0 rather than the latest (4.16.0): the
latest generation targets Tailwind v4-only syntax (bare-value parens
like `gap-(--card-spacing)`, the `in-*` variant, `--spacing()`) that
silently fails to compile under this project's Tailwind v3.4.6.
2.3.0 is the last CLI generation producing classic hsl(var(--x))
v3-compatible component output.

Swapped @radix-ui/react-icons for the already-installed lucide-react
in dialog.tsx, and dropped sonner's next-themes dependency (the app
has no dark-mode toggle, so Toaster is hardcoded to theme="light").

Old custom src/components/ui/Button.tsx, Card.tsx, and Field.tsx are
removed here; call sites are updated in the following commits.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29 19:39:41 +02:00
jeanGaston d01311569f refactor: scaffold shadcn/ui on the existing Tailwind v3 setup
Adds components.json, cn() util, Radix + cva/clsx/tailwind-merge/
lucide-react/sonner deps, and CSS-variable color tokens mapped onto
the brand's existing pink-500 primary (#ec4899) and neutral grays.

`shadcn init` defaulted to Tailwind v4-style output (oklch colors,
`@theme`-driven CSS, `tw-animate-css`) without updating
tailwind.config.ts, which would not have compiled against the
project's pinned Tailwind v3. Hand-wrote the classic v3 integration
instead (HSL vars + tailwind.config.ts color/radius mapping +
tailwindcss-animate) rather than pull in an unplanned Tailwind
major-version migration.

Also drops the sunset/neon/pastel raw color scales from
tailwind.config.ts: grep confirmed no class ever referenced them,
they were leftover from before lib/themes.ts.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29 19:34:48 +02:00
jeanGaston df4e254e9e docs: add GIT_WORKFLOW.md branching and commit policy
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29 19:29:15 +02:00
jeanGaston 1064a0362b Initial commit: baseline snapshot before UI/UX refactor
Captures the existing lovelope.app codebase (Next.js App Router,
custom Tailwind components, Prisma) as a rollback point prior to
adopting shadcn/ui and a mobile-first redesign.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29 19:27:12 +02:00