6.8 KiB
6.8 KiB
Frontend Implementation Notes
Based on analysis of compiled frontend in /frontend folder.
Key Findings from Compiled Code
Tech Stack (Confirmed)
- SvelteKit 2.x with adapter-static
- TailwindCSS + DaisyUI 4.x for styling
- Leaflet for map/canvas
- Cloudflare Turnstile for captcha/bot protection
- No additional state libraries - uses Svelte stores
API Client Pattern
// Found in chunks/1lh-LSvX.js
class ApiClient {
async request(endpoint, options) {
const response = await fetch(`${this.url}${endpoint}`, options);
this.online = true;
return response;
}
}
Endpoints found:
/me- GET user profile/auth/logout- POST logout/me/update- POST update profile/alliance- GET/POST alliance operations/alliance/update-description- POST/alliance/update-headquarters- POST/alliance/invites- GET/alliance/give-admin- POST/alliance/ban- POST/alliance/unban- POST/purchase- POST store purchases/favorite-location- POST/favorite-location/update- POST/moderator/tickets- GET/moderator/severe-open-tickets-count- GET/me/profile-pictures- GET/otp/cooldown,/otp/send,/otp/verify- OTP system (phone verification)
Authentication
- OAuth providers: Google, Twitch
- Auth redirects to:
${API_URL}/auth/{provider}?token={turnstile_token}&r={redirect} - JWT stored in
jcookie (HttpOnly) - Turnstile captcha required before OAuth
Global State (from chunks/1lh-LSvX.js)
let globalState = {
dropletsDialogOpen: false,
muted: false,
language: getLanguage(), // 'en' or 'pt' detected from navigator
captcha: undefined, // Turnstile token
now: Date.now(), // Updates every 500ms
turnstatileLoaded: false
};
setInterval(() => {
globalState.now = Date.now()
}, 500);
Cloudflare Turnstile
- Site key:
0x4AAAAAABpqJe8FO0N84q0F(from constantqt) - Script:
https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit - Required before login/OAuth
Routes (from app.iDaujbEI.js dictionary)
/ - Main canvas (node 2)
/404 - 404 page (node 3)
/join - Join/onboarding (node 4)
/admin - Admin panel (node 5)
/offline - Offline page (node 6)
/payment/success - Payment success (node 7)
/profile-picture - Profile picture selector (node 8)
/terms/privacy - Privacy policy (node 9)
/terms/return - Return policy (node 10)
/terms/terms-of-service - Terms of service (node 11)
/moderation - Moderation panel (node 14)
Styling Patterns
- Base classes:
bg-base-100,bg-base-200,text-base-content - Buttons:
btn,btn-ghost,btn-circle,btn-sm,btn-lg,btn-error - Modals:
modal,modal-box,modal-backdrop - Tabs:
tabs,tabs-border,tab - Loading:
loading loading-spinner loading-md - Tooltips:
tooltip tooltip-bottom - Layout: Uses Tailwind grid/flex extensively
Report/Moderation System
Report reasons (from fZ59cmjx.js):
inappropriate-content- "+18, inappropriate link, highly suggestive content"hate-speech- "Racism, homophobia, hate groups"doxxing- "Released personal information"bot- "Automated painting software"griefing- "Messed up artworks for no reason"other- "Other reason"
Report form endpoint: ${API_URL}/report-user
Timeout endpoint: ${API_URL}/moderator/timeout-user
Ban endpoint: ${API_URL}/admin/ban-user
Internationalization
- Supports English (
en) and Portuguese (pt) minimum - Language detection from
navigator.languagesornavigator.language - Translation functions:
(params, {locale}) => locale === "en" ? englishText : portugueseText
Toast Notifications
- Global
Wobject withW.error(),W.info()methods - Aria-live region:
aria-label="Notifications alt+T"
PWA Features
- Service worker:
/service-worker.js - Install prompt:
window.pwaInstallPrompt - Manifest:
/site.webmanifest
CSP Header
script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval' https://challenges.cloudflare.com blob:
Constants
Nt = "files"- Files base path- Season: Default
s1 - Version displayed as span:
Version: 1759175263375
Implementation Priority
-
Core Setup (DONE)
- Package.json with DaisyUI + Tailwind
- Svelte config
- PostCSS/Tailwind config
-
Next Steps
- API client (
src/lib/api/client.ts) - Global stores (
src/lib/stores/) - i18n utilities (
src/lib/i18n/) - Toast notification system
- Turnstile component
- Layout components
- Auth pages (login with OAuth)
- Main canvas route
- Admin/moderation routes
- API client (
-
File Structure
src/
├── lib/
│ ├── api/
│ │ └── client.ts # API client class
│ ├── stores/
│ │ ├── global.ts # Global state (turnstile, language, etc.)
│ │ ├── user.ts # Current user
│ │ ├── canvas.ts # Canvas state
│ │ └── alliance.ts # Alliance state
│ ├── i18n/
│ │ ├── index.ts # Translation utilities
│ │ ├── en.ts # English translations
│ │ └── pt.ts # Portuguese translations
│ ├── components/
│ │ ├── common/
│ │ │ ├── Button.svelte
│ │ │ ├── Modal.svelte
│ │ │ └── Toast.svelte
│ │ ├── auth/
│ │ │ ├── LoginForm.svelte # OAuth buttons + Turnstile
│ │ │ └── Turnstile.svelte # Cloudflare Turnstile
│ │ ├── canvas/
│ │ │ └── LeafletMap.svelte
│ │ └── layout/
│ │ ├── Header.svelte
│ │ └── Logo.svelte
│ ├── constants/
│ │ ├── colors.ts # Color palette
│ │ └── config.ts # API URLs, etc.
│ └── utils/
│ ├── bitmap.ts # Bitmap helpers
│ ├── charges.ts # Charge calculation
│ └── level.ts # Level calculation
├── routes/
│ ├── +layout.svelte # Root layout
│ ├── +page.svelte # Main canvas
│ ├── admin/
│ │ └── +page.svelte # Admin dashboard
│ ├── moderation/
│ │ └── +page.svelte # Moderation panel
│ └── join/
│ └── +page.svelte # Login/onboarding
└── app.html # HTML template
Notes
- Original frontend uses Svelte 5 runes syntax (
$state,$derived) - We can use Svelte 4 with traditional stores for simplicity
- No additional HTTP library needed - uses native
fetch - Leaflet needs
import 'leaflet/dist/leaflet.css'in layout