diff --git a/ka-note/VERSION b/ka-note/VERSION index 48f713f..b7ae2cf 100644 --- a/ka-note/VERSION +++ b/ka-note/VERSION @@ -1 +1 @@ -1.2.31 \ No newline at end of file +1.2.33 \ No newline at end of file diff --git a/ka-note/client/src/lib/components/RoomIcon.svelte b/ka-note/client/src/lib/components/RoomIcon.svelte new file mode 100644 index 0000000..968ff44 --- /dev/null +++ b/ka-note/client/src/lib/components/RoomIcon.svelte @@ -0,0 +1,43 @@ + + + diff --git a/ka-note/client/src/lib/db/repositories.ts b/ka-note/client/src/lib/db/repositories.ts index 8e09bd6..7f83383 100644 --- a/ka-note/client/src/lib/db/repositories.ts +++ b/ka-note/client/src/lib/db/repositories.ts @@ -944,13 +944,14 @@ export async function getTasksByContext(contextId: string): Promise { // --- Rooms --- -export async function createRoom(fields: { name: string; groupType: RoomGroupType; icon: string; sortOrder?: number; userId?: string }): Promise { +export async function createRoom(fields: { name: string; groupType: RoomGroupType; icon: string; color?: string | null; sortOrder?: number; userId?: string }): Promise { const room: Room = { id: newId(), userId: fields.userId ?? '', name: fields.name, groupType: fields.groupType, icon: fields.icon, + color: fields.color ?? null, sortOrder: fields.sortOrder ?? 0, updatedAt: now(), deletedAt: null, @@ -965,7 +966,7 @@ export async function getRooms(): Promise { return db.rooms.filter(r => !r.deletedAt).sortBy('sortOrder'); } -export async function updateRoom(id: string, changes: Partial>): Promise { +export async function updateRoom(id: string, changes: Partial>): Promise { const room = await db.rooms.get(id); if (room) { await db.rooms.update(id, { ...changes, updatedAt: now(), version: room.version + 1 }); @@ -1123,22 +1124,22 @@ export async function getFamilyPersons(): Promise { // --- Seed default rooms --- -const DEFAULT_ROOMS: Array<{ name: string; groupType: RoomGroupType; icon: string }> = [ - { name: 'Wohnzimmer', groupType: 'living', icon: 'sofa' }, - { name: 'Schlafzimmer', groupType: 'living', icon: 'bed' }, - { name: 'Kinderzimmer', groupType: 'living', icon: 'baby' }, - { name: 'Esszimmer', groupType: 'living', icon: 'utensils' }, - { name: 'Ankleidezimmer', groupType: 'living', icon: 'shirt' }, - { name: 'Flur/Diele', groupType: 'living', icon: 'door-open' }, - { name: 'Küche', groupType: 'functional', icon: 'chef-hat' }, - { name: 'Badezimmer', groupType: 'functional', icon: 'bath' }, - { name: 'WC', groupType: 'functional', icon: 'toilet' }, - { name: 'Arbeitszimmer', groupType: 'functional', icon: 'monitor' }, - { name: 'Hauswirtschaft', groupType: 'functional', icon: 'washing-machine' }, - { name: 'Keller', groupType: 'outdoor', icon: 'archive' }, - { name: 'Dachboden', groupType: 'outdoor', icon: 'home' }, - { name: 'Garage', groupType: 'outdoor', icon: 'car' }, - { name: 'Garten', groupType: 'outdoor', icon: 'tree' }, +const DEFAULT_ROOMS: Array<{ name: string; groupType: RoomGroupType; icon: string; color: string }> = [ + { name: 'Wohnzimmer', groupType: 'living', icon: 'sofa', color: '#818cf8' }, + { name: 'Schlafzimmer', groupType: 'living', icon: 'bed', color: '#a78bfa' }, + { name: 'Kinderzimmer', groupType: 'living', icon: 'baby', color: '#f472b6' }, + { name: 'Esszimmer', groupType: 'living', icon: 'utensils', color: '#fb923c' }, + { name: 'Ankleidezimmer', groupType: 'living', icon: 'shirt', color: '#c084fc' }, + { name: 'Flur/Diele', groupType: 'living', icon: 'door-open', color: '#94a3b8' }, + { name: 'Küche', groupType: 'functional', icon: 'chef-hat', color: '#fbbf24' }, + { name: 'Badezimmer', groupType: 'functional', icon: 'droplets', color: '#22d3ee' }, + { name: 'WC', groupType: 'functional', icon: 'droplets', color: '#67e8f9' }, + { name: 'Arbeitszimmer', groupType: 'functional', icon: 'monitor', color: '#60a5fa' }, + { name: 'Hauswirtschaft', groupType: 'functional', icon: 'archive', color: '#94a3b8' }, + { name: 'Keller', groupType: 'outdoor', icon: 'archive', color: '#78716c' }, + { name: 'Dachboden', groupType: 'outdoor', icon: 'home', color: '#a8a29e' }, + { name: 'Garage', groupType: 'outdoor', icon: 'car', color: '#6b7280' }, + { name: 'Garten', groupType: 'outdoor', icon: 'tree-pine', color: '#4ade80' }, ]; const SEED_SETTING_KEY = 'inventory.seeded'; @@ -1156,6 +1157,7 @@ export async function seedDefaultRoomsIfNeeded(userId: string): Promise { name: r.name, groupType: r.groupType, icon: r.icon, + color: r.color, sortOrder: i, updatedAt: ts, deletedAt: null, diff --git a/ka-note/client/src/lib/utils/roomAppearance.ts b/ka-note/client/src/lib/utils/roomAppearance.ts new file mode 100644 index 0000000..5e9e7b7 --- /dev/null +++ b/ka-note/client/src/lib/utils/roomAppearance.ts @@ -0,0 +1,49 @@ +export interface RoomIconDef { + key: string; + label: string; +} + +export const ROOM_ICONS: RoomIconDef[] = [ + { key: 'sofa', label: 'Sofa' }, + { key: 'bed', label: 'Bett' }, + { key: 'armchair', label: 'Sessel' }, + { key: 'utensils', label: 'Besteck' }, + { key: 'chef-hat', label: 'Küche' }, + { key: 'droplets', label: 'Wasser' }, + { key: 'monitor', label: 'Bildschirm' }, + { key: 'shirt', label: 'Kleidung' }, + { key: 'baby', label: 'Kind' }, + { key: 'door-open', label: 'Tür' }, + { key: 'archive', label: 'Regal' }, + { key: 'home', label: 'Haus' }, + { key: 'car', label: 'Auto' }, + { key: 'tree-pine', label: 'Garten' }, + { key: 'hammer', label: 'Werkzeug' }, + { key: 'dumbbell', label: 'Fitness' }, + { key: 'music', label: 'Musik' }, + { key: 'flame', label: 'Feuer' }, + { key: 'bike', label: 'Fahrrad' }, + { key: 'box', label: 'Kiste' }, +]; + +export interface RoomColorDef { + key: string; + label: string; + hex: string; +} + +export const ROOM_COLORS: RoomColorDef[] = [ + { key: 'indigo', label: 'Indigo', hex: '#818cf8' }, + { key: 'violet', label: 'Violett', hex: '#a78bfa' }, + { key: 'purple', label: 'Lila', hex: '#c084fc' }, + { key: 'pink', label: 'Pink', hex: '#f472b6' }, + { key: 'rose', label: 'Rot', hex: '#f87171' }, + { key: 'orange', label: 'Orange', hex: '#fb923c' }, + { key: 'amber', label: 'Gelb', hex: '#fbbf24' }, + { key: 'green', label: 'Grün', hex: '#4ade80' }, + { key: 'teal', label: 'Türkis', hex: '#2dd4bf' }, + { key: 'cyan', label: 'Cyan', hex: '#22d3ee' }, + { key: 'blue', label: 'Blau', hex: '#60a5fa' }, + { key: 'slate', label: 'Grau', hex: '#94a3b8' }, + { key: 'stone', label: 'Stein', hex: '#a8a29e' }, +]; diff --git a/ka-note/client/src/routes/inventory/rooms/+page.svelte b/ka-note/client/src/routes/inventory/rooms/+page.svelte index 3e01c59..cb98175 100644 --- a/ka-note/client/src/routes/inventory/rooms/+page.svelte +++ b/ka-note/client/src/routes/inventory/rooms/+page.svelte @@ -4,9 +4,11 @@ import { db } from '$lib/db/schema'; import { createRoom, updateRoom, softDeleteRoom } from '$lib/db/repositories'; import { account } from '$lib/auth/authStore'; - import { Plus, Package, MoreHorizontal } from 'lucide-svelte'; + import { Plus, MoreHorizontal } from 'lucide-svelte'; import DarkSelect from '$lib/components/DarkSelect.svelte'; import ConfirmDialog from '$lib/components/ConfirmDialog.svelte'; + import RoomIcon from '$lib/components/RoomIcon.svelte'; + import { ROOM_ICONS, ROOM_COLORS } from '$lib/utils/roomAppearance'; import type { Room, RoomGroupType } from '@ka-note/shared'; const rooms$ = liveQuery(() => db.rooms.filter(r => !r.deletedAt).sortBy('sortOrder')); @@ -26,19 +28,27 @@ return ($assets$ ?? []).filter(a => a.roomId === roomId).length; } - // Add room + // --- Add room --- let showAddRoom = $state(false); let newRoomName = $state(''); let newRoomGroup = $state('living'); + let newRoomIcon = $state('sofa'); + let newRoomColor = $state('#818cf8'); async function addRoom() { if (!newRoomName.trim()) return; - await createRoom({ name: newRoomName.trim(), groupType: newRoomGroup, icon: 'package', userId: $account?.homeAccountId ?? '' }); + await createRoom({ + name: newRoomName.trim(), + groupType: newRoomGroup, + icon: newRoomIcon, + color: newRoomColor, + userId: $account?.homeAccountId ?? '', + }); newRoomName = ''; showAddRoom = false; } - // Rename room + // --- Rename --- let renamingId = $state(null); let renameValue = $state(''); @@ -54,14 +64,32 @@ renamingId = null; } - // Delete room + // --- Appearance picker --- + let appearanceRoom = $state(null); + let pickIcon = $state('sofa'); + let pickColor = $state('#818cf8'); + + function openAppearance(room: Room) { + appearanceRoom = room; + pickIcon = room.icon; + pickColor = room.color ?? '#818cf8'; + menuRoomId = null; + } + + async function saveAppearance() { + if (!appearanceRoom) return; + await updateRoom(appearanceRoom.id, { icon: pickIcon, color: pickColor }); + appearanceRoom = null; + } + + // --- Delete --- let deleteTarget = $state(null); async function confirmDelete() { if (deleteTarget) await softDeleteRoom(deleteTarget.id); deleteTarget = null; } - // Context menu + // --- Context menu --- let menuRoomId = $state(null); function toggleMenu(id: string) { menuRoomId = menuRoomId === id ? null : id; } @@ -92,7 +120,7 @@ onclick={() => renamingId !== room.id && goto('/inventory/rooms/' + room.id)} onkeydown={(e) => renamingId !== room.id && e.key === 'Enter' && goto('/inventory/rooms/' + room.id)} > - + {#if renamingId === room.id} {#if menuRoomId === room.id} -
e.stopPropagation()}> +
e.stopPropagation()}> +
{/if} @@ -126,6 +155,7 @@ {/each}
+ {#if showAddRoom}