chore: 导入清理前的完整工程状态(含 Capacitor 原生壳,作为回滚备份点)

This commit is contained in:
toor
2026-10-21 11:50:10 +08:00
committed by trae-solo-agent
commit 8ded87a3a8
389 changed files with 52242 additions and 0 deletions
@@ -0,0 +1,84 @@
<script lang="ts" setup>
import type { DbRecipeItem } from '~/utils/db'
import { isFavorited, toggleFavorite } from '~/composables/store/favorite'
import { addRecipeHistory } from '~/composables/store/history'
import { openRecipe } from '~/utils/recipe'
import { yunleHaptic } from '~/utils/yunleHost'
/**
* 菜谱列表的一行:收藏状态在行内自己读,父列表重新渲染时只要 dish 不变,这一行就不会跟着更新
*/
const props = defineProps<{
dish: DbRecipeItem
}>()
const emit = defineEmits<{
toggled: [favorited: boolean]
}>()
const sliding = ref<{ $el: HTMLIonItemSlidingElement }>()
const favorited = computed(() => isFavorited(props.dish))
function open() {
addRecipeHistory(props.dish)
openRecipe(props.dish)
}
function toggle() {
toggleFavorite(props.dish)
void yunleHaptic(favorited.value ? 'success' : 'light')
void sliding.value?.$el.close()
emit('toggled', favorited.value)
}
</script>
<template>
<ion-item-sliding ref="sliding">
<ion-item :button="true" :detail="false" @click="open">
<ion-label class="truncate">
<DishLabel class="text-sm" :dish="dish" />
</ion-label>
<ion-button
slot="end"
class="recipe-row-star"
fill="clear"
:aria-label="favorited ? '取消收藏' : '收藏'"
:aria-pressed="favorited"
@click.stop="toggle()"
>
<ion-icon slot="icon-only" :icon="favorited ? ioniconsStar : ioniconsStarOutline" color="warning" />
</ion-button>
</ion-item>
<ion-item-options side="end" @ion-swipe="toggle">
<ion-item-option color="warning" :expandable="true" @click="toggle">
{{ favorited ? '取消收藏' : '收藏' }}
</ion-item-option>
</ion-item-options>
</ion-item-sliding>
</template>
<style scoped>
.recipe-row-star ion-icon {
transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.recipe-row-star[aria-pressed='true'] ion-icon {
animation: recipe-row-star-pop 0.36s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes recipe-row-star-pop {
0% {
transform: scale(0.6);
}
60% {
transform: scale(1.2);
}
100% {
transform: scale(1);
}
}
@media (prefers-reduced-motion: reduce) {
.recipe-row-star[aria-pressed='true'] ion-icon {
animation: none;
}
}
</style>
@@ -0,0 +1,48 @@
<script lang="ts" setup>
import type { Recipes } from '~/types'
defineProps<{
recipes: Recipes
}>()
</script>
<template>
<table
class="recipe-table bg-$c-bg"
overflow="auto" h="full"
>
<thead>
<tr>
<th />
<th>
名称
</th>
<th>
工具
</th>
<th>
材料
</th>
</tr>
</thead>
<tbody>
<RecipeTableItem
v-for="(recipe, i) in recipes"
:key="recipe.name"
:index="i" :recipe="recipe"
/>
</tbody>
</table>
</template>
<style lang="scss">
.recipe-table {
font-size: 0.8rem;
}
tr,
th,
td {
border: 1px solid black;
}
</style>
@@ -0,0 +1,31 @@
<script lang="ts" setup>
import type { RecipeItem } from '~/types'
defineProps<{
index: number
recipe: RecipeItem
}>()
</script>
<template>
<tr>
<td>
{{ index }}
</td>
<td>
<a
class="text-blue-500" font-bold
:href="getRecipeLink(recipe)"
target="_blank"
>
{{ recipe.name }}
</a>
</td>
<td>
{{ recipe.tools.join('、') }}
</td>
<td>
{{ recipe.stuff.join('、') }}
</td>
</tr>
</template>