Refactor frontend to Vue 3 + Vite + Pinia + Cypress E2E

- Replace single-file 8441-line HTML with Vue 3 SPA
- Pinia stores: auth, oils, recipes, diary, ui
- Composables: useApi, useDialog, useSmartPaste, useOilTranslation
- 6 shared components: RecipeCard, RecipeDetailOverlay, TagPicker, etc.
- 9 page views: RecipeSearch, RecipeManager, Inventory, OilReference, etc.
- 14 Cypress E2E test specs (113 tests), all passing
- Multi-stage Dockerfile (Node build + Python runtime)
- Demo video generation scripts (TTS + subtitles + screen recording)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-06 18:35:00 +00:00
parent 0368e85abe
commit ee8ec23dc7
62 changed files with 15035 additions and 8448 deletions

View File

@@ -0,0 +1,56 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { api } from '../composables/useApi'
export const useDiaryStore = defineStore('diary', () => {
const userDiary = ref([])
const currentDiaryId = ref(null)
// Actions
async function loadDiary() {
const data = await api.get('/api/diary')
userDiary.value = data
}
async function createDiary(data) {
const result = await api.post('/api/diary', data)
await loadDiary()
return result
}
async function updateDiary(id, data) {
const result = await api.put(`/api/diary/${id}`, data)
await loadDiary()
return result
}
async function deleteDiary(id) {
await api.delete(`/api/diary/${id}`)
userDiary.value = userDiary.value.filter((d) => (d._id ?? d.id) !== id)
if (currentDiaryId.value === id) {
currentDiaryId.value = null
}
}
async function addEntry(diaryId, content) {
const result = await api.post(`/api/diary/${diaryId}/entries`, content)
await loadDiary()
return result
}
async function deleteEntry(entryId) {
await api.delete(`/api/diary/entries/${entryId}`)
await loadDiary()
}
return {
userDiary,
currentDiaryId,
loadDiary,
createDiary,
updateDiary,
deleteDiary,
addEntry,
deleteEntry,
}
})