Deck schema, API routes, and SvelteKit UI for creating and browsing decks (DeckStack component, inline creation, floating nav). Production compose updated with PUBLIC_AUTH_WEB_URL so cards-web redirects to auth.mana.how for login/register instead of the raw API. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
80 lines
2.1 KiB
TypeScript
80 lines
2.1 KiB
TypeScript
import { z } from 'zod';
|
|
|
|
import { FsrsSettingsSchema } from './fsrs-settings.ts';
|
|
|
|
const VisibilitySchema = z.enum(['private', 'space', 'public']);
|
|
|
|
export const DECK_CATEGORY_IDS = [
|
|
'language',
|
|
'medicine',
|
|
'science',
|
|
'math',
|
|
'history',
|
|
'law',
|
|
'technology',
|
|
'arts',
|
|
'music',
|
|
'sport',
|
|
'other',
|
|
] as const;
|
|
|
|
export type DeckCategoryId = (typeof DECK_CATEGORY_IDS)[number];
|
|
export const DeckCategorySchema = z.enum(DECK_CATEGORY_IDS);
|
|
|
|
export const DECK_CATEGORY_LABELS: Record<DeckCategoryId, string> = {
|
|
language: 'Sprache',
|
|
medicine: 'Medizin',
|
|
science: 'Wissenschaft',
|
|
math: 'Mathematik',
|
|
history: 'Geschichte',
|
|
law: 'Recht',
|
|
technology: 'Technik',
|
|
arts: 'Kunst',
|
|
music: 'Musik',
|
|
sport: 'Sport',
|
|
other: 'Sonstiges',
|
|
};
|
|
|
|
export const DeckSchema = z
|
|
.object({
|
|
id: z.string().min(1),
|
|
user_id: z.string().min(1),
|
|
name: z.string().min(1).max(200),
|
|
description: z.string().max(2000).optional().nullable(),
|
|
color: z
|
|
.string()
|
|
.regex(/^#[0-9a-fA-F]{6}$/)
|
|
.optional()
|
|
.nullable(),
|
|
category: DeckCategorySchema.optional().nullable(),
|
|
visibility: VisibilitySchema.default('private'),
|
|
fsrs_settings: FsrsSettingsSchema.default({}),
|
|
content_hash: z.string().optional().nullable(),
|
|
forked_from_marketplace_deck_id: z.string().optional().nullable(),
|
|
forked_from_marketplace_version_id: z.string().optional().nullable(),
|
|
archived_at: z.string().datetime().optional().nullable(),
|
|
created_at: z.string().datetime(),
|
|
updated_at: z.string().datetime(),
|
|
})
|
|
.strict();
|
|
export type Deck = z.infer<typeof DeckSchema>;
|
|
|
|
export const DeckCreateSchema = z
|
|
.object({
|
|
name: z.string().min(1).max(200),
|
|
description: z.string().max(2000).optional(),
|
|
color: z
|
|
.string()
|
|
.regex(/^#[0-9a-fA-F]{6}$/)
|
|
.optional(),
|
|
category: DeckCategorySchema.optional(),
|
|
visibility: VisibilitySchema.optional(),
|
|
fsrs_settings: FsrsSettingsSchema.optional(),
|
|
})
|
|
.strict();
|
|
export type DeckCreate = z.infer<typeof DeckCreateSchema>;
|
|
|
|
export const DeckUpdateSchema = DeckCreateSchema.partial().extend({
|
|
archived: z.boolean().optional(),
|
|
});
|
|
export type DeckUpdate = z.infer<typeof DeckUpdateSchema>;
|