Commit Graph

50 Commits

Author SHA1 Message Date
e2abb0794a style: use text-foreground color for burger menu lines
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 19:18:39 +01:00
2644e033b4 style: remove underline from logout button hover
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 19:16:43 +01:00
ee1cea6d01 style: match logout button hover to other icon buttons, destructive color on hover
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 19:16:04 +01:00
1496399b96 style: remove header border, keep glow shadow only
All checks were successful
Build and Push Frontend Image / build (push) Successful in 1m15s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 19:09:55 +01:00
075f64f4e3 style: single crisp primary border with soft glow on header
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 19:06:43 +01:00
8c6c98d612 style: edgy glowing bottom border on header
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 19:05:41 +01:00
28be084781 style: transparent header, no scroll tracking
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 19:04:25 +01:00
21b8d2c223 feat: transparent header at top, solid on scroll
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 19:03:39 +01:00
b315062d43 revert: restore original header styling
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 19:02:42 +01:00
8508e1f6e9 style: reduce header background opacity for softer appearance
All checks were successful
Build and Push Frontend Image / build (push) Successful in 1m13s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 17:39:47 +01:00
af4a11b73c style: apply prettier formatting to svelte and ts files
Some checks failed
Build and Push Backend Image / build (push) Successful in 1m3s
Build and Push Frontend Image / build (push) Has been cancelled
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 11:49:43 +01:00
422f97417e fix: resolve vite-plugin-svelte warnings
- image-viewer: replace backdrop div with button for a11y
- file-drop-zone: wrap prop check in \$effect to avoid state_referenced_locally
- about: use \$derived for stats array
- magazine: use \$derived for featuredArticle
- play: add role/keyboard support to seek bar slider; fix \$state on SvelteMap in device-mapping-dialog
- admin/videos/[id]: add <track kind="captions"> to video element

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 11:41:58 +01:00
2980c0b637 fix: remove brand name text from mobile flyout header
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 10:42:22 +01:00
e236ced12a refactor: replace all explicit any types with proper TypeScript types
Backend resolvers: typed enrichArticle/enrichVideo/enrichModel with DB
and $inferSelect types, SQL<unknown>[] for conditions arrays, proper
enum casts for status/role fields, $inferInsert for .set() updates,
typed raw SQL result rows in gamification, ReplyLike interface for
ctx.reply in auth. Frontend: typed catch blocks with Error/interface
casts, isActiveLink param, adminGetUser response, tags filter callback.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 19:25:04 +01:00
8313664d70 chore: fix all lint errors and format codebase
- Remove unused `or` import in comments resolver
- Remove unused `users` import in recordings resolver
- Add index keys to pagination {#each} loops in videos, models, magazine
- Remove stale svelte-ignore comment in header (a11y warnings no longer fired)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 19:06:57 +01:00
cb7720ca9c fix: smooth hero-to-content transition with transparent gradient fade
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 18:47:24 +01:00
1a2fab3e37 refactor: UX and styling improvements across frontend
- Fix login spinner (isLoading never set to true before await)
- Extract PageHero component, replace copy-pasted hero sections on videos/models/tags pages
- Replace inline plasma blobs with SexyBackground on videos/models/tags pages
- Make video/model/tag cards fully clickable (wrap in <a>), remove redundant Watch/View Profile buttons
- Convert inner overlay anchors to divs to avoid nested <a> elements
- Fix home page model avatar preset: mini → thumbnail (correct size for 96px display)
- Reduce home hero height: min-h-screen → min-h-[70vh]
- Remove dead hideName prop from Logo, simplify component
- Add brand name to mobile flyout panel header with gradient styling
- Remove dead _relatedVideos array, isBookmarked state, _handleBookmark from video detail page
- Clean up commented-out code blocks in video detail and models pages
- Note: tag card inner tag links converted to spans to avoid nested anchors

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 18:33:32 +01:00
a050e886cb feat: replace slide-to-logout with avatar + name + logout button in header
Removes the drag-to-logout widget in favour of a clean inline layout:
- Desktop: avatar (links to /me), artist name, and a logout icon button
- Mobile flyout: user card with avatar, name, email, and logout button

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 18:12:18 +01:00
519fd45d8d feat: rebrand to Sexy, restyle logo with gradient icon and updated assets
- Rename brand from SexyArt to Sexy throughout i18n locale
- Apply primary→accent gradient to SVG icon stroke
- Remove brand name text from logo, icon-only display
- Switch logo font to Noto Sans bold (default), drop Dancing Script
- Update favicons, app icons, webmanifest, and add logo.svg

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 18:04:14 +01:00
798495c3d6 fix: remove archived badge from recording card and i18n
All checks were successful
Build and Push Backend Image / build (push) Successful in 17s
Build and Push Frontend Image / build (push) Successful in 4m19s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 11:57:40 +01:00
f2871b98db style: apply prettier formatting across frontend components and pages
Some checks failed
Build and Push Backend Image / build (push) Successful in 1m4s
Build and Push Frontend Image / build (push) Has been cancelled
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 10:49:35 +01:00
c90c09da9a chore: cleanup
All checks were successful
Build and Push Backend Image / build (push) Successful in 49s
Build and Push Frontend Image / build (push) Successful in 4m18s
2026-03-06 19:25:07 +01:00
aed7b4a16f fix: restore admin role in User type, use image logo
- Add "admin" back to User.role union to fix backend TS build
- Replace SVG PeonyIcon with logo.png image in Logo component

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 18:04:49 +01:00
19d29cbfc6 fix: replace flyout profile card with logout slider, i18n auth errors
- Replace static account card in mobile flyout with swipe-to-logout widget
- Remove redundant logout button from flyout bottom
- Make LogoutButton full-width via class prop and dynamic maxSlide
- Extract clean GraphQL error messages instead of raw JSON in all auth forms
- Add i18n keys for known backend errors (invalid credentials, email taken, invalid token)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 17:26:14 +01:00
609f116b5d feat: replace native date inputs with shadcn date picker
Add calendar + popover components and a custom DateTimePicker wrapper.
Video forms use date-only; article forms include a time picker.
Also add video player preview to the video edit form.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 17:03:35 +01:00
e943876e70 fix: prevent age verification dialog flicker on page load
Initialize isOpen as false and only open in onMount if not yet verified,
instead of opening immediately and closing after localStorage check.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 16:52:48 +01:00
95fd9f48fc refactor: align article author with VideoModel, streamline selects, fix flyout inert
- Remove ArticleAuthor type; article.author now reuses VideoModel (id, artist_name, slug, avatar)
- updateArticle accepts authorId; author selectable in admin article edit page
- Article edit: single Select with bind:value + $derived selectedAuthor display
- Video edit: replace pill toggles with Select type="multiple" bind:value for models
- Video table: replace inline badge spans with Badge component
- Magazine: display artist_name throughout, author bio links to model profile
- Fix flyout aria-hidden warning: replace with inert attribute

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 16:31:41 +01:00
670c18bcb7 feat: refactor role system to is_admin flag, add Badge component, fix native dialogs
- Separate admin identity from role: viewer|model + is_admin boolean flag
- DB migration 0001_is_admin: adds column, migrates former admin role users
- Update ACL helpers, auth session, GraphQL types and all resolvers
- Admin layout guard and header links check is_admin instead of role
- Admin users table: show Admin badge next to name, remove admin from role select
- Admin user edit page: is_admin checkbox toggle
- Install shadcn Badge component; use in admin users table
- Fix duplicate photo keys in adminGetUser resolver
- Replace confirm() in /me recordings with Dialog component

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 16:14:00 +01:00
b71d7dc559 refactor: remove duplicate utils/utils.ts, consolidate into utils.ts
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 13:31:35 +01:00
f764e27d59 fix: shrink flyout account card, remove online indicator
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 13:29:33 +01:00
d7eb2acc6c fix: match mobile flyout header height to main header (h-16)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 13:27:31 +01:00
ad7ceee5f8 fix: resolve lint errors from ACL/admin implementation
- Remove unused requireOwnerOrAdmin import from videos.ts
- Remove unused requireAuth import from users.ts
- Remove unused GraphQLError import from articles.ts
- Replace URLSearchParams with SvelteURLSearchParams in admin users page
- Apply prettier formatting to all changed files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 12:35:11 +01:00
c1770ab9c9 feat: role-based ACL + admin management UI
Backend:
- Add acl.ts with requireAuth/requireRole/requireOwnerOrAdmin helpers
- Gate premium videos from unauthenticated users in videos query/resolver
- Fix updateVideoPlay to verify ownership before updating
- Add admin mutations: adminListUsers, adminUpdateUser, adminDeleteUser
- Add admin mutations: createVideo, updateVideo, deleteVideo, setVideoModels, adminListVideos
- Add admin mutations: createArticle, updateArticle, deleteArticle, adminListArticles
- Add deleteComment mutation (owner or admin only)
- Add AdminUserListType to GraphQL types
- Fix featured filter on articles query

Frontend:
- Install marked for markdown rendering
- Add /admin/* section with sidebar layout and admin-only guard
- Admin users page: paginated table with search, role filter, inline role change, delete
- Admin videos pages: list, create form, edit form with file upload and model assignment
- Admin articles pages: list, create form, edit form with split-pane markdown editor
- Add admin nav link in header (desktop + mobile) for admin users
- Render article content through marked in magazine detail page
- Add all admin GraphQL service functions to services.ts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 12:31:33 +01:00
e200514347 refactor: move flyout to left side, restore logo, remove close button
Some checks failed
Build and Push Backend Image / build (push) Failing after 47s
Build and Push Frontend Image / build (push) Successful in 5m13s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 12:34:57 +01:00
d7057c3681 refactor: improve mobile flyout header
- Replace inline mobile dropdown with sliding flyout panel from right
- Hide burger menu on lg breakpoint, desktop auth buttons use hidden lg:flex
- Add backdrop overlay with opacity transition
- Remove logo from flyout panel header
- Fix backdrop div accessibility with role="presentation"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 11:44:23 +01:00
97269788ee feat: add shared @sexy.pivoine.art/types package and fix type safety across frontend/backend
- Create packages/types with shared TypeScript domain model interfaces (User, Video, Model, Article, Comment, Recording, etc.)
- Wire both frontend and backend packages to use @sexy.pivoine.art/types via workspace:*
- Update backend Pothos objectRef types to use shared interfaces instead of inline types
- Update frontend $lib/types.ts to re-export from shared package
- Fix all type errors introduced by more accurate nullable types (avatar/banner as string|null UUIDs, author nullable, events/device_info as object[])
- Add artist_name to comment user select in backend resolver
- Widen utility function signatures (getAssetUrl, getUserInitials, calcReadingTime) to accept null/undefined

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 11:01:11 +01:00
fd4050a49f refactor: remove directus.ts shim, import directly from api
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 10:19:05 +01:00
efc7624ba3 style: apply prettier formatting to all files
All checks were successful
Build and Push Backend Image / build (push) Successful in 46s
Build and Push Frontend Image / build (push) Successful in 5m12s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 22:27:54 +01:00
18116072c9 feat: add formidable ESLint + Prettier linting setup
Some checks failed
Build and Push Backend Image / build (push) Successful in 47s
Build and Push Frontend Image / build (push) Has been cancelled
- Root-level eslint.config.js (flat config): typescript-eslint,
  eslint-plugin-svelte, eslint-config-prettier, @eslint/js
- Root-level prettier.config.js with prettier-plugin-svelte
- svelte-check added to frontend for Svelte/TS type checking
- lint, lint:fix, format, format:check, check scripts in root
  and both packages
- All 60 lint errors fixed across backend and frontend:
  - Consistent type imports
  - Removed unused imports/variables
  - Added keys to all {#each} blocks for Svelte performance
  - Replaced mutable Set/Map with SvelteSet/SvelteMap
  - Fixed useless assignments and empty catch blocks
- 64 remaining warnings are intentional any usages in the
  Pothos/Drizzle GraphQL resolver layer

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 22:24:55 +01:00
de16b64255 fix: use env object from \$env/dynamic/public instead of named imports
All checks were successful
Build and Push Docker Image to Gitea / build-and-push (push) Successful in 5m13s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 17:19:26 +01:00
865787fb45 feat: switch PUBLIC_API_URL and PUBLIC_URL to dynamic env for runtime configurability
Some checks failed
Build and Push Docker Image to Gitea / build-and-push (push) Failing after 3m3s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 17:01:37 +01:00
c85fa7798e chore: remove Letterspace newsletter integration and all LETTERSPACE_* variables 2026-02-21 10:56:43 +01:00
6ea4ed1933 feat: upgrade buttplug package to protocol v4 and WASM v10
All checks were successful
Build and Push Docker Image to Gitea / build-and-push (push) Successful in 7m30s
Upgrade the buttplug TypeScript client from class-based v3 protocol to
interface-based v4 protocol, and the Rust/WASM server from the monolithic
buttplug 9.0.9 crate to the split buttplug_core/buttplug_server/
buttplug_server_device_config 10.0.0 crates.

TypeScript changes:
- Messages are now plain interfaces with msgId()/setMsgId() helpers
- ActuatorType → OutputType, SensorType → InputType
- ScalarCmd/RotateCmd/LinearCmd → OutputCmd, SensorReadCmd → InputCmd
- Client.ts → ButtplugClient.ts, new DeviceCommand/DeviceFeature files
- Devices getter returns Map instead of array
- Removed class-transformer/reflect-metadata dependencies

Rust/WASM changes:
- Split imports across buttplug_core, buttplug_server, buttplug_server_device_config
- Removed ButtplugServerDowngradeWrapper (use ButtplugServer directly)
- Replaced ButtplugFuture/ButtplugFutureStateShared with tokio::sync::oneshot
- Updated Hardware::new for new 6-arg signature
- Uses git fork (valknarthing/buttplug) to fix missing wasm deps in buttplug_core

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 14:46:47 +01:00
756d767d59 fix: align sharing button height with like button
Some checks failed
Build and Push Docker Image to Gitea / build-and-push (push) Has been cancelled
Remove size="sm" from SharingPopupButton to use default button height (h-9)
instead of small size (h-8), ensuring consistent button heights across all
action buttons on video, model, and article pages.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 19:20:30 +01:00
Valknar XXX
6232cc58f0 fix: add null safety to logout button component
Added null checks for user.name property to prevent SSR errors when
the property is undefined. Made name and avatar properties optional
in the User interface and added fallbacks to use email when name is
not available.

Fixes TypeError: Cannot read properties of undefined (reading 'split')
that was occurring during server-side rendering.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-28 11:21:42 +01:00
Valknar XXX
a252da6d9d fix: recording save functionality and authentication
- Fix artist_name null handling in header component with email fallback
- Fix authentication in recording endpoints to use req.accountability
- Change duration field type from integer to double precision for millisecond precision
- Add createRecording service function with proper authentication
- Update play page to use fetch API for recording saves

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-28 05:16:36 +01:00
Valknar XXX
5bd2d9c215 fix: handle undefined user name in UI components
- Added null check in getUserInitials function to return "??" for undefined names
- Fixed logout button to handle undefined user.name when displaying first name
- Prevents 500 errors when rendering components for users without names

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-28 04:48:41 +01:00
Valknar XXX
aa4e376490 feat: add buttplug device recording feature (Phase 1 & 2)
Implemented complete infrastructure for recording, saving, and managing
buttplug device patterns with precise event timing.

**Phase 1: Backend & Infrastructure**
- Added Directus schema for sexy_recordings collection with all fields
  (id, status, user_created, title, description, slug, duration, events,
  device_info, tags, linked_video, featured, public)
- Created REST API endpoints in bundle extension:
  * GET /sexy/recordings - list user recordings with filtering
  * GET /sexy/recordings/:id - get single recording
  * POST /sexy/recordings - create new recording with validation
  * PATCH /sexy/recordings/:id - update recording (owner only)
  * DELETE /sexy/recordings/:id - soft delete by archiving
- Added TypeScript types: RecordedEvent, DeviceInfo, Recording
- Created frontend services: getRecordings(), deleteRecording()
- Built RecordingCard component with stats, device info, and actions
- Added Recordings tab to /me dashboard page with grid layout
- Added i18n translations for recordings UI

**Phase 2: Recording Capture**
- Implemented recording state management in /play page
- Added Start/Stop Recording buttons with visual indicators
- Capture device events with precise timestamps during recording
- Normalize actuator values (0-100) for cross-device compatibility
- Created RecordingSaveDialog component with:
  * Recording stats display (duration, events, devices)
  * Form inputs (title, description, tags)
  * Device information preview
- Integrated save recording API call from play page
- Added success/error toast notifications
- Automatic event filtering during recording

**Technical Details**
- Events stored as JSON array with timestamp, deviceIndex, deviceName,
  actuatorIndex, actuatorType, and normalized value
- Device metadata includes name, index, and capability list
- Slug auto-generated from title for SEO-friendly URLs
- Status workflow: draft → published → archived
- Permission checks: users can only access own recordings or public ones
- Frontend uses performance.now() for millisecond precision timing

**User Flow**
1. User scans and connects devices on /play page
2. Clicks "Start Recording" to begin capturing events
3. Manipulates device sliders - all changes are recorded
4. Clicks "Stop Recording" to end capture
5. Save dialog appears with recording preview and form
6. User enters title, description, tags and saves
7. Recording appears in dashboard /me Recordings tab
8. Can play back, edit, or delete recordings

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-28 04:05:09 +01:00
Valknar XXX
29e8808be1 fix: PUBLIC_URL usage and add ffmpeg 2025-10-25 22:38:45 +02:00
Valknar XXX
be0fc11a5c A new start 2025-10-25 22:04:41 +02:00