mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 21:21:10 +02:00
✨ feat(figgos): scaffold SvelteKit web app with neo-brutalist theme
SvelteKit 2 + Svelte 5 + Tailwind CSS 4 on port 5196. Create and Collection pages matching the mobile neo-brutalist design system. Follows monorepo patterns (adapter-node, shared-vite-config, type-check). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
1c24ad9d5c
commit
95dd1d3e9e
16 changed files with 1003 additions and 139 deletions
|
|
@ -8,7 +8,8 @@ A collectible figure game where users create and collect AI-generated fantasy fi
|
|||
apps/figgos/
|
||||
├── apps/
|
||||
│ ├── backend/ # @figgos/backend - NestJS API (port 3025)
|
||||
│ └── mobile/ # @figgos/mobile - Expo React Native app
|
||||
│ ├── mobile/ # @figgos/mobile - Expo React Native app
|
||||
│ └── web/ # @figgos/web - SvelteKit web app (port 5196)
|
||||
├── packages/
|
||||
│ └── shared/ # @figgos/shared - Shared types & constants
|
||||
└── package.json
|
||||
|
|
@ -20,6 +21,7 @@ apps/figgos/
|
|||
|
||||
```bash
|
||||
pnpm dev:figgos:mobile # Start mobile app
|
||||
pnpm dev:figgos:web # Start web app (port 5196)
|
||||
pnpm dev:figgos:backend # Start backend
|
||||
pnpm dev:figgos:app # Start web + backend together
|
||||
pnpm dev:figgos:full # Start with auth + auto DB setup
|
||||
|
|
@ -39,6 +41,7 @@ npx expo start --clear # Start with clean cache
|
|||
## Technology Stack
|
||||
|
||||
- **Mobile**: React Native 0.81 + Expo SDK 54, NativeWind 4, Expo Router
|
||||
- **Web**: SvelteKit 2.x, Svelte 5 (runes mode), Tailwind CSS 4
|
||||
- **Backend**: NestJS 10, Drizzle ORM, PostgreSQL
|
||||
- **Auth**: Mana Core Auth (JWT via @manacore/shared-nestjs-auth)
|
||||
- **Shared**: `@figgos/shared` — all types inlined in `src/index.ts` (Node v24 ESM compat)
|
||||
|
|
@ -50,7 +53,7 @@ npx expo start --clear # Start with clean cache
|
|||
| App | Port |
|
||||
|-----|------|
|
||||
| Backend | 3025 |
|
||||
| Web (planned) | 5181 |
|
||||
| Web | 5196 |
|
||||
|
||||
## Environment Variables
|
||||
|
||||
|
|
|
|||
23
apps/figgos/apps/web/.gitignore
vendored
Normal file
23
apps/figgos/apps/web/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
node_modules
|
||||
|
||||
# Output
|
||||
.output
|
||||
.vercel
|
||||
.netlify
|
||||
.wrangler
|
||||
/.svelte-kit
|
||||
/build
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Env
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
!.env.test
|
||||
|
||||
# Vite
|
||||
vite.config.js.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
||||
30
apps/figgos/apps/web/package.json
Normal file
30
apps/figgos/apps/web/package.json
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"name": "@figgos/web",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"prepare": "svelte-kit sync || echo ''",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"type-check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@manacore/shared-vite-config": "workspace:*",
|
||||
"@sveltejs/adapter-node": "^5.4.0",
|
||||
"@sveltejs/kit": "^2.50.2",
|
||||
"@sveltejs/vite-plugin-svelte": "^6.2.4",
|
||||
"@tailwindcss/vite": "^4.1.7",
|
||||
"svelte": "^5.49.2",
|
||||
"svelte-check": "^4.3.6",
|
||||
"tailwindcss": "^4.1.17",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^7.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@figgos/shared": "workspace:*"
|
||||
}
|
||||
}
|
||||
82
apps/figgos/apps/web/src/app.css
Normal file
82
apps/figgos/apps/web/src/app.css
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
@import "tailwindcss";
|
||||
|
||||
/* =============================================================================
|
||||
Figgos Design System — Neo-Brutalist Game UI (Tailwind v4)
|
||||
|
||||
Color strategy:
|
||||
- Primary: Electric Yellow — bold, in-your-face, action
|
||||
- Secondary: Hot Pink — accents, badges, highlights
|
||||
- Surface: Deep navy — dark but warm enough for contrast
|
||||
- Borders: Thick, visible, part of the design language
|
||||
- Shadows: Hard offset layers, not soft blurs
|
||||
============================================================================= */
|
||||
|
||||
@theme {
|
||||
--color-background: rgb(15, 15, 30);
|
||||
--color-foreground: rgb(245, 245, 245);
|
||||
|
||||
--color-surface: rgb(26, 26, 53);
|
||||
--color-surface-elevated: rgb(35, 35, 65);
|
||||
|
||||
--color-muted: rgb(55, 55, 80);
|
||||
--color-muted-foreground: rgb(136, 136, 170);
|
||||
|
||||
/* Electric Yellow */
|
||||
--color-primary: rgb(255, 204, 0);
|
||||
--color-primary-foreground: rgb(15, 15, 30);
|
||||
--color-primary-dark: rgb(179, 143, 0);
|
||||
|
||||
/* Hot Pink */
|
||||
--color-secondary: rgb(255, 51, 102);
|
||||
--color-secondary-foreground: rgb(255, 255, 255);
|
||||
--color-secondary-dark: rgb(179, 35, 74);
|
||||
|
||||
/* Teal */
|
||||
--color-accent: rgb(0, 210, 170);
|
||||
--color-accent-foreground: rgb(15, 15, 30);
|
||||
--color-accent-dark: rgb(0, 150, 120);
|
||||
|
||||
--color-destructive: rgb(255, 80, 80);
|
||||
--color-destructive-foreground: rgb(15, 15, 30);
|
||||
|
||||
--color-border: rgb(255, 204, 0);
|
||||
--color-border-muted: rgb(50, 50, 80);
|
||||
|
||||
--color-input: rgb(20, 20, 40);
|
||||
--color-ring: rgb(255, 204, 0);
|
||||
|
||||
/* Rarity */
|
||||
--color-rarity-common: rgb(136, 136, 170);
|
||||
--color-rarity-common-foreground: rgb(245, 245, 245);
|
||||
--color-rarity-rare: rgb(100, 180, 255);
|
||||
--color-rarity-rare-foreground: rgb(15, 15, 30);
|
||||
--color-rarity-epic: rgb(180, 130, 255);
|
||||
--color-rarity-epic-foreground: rgb(15, 15, 30);
|
||||
--color-rarity-legendary: rgb(255, 185, 30);
|
||||
--color-rarity-legendary-foreground: rgb(25, 25, 25);
|
||||
}
|
||||
|
||||
/* Base */
|
||||
body {
|
||||
background-color: var(--color-background);
|
||||
color: var(--color-foreground);
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
min-height: 100dvh;
|
||||
}
|
||||
|
||||
/* Neo-Brutalist utilities */
|
||||
.brutal-shadow {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.brutal-shadow::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 5px;
|
||||
right: -5px;
|
||||
bottom: -5px;
|
||||
background-color: var(--color-primary-dark);
|
||||
border-radius: inherit;
|
||||
z-index: -1;
|
||||
}
|
||||
13
apps/figgos/apps/web/src/app.d.ts
vendored
Normal file
13
apps/figgos/apps/web/src/app.d.ts
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// See https://svelte.dev/docs/kit/types#app.d.ts
|
||||
// for information about these interfaces
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface PageState {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
12
apps/figgos/apps/web/src/app.html
Normal file
12
apps/figgos/apps/web/src/app.html
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
1
apps/figgos/apps/web/src/lib/assets/favicon.svg
Normal file
1
apps/figgos/apps/web/src/lib/assets/favicon.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="107" height="128" viewBox="0 0 107 128"><title>svelte-logo</title><path d="M94.157 22.819c-10.4-14.885-30.94-19.297-45.792-9.835L22.282 29.608A29.92 29.92 0 0 0 8.764 49.65a31.5 31.5 0 0 0 3.108 20.231 30 30 0 0 0-4.477 11.183 31.9 31.9 0 0 0 5.448 24.116c10.402 14.887 30.942 19.297 45.791 9.835l26.083-16.624A29.92 29.92 0 0 0 98.235 78.35a31.53 31.53 0 0 0-3.105-20.232 30 30 0 0 0 4.474-11.182 31.88 31.88 0 0 0-5.447-24.116" style="fill:#ff3e00"/><path d="M45.817 106.582a20.72 20.72 0 0 1-22.237-8.243 19.17 19.17 0 0 1-3.277-14.503 18 18 0 0 1 .624-2.435l.49-1.498 1.337.981a33.6 33.6 0 0 0 10.203 5.098l.97.294-.09.968a5.85 5.85 0 0 0 1.052 3.878 6.24 6.24 0 0 0 6.695 2.485 5.8 5.8 0 0 0 1.603-.704L69.27 76.28a5.43 5.43 0 0 0 2.45-3.631 5.8 5.8 0 0 0-.987-4.371 6.24 6.24 0 0 0-6.698-2.487 5.7 5.7 0 0 0-1.6.704l-9.953 6.345a19 19 0 0 1-5.296 2.326 20.72 20.72 0 0 1-22.237-8.243 19.17 19.17 0 0 1-3.277-14.502 17.99 17.99 0 0 1 8.13-12.052l26.081-16.623a19 19 0 0 1 5.3-2.329 20.72 20.72 0 0 1 22.237 8.243 19.17 19.17 0 0 1 3.277 14.503 18 18 0 0 1-.624 2.435l-.49 1.498-1.337-.98a33.6 33.6 0 0 0-10.203-5.1l-.97-.294.09-.968a5.86 5.86 0 0 0-1.052-3.878 6.24 6.24 0 0 0-6.696-2.485 5.8 5.8 0 0 0-1.602.704L37.73 51.72a5.42 5.42 0 0 0-2.449 3.63 5.79 5.79 0 0 0 .986 4.372 6.24 6.24 0 0 0 6.698 2.486 5.8 5.8 0 0 0 1.602-.704l9.952-6.342a19 19 0 0 1 5.295-2.328 20.72 20.72 0 0 1 22.237 8.242 19.17 19.17 0 0 1 3.277 14.503 18 18 0 0 1-8.13 12.053l-26.081 16.622a19 19 0 0 1-5.3 2.328" style="fill:#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
1
apps/figgos/apps/web/src/lib/index.ts
Normal file
1
apps/figgos/apps/web/src/lib/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
// place files you want to import through the `$lib` alias in this folder.
|
||||
52
apps/figgos/apps/web/src/routes/+layout.svelte
Normal file
52
apps/figgos/apps/web/src/routes/+layout.svelte
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<script lang="ts">
|
||||
import '../app.css';
|
||||
import { page } from '$app/state';
|
||||
|
||||
let { children } = $props();
|
||||
|
||||
let isCreate = $derived(page.url.pathname === '/');
|
||||
let isCollection = $derived(page.url.pathname === '/collection');
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Figgos</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="min-h-dvh bg-background text-foreground">
|
||||
<!-- Tab Navigation -->
|
||||
<nav class="fixed bottom-0 left-0 right-0 z-50 border-t-3 border-border bg-surface">
|
||||
<div class="mx-auto flex max-w-md items-center justify-around py-2">
|
||||
<a
|
||||
href="/"
|
||||
class="flex flex-col items-center gap-1 px-6 py-2 transition-opacity hover:opacity-80 {isCreate
|
||||
? 'text-primary'
|
||||
: 'text-muted-foreground hover:text-primary'}"
|
||||
>
|
||||
<svg class="h-6 w-6" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11h-4v4h-2v-4H7v-2h4V7h2v4h4v2z"
|
||||
/>
|
||||
</svg>
|
||||
<span class="text-xs font-black uppercase tracking-wider">Create</span>
|
||||
</a>
|
||||
<a
|
||||
href="/collection"
|
||||
class="flex flex-col items-center gap-1 px-6 py-2 transition-opacity hover:opacity-80 {isCollection
|
||||
? 'text-primary'
|
||||
: 'text-muted-foreground hover:text-primary'}"
|
||||
>
|
||||
<svg class="h-6 w-6" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
d="M4 8h4V4H4v4zm6 12h4v-4h-4v4zm-6 0h4v-4H4v4zm0-6h4v-4H4v4zm6 0h4v-4h-4v4zm6-10v4h4V4h-4zm-6 4h4V4h-4v4zm6 6h4v-4h-4v4zm0 6h4v-4h-4v4z"
|
||||
/>
|
||||
</svg>
|
||||
<span class="text-xs font-black uppercase tracking-wider">Collection</span>
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Page Content -->
|
||||
<main class="pb-24">
|
||||
{@render children()}
|
||||
</main>
|
||||
</div>
|
||||
214
apps/figgos/apps/web/src/routes/+page.svelte
Normal file
214
apps/figgos/apps/web/src/routes/+page.svelte
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
<script lang="ts">
|
||||
import type { FigureResponse, FigureRarity } from '@figgos/shared';
|
||||
|
||||
let name = $state('');
|
||||
let description = $state('');
|
||||
let loading = $state(false);
|
||||
let error = $state<string | null>(null);
|
||||
let result = $state<FigureResponse | null>(null);
|
||||
|
||||
const RARITY_SHADOW: Record<FigureRarity, string> = {
|
||||
common: 'rgb(80, 90, 100)',
|
||||
rare: 'rgb(60, 120, 180)',
|
||||
epic: 'rgb(120, 80, 180)',
|
||||
legendary: 'rgb(180, 130, 20)',
|
||||
};
|
||||
|
||||
async function handleGenerate() {
|
||||
if (!name.trim() || !description.trim()) {
|
||||
error = 'Give your figure a name and a story';
|
||||
return;
|
||||
}
|
||||
loading = true;
|
||||
error = null;
|
||||
try {
|
||||
await new Promise((r) => setTimeout(r, 1500));
|
||||
const rarities: FigureRarity[] = ['common', 'common', 'common', 'rare', 'rare', 'epic', 'legendary'];
|
||||
result = {
|
||||
id: 'mock-id',
|
||||
userId: 'mock-user',
|
||||
name: name.trim(),
|
||||
userInput: { description: description.trim() },
|
||||
imageUrl: null,
|
||||
rarity: rarities[Math.floor(Math.random() * rarities.length)],
|
||||
isPublic: false,
|
||||
isArchived: false,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
} catch (e: any) {
|
||||
error = e.message || 'Something went wrong';
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleReset() {
|
||||
name = '';
|
||||
description = '';
|
||||
result = null;
|
||||
error = null;
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if result}
|
||||
<!-- ── Result Screen ── -->
|
||||
<div class="mx-auto max-w-md px-6 pt-8">
|
||||
<!-- Badge -->
|
||||
<div class="mb-5 flex justify-center">
|
||||
<span
|
||||
class="inline-block rounded bg-secondary px-3.5 py-1 text-[11px] font-black uppercase tracking-[3px] text-secondary-foreground"
|
||||
style="transform: rotate(-2deg)"
|
||||
>
|
||||
Unboxing
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Figure Card -->
|
||||
<div class="brutal-shadow rounded-lg">
|
||||
<div
|
||||
class="rounded-lg border-3 border-border bg-surface p-6"
|
||||
>
|
||||
<!-- Image placeholder -->
|
||||
<div
|
||||
class="mx-auto mb-5 flex h-[200px] w-[200px] items-center justify-center rounded-lg border-2 border-border-muted bg-input"
|
||||
>
|
||||
<span class="text-xs text-muted-foreground">Image coming soon</span>
|
||||
</div>
|
||||
|
||||
<h2 class="text-center text-[22px] font-black tracking-tight text-foreground">
|
||||
{result.name}
|
||||
</h2>
|
||||
<p class="mt-3 text-center text-sm leading-5 text-muted-foreground">
|
||||
{result.userInput.description}
|
||||
</p>
|
||||
|
||||
<!-- Rarity Badge -->
|
||||
<div class="mt-4 flex justify-center">
|
||||
<div class="relative">
|
||||
<div
|
||||
class="absolute rounded-full"
|
||||
style="top: 3px; left: 2px; right: -2px; bottom: -3px; background-color: {RARITY_SHADOW[result.rarity]}"
|
||||
></div>
|
||||
<span
|
||||
class="relative inline-block rounded-full border-2 border-white/20 px-5 py-2 text-xs font-black uppercase tracking-[2px]"
|
||||
style="background-color: var(--color-rarity-{result.rarity}); color: var(--color-rarity-{result.rarity}-foreground)"
|
||||
>
|
||||
{result.rarity}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Create Another -->
|
||||
<div class="mt-8">
|
||||
<button onclick={handleReset} class="group w-full cursor-pointer">
|
||||
<div class="relative">
|
||||
<div
|
||||
class="absolute rounded-lg bg-accent-dark"
|
||||
style="top: 5px; left: 3px; right: -3px; bottom: -5px"
|
||||
></div>
|
||||
<div
|
||||
class="relative rounded-lg border-2 border-white/15 bg-accent py-4 text-center text-base font-black uppercase tracking-wider text-accent-foreground transition-opacity group-hover:opacity-90"
|
||||
>
|
||||
Create Another
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<!-- ── Create Form ── -->
|
||||
<div class="mx-auto max-w-md px-6">
|
||||
<!-- Header -->
|
||||
<div class="flex flex-col items-center pb-8 pt-10">
|
||||
<span
|
||||
class="mb-2 inline-block rounded bg-secondary px-3.5 py-1 text-[11px] font-black uppercase tracking-[3px] text-secondary-foreground"
|
||||
style="transform: rotate(-2deg)"
|
||||
>
|
||||
New Drop
|
||||
</span>
|
||||
<h1 class="text-center text-[32px] font-black leading-tight tracking-tight text-foreground">
|
||||
CREATE YOUR<br />FIGGO
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<!-- Form -->
|
||||
<div>
|
||||
<!-- Name -->
|
||||
<label
|
||||
class="mb-2 block text-[13px] font-black uppercase tracking-[3px] text-primary"
|
||||
for="name"
|
||||
>
|
||||
Name
|
||||
</label>
|
||||
<div class="brutal-shadow mb-6 rounded-lg">
|
||||
<input
|
||||
id="name"
|
||||
type="text"
|
||||
bind:value={name}
|
||||
maxlength={200}
|
||||
placeholder="Captain Thunderstrike"
|
||||
class="w-full rounded-lg border-3 border-border bg-input px-4 text-base text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring"
|
||||
style="height: 52px"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Story -->
|
||||
<label
|
||||
class="mb-2 block text-[13px] font-black uppercase tracking-[3px] text-primary"
|
||||
for="story"
|
||||
>
|
||||
Story
|
||||
</label>
|
||||
<div class="brutal-shadow mb-6 rounded-lg">
|
||||
<textarea
|
||||
id="story"
|
||||
bind:value={description}
|
||||
maxlength={2000}
|
||||
rows={4}
|
||||
placeholder="A cyberpunk warrior with lightning gauntlets..."
|
||||
class="w-full rounded-lg border-3 border-border bg-input px-4 py-3.5 text-base text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring"
|
||||
style="min-height: 120px; resize: vertical"
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<!-- Error -->
|
||||
{#if error}
|
||||
<div class="mb-4 rounded-lg border-2 border-destructive/30 bg-destructive/10 p-3">
|
||||
<p class="text-center text-sm font-semibold text-destructive">{error}</p>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Generate Button -->
|
||||
<button
|
||||
onclick={handleGenerate}
|
||||
disabled={loading}
|
||||
class="group w-full cursor-pointer disabled:cursor-not-allowed disabled:opacity-60"
|
||||
>
|
||||
<div class="relative">
|
||||
<div
|
||||
class="absolute rounded-lg bg-primary-dark"
|
||||
style="top: 6px; left: 4px; right: -4px; bottom: -6px"
|
||||
></div>
|
||||
<div
|
||||
class="relative rounded-lg border-3 border-[rgb(255,224,102)] bg-primary py-[18px] text-center text-lg font-black uppercase tracking-[2px] text-primary-foreground transition-opacity group-hover:opacity-90"
|
||||
>
|
||||
{#if loading}
|
||||
<span class="inline-flex items-center gap-2">
|
||||
<svg class="h-5 w-5 animate-spin" viewBox="0 0 24 24" fill="none">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
Rolling...
|
||||
</span>
|
||||
{:else}
|
||||
Generate Figgo
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
23
apps/figgos/apps/web/src/routes/collection/+page.svelte
Normal file
23
apps/figgos/apps/web/src/routes/collection/+page.svelte
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<script lang="ts">
|
||||
</script>
|
||||
|
||||
<div class="flex min-h-[60vh] items-center justify-center px-8">
|
||||
<!-- Empty state card -->
|
||||
<div class="brutal-shadow rounded-lg">
|
||||
<div
|
||||
class="flex flex-col items-center rounded-lg border-3 border-border bg-surface px-8 py-8"
|
||||
>
|
||||
<div
|
||||
class="mb-4 flex h-14 w-14 items-center justify-center rounded-lg border-2 border-border-muted bg-input"
|
||||
>
|
||||
<span class="text-2xl">📦</span>
|
||||
</div>
|
||||
<h2 class="text-lg font-black tracking-tight text-foreground">
|
||||
No figures yet
|
||||
</h2>
|
||||
<p class="mt-2 text-center text-sm leading-5 text-muted-foreground">
|
||||
Create your first Figgo<br />to start your collection.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
3
apps/figgos/apps/web/static/robots.txt
Normal file
3
apps/figgos/apps/web/static/robots.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# allow crawling everything by default
|
||||
User-agent: *
|
||||
Disallow:
|
||||
15
apps/figgos/apps/web/svelte.config.js
Normal file
15
apps/figgos/apps/web/svelte.config.js
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import adapter from '@sveltejs/adapter-node';
|
||||
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
preprocess: vitePreprocess(),
|
||||
|
||||
kit: {
|
||||
adapter: adapter({
|
||||
out: 'build',
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
19
apps/figgos/apps/web/tsconfig.json
Normal file
19
apps/figgos/apps/web/tsconfig.json
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"extends": "./.svelte-kit/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"moduleResolution": "bundler"
|
||||
}
|
||||
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
|
||||
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
|
||||
//
|
||||
// To make changes to top-level options such as include and exclude, we recommend extending
|
||||
// the generated config; see https://svelte.dev/docs/kit/configuration#typescript
|
||||
}
|
||||
18
apps/figgos/apps/web/vite.config.ts
Normal file
18
apps/figgos/apps/web/vite.config.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import tailwindcss from '@tailwindcss/vite';
|
||||
import { defineConfig } from 'vite';
|
||||
import { MANACORE_SHARED_PACKAGES } from '@manacore/shared-vite-config';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [tailwindcss(), sveltekit()],
|
||||
server: {
|
||||
port: 5196,
|
||||
strictPort: true,
|
||||
},
|
||||
ssr: {
|
||||
noExternal: [...MANACORE_SHARED_PACKAGES, '@figgos/shared'],
|
||||
},
|
||||
optimizeDeps: {
|
||||
exclude: [...MANACORE_SHARED_PACKAGES, '@figgos/shared'],
|
||||
},
|
||||
});
|
||||
629
pnpm-lock.yaml
generated
629
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue