kiwi/frontend/src/components/SettingsView.vue
pyr0ball b9eadcdf0e feat(frontend): warm organic design overhaul — Fraunces/DM fonts, saffron accent, compact inventory shelf view
- EditItemModal: replace all hardcoded colors (#eee, #f5f5f5, #2196F3, etc.) with CSS variable tokens; restyle modal header with display font, blur backdrop, and theme-aware form elements
- ReceiptsView: replace emoji headings, hardcoded spinner, and non-theme .button class with themed equivalents; all colors through var(--color-*) tokens
- RecipesView: fix broken --color-warning-rgb / --color-primary-rgb references (not defined in theme); use --color-warning-bg and --color-info-bg instead; apply section-title to heading
- SettingsView: apply section-title display-font class to heading for consistency
- InventoryList: remove three dead functions (formatDate, getDaysUntilExpiry, getExpiryClass) that caused TS6133 build errors
2026-04-01 22:29:55 -07:00

162 lines
3.9 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="settings-view">
<div class="card">
<h2 class="section-title text-xl mb-md">Settings</h2>
<!-- Cooking Equipment -->
<section>
<h3 class="text-lg font-semibold mb-xs">Cooking Equipment</h3>
<p class="text-sm text-secondary mb-md">
Tell Kiwi what you have used when Hard Day Mode is on to filter out recipes requiring
equipment you don't own.
</p>
<!-- Current equipment tags -->
<div class="tags-wrap flex flex-wrap gap-xs mb-sm">
<span
v-for="item in settingsStore.cookingEquipment"
:key="item"
class="tag-chip status-badge status-info"
>
{{ item }}
<button class="chip-remove" @click="removeEquipment(item)" aria-label="Remove">×</button>
</span>
</div>
<!-- Custom input -->
<div class="form-group">
<label class="form-label">Add equipment</label>
<input
class="form-input"
v-model="equipmentInput"
placeholder="Type equipment name, press Enter or comma"
@keydown="onEquipmentKey"
@blur="commitEquipmentInput"
/>
</div>
<!-- Quick-add chips -->
<div class="form-group">
<label class="form-label">Quick-add</label>
<div class="flex flex-wrap gap-xs">
<button
v-for="eq in quickAddOptions"
:key="eq"
:class="['btn', 'btn-sm', 'btn-secondary', { active: settingsStore.cookingEquipment.includes(eq) }]"
@click="toggleEquipment(eq)"
>
{{ eq }}
</button>
</div>
</div>
<!-- Save button -->
<div class="flex-start gap-sm">
<button
class="btn btn-primary"
:disabled="settingsStore.loading"
@click="settingsStore.save()"
>
<span v-if="settingsStore.loading">Saving…</span>
<span v-else-if="settingsStore.saved">✓ Saved!</span>
<span v-else>Save Settings</span>
</button>
</div>
</section>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useSettingsStore } from '../stores/settings'
const settingsStore = useSettingsStore()
const equipmentInput = ref('')
const quickAddOptions = [
'Oven',
'Stovetop',
'Microwave',
'Air Fryer',
'Instant Pot',
'Slow Cooker',
'Grill',
'Blender',
]
function addEquipment(value: string) {
const item = value.trim()
if (item && !settingsStore.cookingEquipment.includes(item)) {
settingsStore.cookingEquipment = [...settingsStore.cookingEquipment, item]
}
equipmentInput.value = ''
}
function removeEquipment(item: string) {
settingsStore.cookingEquipment = settingsStore.cookingEquipment.filter((e) => e !== item)
}
function toggleEquipment(item: string) {
if (settingsStore.cookingEquipment.includes(item)) {
removeEquipment(item)
} else {
addEquipment(item)
}
}
function onEquipmentKey(e: KeyboardEvent) {
if (e.key === 'Enter' || e.key === ',') {
e.preventDefault()
addEquipment(equipmentInput.value)
}
}
function commitEquipmentInput() {
if (equipmentInput.value.trim()) {
addEquipment(equipmentInput.value)
}
}
onMounted(async () => {
await settingsStore.load()
})
</script>
<style scoped>
.mb-md {
margin-bottom: var(--spacing-md);
}
.mb-sm {
margin-bottom: var(--spacing-sm);
}
.mb-xs {
margin-bottom: var(--spacing-xs);
}
.tag-chip {
display: inline-flex;
align-items: center;
gap: var(--spacing-xs);
}
.chip-remove {
background: transparent;
border: none;
cursor: pointer;
padding: 0;
font-size: 14px;
line-height: 1;
color: inherit;
opacity: 0.7;
transition: opacity 0.15s;
}
.chip-remove:hover {
opacity: 1;
transform: none;
}
</style>