eslint --fix

This commit is contained in:
Oscar
2026-06-08 15:09:53 +03:00
parent 10d696f4ca
commit b98387ea58
64 changed files with 6070 additions and 2467 deletions

View File

@@ -8,14 +8,15 @@ Project root: `C:\MyApps\dating-app-frontend`
Package manager: **pnpm**
Stack: **Vue 3 (Composition API + `<script setup>`) + Vite + Tauri v2**
The app must work in three contexts simultaneously:
1. Browser (dev/PWA) — desktop viewport
2. Browser — mobile viewport (responsive, ≥ 375 px)
3. Tauri desktop window (Windows / macOS / Linux)
---
All user-facing text (button labels, placeholders, error messages,
toast notifications, empty states, navigation items, form hints,
All user-facing text (button labels, placeholders, error messages,
toast notifications, empty states, navigation items, form hints,
section headings) must be written in Russian.
Brand name, logo, and any decorative/editorial text remain in English.
@@ -32,6 +33,7 @@ Before writing any code, internalize these two skill files in full:
Apply **Impeccable** design principles throughout every component.
Apply **Taste-skill** with these parameters:
- `DESIGN_VARIANCE: 8`
- `MOTION_INTENSITY: 6`
- `VISUAL_DENSITY: 4`
@@ -39,6 +41,7 @@ Apply **Taste-skill** with these parameters:
### Aesthetic Direction
The visual language is **"warm brutalism meets editorial intimacy"**:
- Dark base (`#0d0d0d`) with warm cream (`#f0ebe0`) as the primary text/accent surface
- A single vivid signal color — deep terracotta `#c45c3a` — used sparingly for CTAs, likes, active states
- Typography: pair **`Instrument Serif`** (display, headers, profile names) with **`DM Mono`** (UI labels, metadata, counts). Load both from Google Fonts.
@@ -164,6 +167,7 @@ src/
Implement every endpoint from `src/api/api.ts`. Below is the complete feature map:
### Auth (`/api/v1/auth/`)
- `POST /register` — registration form with phone + password, validation via Vuelidate
- `POST /login` — login form
- `POST /logout` — clear store + redirect
@@ -173,11 +177,13 @@ Implement every endpoint from `src/api/api.ts`. Below is the complete feature ma
Store access token in memory (Pinia), refresh token in `localStorage`. Never store access token in `localStorage`.
### Users (`/api/v1/users/`)
- `GET /me` — populate auth store on app load
- `GET /:id` — view any user (admin use)
- `PATCH /:id/ban` and `/activate` — admin panel actions
### Profiles (`/api/v1/profiles/`)
- `POST /` — profile creation wizard (multi-step: basic info → location → tags → photo)
- `GET /my` — list own profiles in MyProfileView
- `GET /:profileId` — public profile detail page
@@ -185,20 +191,24 @@ Store access token in memory (Pinia), refresh token in `localStorage`. Never sto
- `DELETE /:profileId` — with confirmation modal
### Media (`/api/v1/profiles/:profileId/media/`)
- `POST /upload?type=` — drag-and-drop + file picker; show upload progress bar
- `GET /` — grid gallery with lightbox
- `DELETE /:mediaId` — with optimistic UI removal
### Feed (`/api/v1/feed`)
- Infinite scroll OR card-stack swipe (implement BOTH modes, togglable via UI switch)
- Filter panel: cityId, districtId, ageMin/ageMax, keyword, tagIds (multi-select chips)
- Show "search paused" banner when match limit is exceeded (detect via API response or a dedicated flag)
### Likes (`/api/v1/likes`)
- `POST /` — like/dislike with swipe gesture (GSAP drag) or button
- `GET /matches?profileId=` — matches list with match animation (confetti-lite or editorial flash)
### Chat (`/api/v1/chats`)
- `POST /` — open chat from a match card
- `GET /?profileId=` — chats list; lock icon on inactive chats (only one active at a time)
- `GET /:chatId/messages?profileId=` — message history with virtual scroll
@@ -207,16 +217,19 @@ Store access token in memory (Pinia), refresh token in `localStorage`. Never sto
- Implement **polling** (2 s interval) for new messages; note in code where WebSocket would replace this
### Dates (`/api/v1/dates`)
- `POST /` — proposal form: map picker (Leaflet) for lat/lng, datetime picker, optional statusId
- `GET /?profileId=` — list with status chips
- `PATCH /:id/status?profileId=` — accept / decline / complete actions
- `GET /statuses` — fetch on mount, cache in Pinia
### Reports (`/api/v1/reports`)
- `POST /``ReportModal` triggered from profile or chat bubble context menu
- `GET /` — admin table view with pagination
### Tags, Cities, Greetings
- `GET /tags`, `GET /cities`, `GET /cities/:cityId/districts`, `GET /greetings` — fetch on app init, cache in Pinia
- Admin: create/delete tags, cities, districts, greetings
@@ -225,7 +238,9 @@ Store access token in memory (Pinia), refresh token in `localStorage`. Never sto
## Component Implementation Standards
### FeedCard.vue
The centerpiece. Execute this with exceptional care:
- Full-bleed image background
- Profile name in large Instrument Serif, overlapping bottom of image
- Age, city, tags as DM Mono micro-labels
@@ -235,6 +250,7 @@ The centerpiece. Execute this with exceptional care:
- Tap to expand into ProfileDetailView
### ChatRoomView.vue
- Messages grouped by date separator
- Own messages: right-aligned, cream background
- Partner messages: left-aligned, dark card with subtle border
@@ -245,18 +261,21 @@ The centerpiece. Execute this with exceptional care:
- Input bar: text area auto-grows, attach button opens media type picker
### AppShell.vue
- Desktop: left sidebar (64px collapsed / 240px expanded) + main content area
- Mobile: top header + bottom nav (5 items)
- Tauri: custom titlebar with drag region, traffic lights on macOS (use `data-tauri-drag-region`)
- Grain SVG filter applied as a pseudo-element over the entire shell
### Responsive breakpoints
```scss
$mobile: 375px;
$tablet: 768px;
$desktop: 1024px;
$wide: 1440px;
```
Use `@container` queries inside card components where possible.
---
@@ -285,18 +304,21 @@ Navigation guard: check auth store on every route change. Refresh token silently
## State Management (Pinia)
### `auth.store.ts`
```ts
state: { user, accessToken, profiles, activeProfileId }
actions: login, logout, register, refreshToken, setActiveProfile
```
### `feed.store.ts`
```ts
state: { cards[], filters, page, hasMore, searchPaused }
actions: fetchNextPage, applyFilters, likeCard, dislikeCard
```
### `chat.store.ts`
```ts
state: { chats[], activeChat, messages[], polling: NodeJS.Timer | null }
actions: openChat, closeChat, sendMessage, fetchMessages, startPolling, stopPolling
@@ -316,6 +338,7 @@ actions: openChat, closeChat, sendMessage, fetchMessages, startPolling, stopPoll
## CSS Architecture
`src/styles/main.scss` imports in order:
1. `_variables.scss` — all CSS custom properties
2. `_typography.scss` — font definitions, heading scale
3. `_animations.scss` — keyframes, transition utilities
@@ -324,26 +347,26 @@ actions: openChat, closeChat, sendMessage, fetchMessages, startPolling, stopPoll
```scss
// _variables.scss
:root {
--color-base: #0d0d0d;
--color-surface: #161614;
--color-base: #0d0d0d;
--color-surface: #161614;
--color-surface-2: #1e1e1b;
--color-cream: #f0ebe0;
--color-muted: #6b6860;
--color-signal: #c45c3a;
--color-signal-dim:#7a3822;
--color-border: rgba(240, 235, 224, 0.08);
--color-cream: #f0ebe0;
--color-muted: #6b6860;
--color-signal: #c45c3a;
--color-signal-dim: #7a3822;
--color-border: rgba(240, 235, 224, 0.08);
--font-display: 'Instrument Serif', Georgia, serif;
--font-mono: 'DM Mono', 'Courier New', monospace;
--font-mono: 'DM Mono', 'Courier New', monospace;
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 16px;
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 16px;
--shadow-card: 0 2px 24px rgba(0,0,0,0.6);
--shadow-card: 0 2px 24px rgba(0, 0, 0, 0.6);
--transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
--transition-base: 280ms cubic-bezier(0.4, 0, 0.2, 1);
--transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
--transition-base: 280ms cubic-bezier(0.4, 0, 0.2, 1);
--transition-spring: 420ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
```