feat: orientation model, password confirm, frontend build

- Collapse orientation to landscape/portrait (ribbon left = portrait standard)
- Add OrientationPicker component and wire settings sheet in HomeView
- Add password confirmation field to registration form (RepeatedType)
- Build frontend SPA to public/build/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-04 16:59:03 -04:00
parent 6c7c7a1a6f
commit 6c891d6fad
119 changed files with 82314 additions and 75 deletions
+25 -4
View File
@@ -12,8 +12,22 @@
{{ status === 'offline' ? 'Offline' : 'Sync issue' }}
</div>
<!-- Settings button (large card only) -->
<button
v-if="size === 'large'"
class="frame-card__settings-btn"
type="button"
aria-label="Frame settings"
@click="$emit('edit', deviceId)"
>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true">
<circle cx="12" cy="12" r="3"/>
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/>
</svg>
</button>
<!-- Preview area -->
<div class="frame-card__preview">
<div class="frame-card__preview" :style="previewStyle">
<img
v-if="thumbnailUrl"
:src="thumbnailUrl"
@@ -49,18 +63,26 @@
</template>
<script setup lang="ts">
import { computed } from 'vue'
import BaseButton from '@/components/BaseButton.vue'
defineProps<{
const props = defineProps<{
deviceId: number
name: string
size: 'large' | 'compact'
status: 'ok' | 'offline' | 'sync-fail'
orientation: 'landscape' | 'portrait'
thumbnailUrl?: string
photoCount?: number
}>()
defineEmits<{ 'add-photo': [deviceId: number] }>()
defineEmits<{ 'add-photo': [deviceId: number]; edit: [deviceId: number] }>()
const previewStyle = computed(() =>
props.size === 'large'
? { aspectRatio: props.orientation === 'portrait' ? '3/5' : '5/3' }
: {}
)
</script>
<style scoped lang="scss">
@@ -99,7 +121,6 @@ defineEmits<{ 'add-photo': [deviceId: number] }>()
// ── Large (single device) ────────────────────────────────────────────────
&--large &__preview {
aspect-ratio: 5/3;
background: var(--color-surface-2);
display: flex;
align-items: center;