14 Commits

Author SHA1 Message Date
YunYouJun
87025cd17e chore: release v1.2.2 2023-11-13 00:41:24 +08:00
YunYouJun
68a4b2dbeb chore: upgrade deps 2023-11-13 00:41:15 +08:00
YunYouJun
1ab402af8b feat: add random recipes localStorage 2023-11-13 00:31:29 +08:00
YunYouJun
b2cf053446 chore: update lock 2023-11-11 19:53:44 +08:00
YunYouJun
37bab9269c chore: release v1.2.1 2023-11-11 19:53:07 +08:00
YunYouJun
44f9b40ee5 feat: add 麻婆豆腐, close #55 2023-11-11 19:51:51 +08:00
YunYouJun
4ddd5ac2d2 chore: fix data updated time 2023-11-11 19:46:44 +08:00
YunYouJun
9df47e977e chore: fix 可乐饼 link 2023-11-11 19:43:43 +08:00
KazariEX
5fb76f24dc fix: keyword filter (#57) 2023-11-07 15:33:16 +08:00
YunYouJun
014f129b8e chore: fix style details cursor size 2023-11-07 02:18:49 +08:00
YunYouJun
2949c45839 chore: release v1.2.0 2023-11-07 02:00:11 +08:00
YunYouJun
81586158d5 chore: fix lint 2023-11-07 02:00:03 +08:00
YunYouJun
bfb6ea3e14 feat: add history 2023-11-07 01:59:29 +08:00
YunYouJun
7d26f9ba84 feat: add search keyword 2023-11-07 01:06:30 +08:00
19 changed files with 1228 additions and 787 deletions

View File

@@ -16,11 +16,12 @@ const { random, randomRecipes } = useRandomRecipe(count)
</button>
</div>
<div v-show="randomRecipes.length > 0">
<button cursor-pointer class="inline-flex inline-flex items-center justify-center rounded-md border-none bg-blue-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-blue-500 focus-visible:outline-2 focus-visible:outline-blue-600 focus-visible:outline-offset-2 focus-visible:outline" @click="random">
<div class="transition" hover="text-blue-500" i-ri-refresh-line mr-1 inline-flex />
<div>随机一下</div>
</button>
<div v-show="randomRecipes.length > 0">
<div m="t-8" flex="~ col">
<template v-for="recipe, i in randomRecipes" :key="i">
<DishTag v-if="recipe" :dish="recipe" />

View File

@@ -0,0 +1,105 @@
<script setup lang="ts">
import { Dialog, DialogPanel, DialogTitle, TransitionChild, TransitionRoot } from '@headlessui/vue'
import { db } from '~/utils/db'
const isOpen = ref(false)
function closeModal() {
isOpen.value = false
}
function openModal() {
isOpen.value = true
}
const keyword = ref('')
async function getFilterRecipes(keyword: string) {
return db.recipes.filter((recipe) => {
return recipe.name.includes(keyword)
}).toArray()
}
const filteredRecipes = computedAsync(async () => {
return await getFilterRecipes(keyword.value)
})
</script>
<template>
<YlfIconButton
absolute right-3 top-5
class="icon-btn hover:text-yellow-400 !outline-none"
text-xl
title="切换" @click="openModal"
>
<div i="ri-search-line" />
</YlfIconButton>
<TransitionRoot appear :show="isOpen" as="template">
<Dialog as="div" class="relative z-10" @close="closeModal">
<TransitionChild
as="template"
enter="duration-300 ease-out"
enter-from="opacity-0"
enter-to="opacity-100"
leave="duration-200 ease-in"
leave-from="opacity-100"
leave-to="opacity-0"
>
<div class="fixed inset-0 bg-black/10" />
</TransitionChild>
<div class="fixed inset-0 overflow-y-auto">
<div
class="h-full flex justify-center text-center"
>
<TransitionChild
as="template"
enter="duration-300 ease-out"
enter-from="opacity-0 scale-95"
enter-to="opacity-100 scale-100"
leave="duration-200 ease-in"
leave-from="opacity-100 scale-100"
leave-to="opacity-0 scale-95"
>
<DialogPanel
class="h-full max-w-xl w-full transform overflow-hidden bg-white p-4 text-left align-middle shadow-xl transition-all dark:bg-dark-600"
md="rounded-2xl"
overflow="auto"
flex="~ col"
>
<DialogTitle
as="h3"
class="flex items-center justify-center text-lg font-medium leading-6"
>
<div relative inline-flex flex="grow">
<div
i-ri-search-line
class="absolute left-3 top-2 cursor-pointer text-gray-400"
/>
<input
v-model="keyword"
type="text"
class="w-full rounded-full bg-transparent text-sm focus:outline-none focus:ring-1 focus:ring-blue-500 placeholder-gray-400"
border="~ rounded-full gray-300 op-50 focus:border-blue-500"
placeholder="搜索菜谱"
autofocus py-2 pl-10 pr-3
>
<div
v-if="keyword" i-ri-close-line
class="absolute right-3 top-2 cursor-pointer text-gray-400"
@click="keyword = ''"
/>
</div>
<div op="70" ml-2 inline-flex cursor-pointer text-base @click="closeModal">
取消
</div>
</DialogTitle>
<div flex="~ col grow" overflow="auto" class="mt-2" text-xs>
<DishTag v-for="item, i in filteredRecipes" :key="i" :dish="item" />
</div>
</DialogPanel>
</TransitionChild>
</div>
</div>
</Dialog>
</TransitionRoot>
</template>

View File

@@ -3,6 +3,7 @@ import type { DbRecipeItem } from '~/utils/db'
import { tools } from '~/data/food'
import type { RecipeItem } from '~/types'
import { getEmojisFromStuff } from '~/utils'
import { recipeHistories } from '~/composables/store/history'
const props = defineProps<{
dish: RecipeItem | DbRecipeItem
@@ -10,16 +11,21 @@ const props = defineProps<{
const gtm = useGtm()
function triggerGtm(val: string) {
function triggerGtm(dish: RecipeItem) {
recipeHistories.value.push({
recipe: dish,
time: Date.now(),
})
gtm?.trackEvent({
event: 'click',
category: `dish_${val}`,
category: `dish_${dish.name}`,
action: 'click_recipe',
label: '跳转菜谱',
})
gtm?.trackEvent({
event: 'click_dish',
action: val,
action: dish.name,
})
}
@@ -34,7 +40,7 @@ const dishLabel = computed(() => {
:href="dish.link || `https://www.bilibili.com/video/${dish.bv}`" target="_blank" class="dish-tag rounded tag" p="x-2"
border="~ blue-200 dark:blue-800"
bg="blue-300 opacity-20"
@click="triggerGtm(dish.name)"
@click="triggerGtm(dish)"
>
<span m="r-1" class="inline-flex items-center justify-center" text="sm blue-700 dark:blue-200">
{{ dishLabel }}

View File

@@ -16,11 +16,11 @@ defineProps<{
:is="to ? NuxtLink : 'div'"
:to="to"
class="ylf-form-item"
w-full flex cursor-pointer items-center justify-between p-3
w-full flex cursor-pointer items-center justify-between p-2
hover:bg-gray-100
dark:hover:bg-dark-400
>
<div v-if="label" class="text-md" inline-flex items-center justify-center>
<div v-if="label" class="text-sm" inline-flex items-center justify-center>
<div v-if="icon" :class="icon" mr-2 inline-flex />
<span>{{ label }}</span>
</div>

View File

@@ -0,0 +1,22 @@
<script lang="ts" setup>
defineProps<{
icon: string
label: string
to: string
}>()
</script>
<template>
<NuxtLink
:to="to"
flex="~ col"
border="~ solid dark:$ylf-c-border"
bg="$ylf-c-bg-alt"
class="inline-flex items-center justify-center rounded-md px-4 py-2 text-sm font-medium decoration-none hover-bg-gray-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-blue-500 dark:hover:bg-dark-400"
>
<div :class="icon" inline-flex text-lg />
<div mt-2 inline-flex text-xs>
{{ label }}
</div>
</NuxtLink>
</template>

View File

@@ -1,3 +1,5 @@
import { useStorage } from '@vueuse/core'
import { namespace } from '~/constants'
import type { DbRecipeItem } from '~/utils/db'
/**
@@ -5,7 +7,7 @@ import type { DbRecipeItem } from '~/utils/db'
* @param total
*/
export function useRandomRecipe(total: Ref<number>) {
const randomRecipes = ref<(DbRecipeItem | undefined)[]>([])
const randomRecipes = useStorage<(DbRecipeItem | undefined)[]>(`${namespace}:random:recipes`, [])
async function random() {
const length = await db.recipes.count()
const randomArr = generateRandomArray(length, total.value)
@@ -19,6 +21,8 @@ export function useRandomRecipe(total: Ref<number>) {
})
onMounted(() => {
// 如果没有随机菜谱,就生成一次
if (randomRecipes.value.length <= 0)
random()
})

View File

@@ -0,0 +1,10 @@
import { useStorage } from '@vueuse/core'
import { namespace } from '~/constants'
import type { RecipeItem } from '~/types'
export interface RecipeHistoryItem {
recipe: RecipeItem
time: number
}
export const recipeHistories = useStorage<RecipeHistoryItem[]>(`${namespace}:history`, [])

View File

@@ -78,8 +78,6 @@ export const useRecipeStore = defineStore('recipe', () => {
async function searchRecipes() {
isSearching.value = true
let result: RecipeItem[] = []
if (keyword.value)
result = await db.recipes.filter(item => item.name.includes(keyword.value)).toArray()
if (curMode.value === 'strict') {
result = await db.recipes.filter((item) => {
@@ -116,6 +114,9 @@ export const useRecipeStore = defineStore('recipe', () => {
}).toArray()
}
if (keyword.value)
result = result.filter(item => item.name.includes(keyword.value))
isSearching.value = false
return result
}

View File

@@ -2,6 +2,6 @@ export const appName = '食用手册'
export const appDescription = '好的,今天我们来做菜!'
export const namespace = 'cook'
export const lastDbUpdated = '2022-07-27 03:05:02'
export const lastDbUpdated = '2023-11-11 19:51:02'
export * from './links'

View File

@@ -296,7 +296,7 @@ BBQ烟熏手撕猪肉,猪肉,BV1DV411x7SH,复杂,,烤,烤箱,
名古屋鸡翅,鸡肉,BV1ET4y1A7Xd,普通,日式,,一口大锅,
日式炖白萝,白萝卜,BV17b411B7H1,简单,日式,,一口大锅,
炸虾天妇罗,,BV1e5411t7LY,困难,日式,,一口大锅,
可乐饼,土豆、洋葱、肉、鸡蛋,BV1yW411Q7sa,普通,日式菜,,一口大锅,
可乐饼,土豆、洋葱、肉、鸡蛋,BV17x411U75q,普通,日式菜,,一口大锅,
清炒莴笋丝,莴笋、胡萝卜,BV1qK411H7RL,简单,爽口,,一口大锅,
莴笋泡菜,莴笋,BV1h741127rS,简单,爽口,泡菜,一口大锅,
口蘑汤,菌菇,BV1e64y1h776,简单,,煎、炖,一口大锅,
@@ -597,3 +597,4 @@ biangbiang面,面食,BV1844y157GL,简单,,油泼,一口大锅,
电饭煲番茄牛肉焖饭,番茄、牛肉、米,BV1Bv411C7X3,普通,,,一口大锅、电饭煲,
电饭煲排骨土豆焖饭,猪肉、土豆、米,BV1Bv411C7X3,普通,,,一口大锅、电饭煲,
米布丁,米、鸡蛋,BV1hr4y1k7A5,简单,,,一口大锅、电饭煲,
麻婆豆腐,豆腐,BV1it4y1X75m,简单,,,一口大锅,
1 name stuff bv difficulty tags methods tools
296 名古屋鸡翅 鸡肉 BV1ET4y1A7Xd 普通 日式 一口大锅
297 日式炖白萝 白萝卜 BV17b411B7H1 简单 日式 一口大锅
298 炸虾天妇罗 BV1e5411t7LY 困难 日式 一口大锅
299 可乐饼 土豆、洋葱、肉、鸡蛋 BV1yW411Q7sa BV17x411U75q 普通 日式菜 一口大锅
300 清炒莴笋丝 莴笋、胡萝卜 BV1qK411H7RL 简单 爽口 一口大锅
301 莴笋泡菜 莴笋 BV1h741127rS 简单 爽口 泡菜 一口大锅
302 口蘑汤 菌菇 BV1e64y1h776 简单 煎、炖 一口大锅
597 电饭煲番茄牛肉焖饭 番茄、牛肉、米 BV1Bv411C7X3 普通 一口大锅、电饭煲
598 电饭煲排骨土豆焖饭 猪肉、土豆、米 BV1Bv411C7X3 普通 一口大锅、电饭煲
599 米布丁 米、鸡蛋 BV1hr4y1k7A5 简单 一口大锅、电饭煲
600 麻婆豆腐 豆腐 BV1it4y1X75m 简单 一口大锅

File diff suppressed because one or more lines are too long

View File

@@ -10,7 +10,7 @@ const route = useRoute()
<main class="text-center text-gray-700 dark:text-gray-200" p="t-5 b-15">
<div flex items-center justify-between>
<BackBtn ml-3 />
<h2 flex items-center justify-center text-lg>
<h2 flex items-center justify-center text-lg font="bold">
{{ route.meta.title }}
</h2>
<DarkToggle mr-3 />

View File

@@ -1,7 +1,8 @@
<template>
<main class="cook-main text-center text-gray-700 dark:text-gray-200" p="t-8 b-$cook-bottom-menu-height">
<slot />
<DarkToggle absolute right-3 top-5 />
<DarkToggle absolute left-3 top-5 />
<SearchRecipe />
<TheBottomMenu fixed bottom-0 left-0 right-0 />
</main>
</template>

View File

@@ -1,6 +1,6 @@
{
"type": "module",
"version": "1.1.9",
"version": "1.2.2",
"private": true,
"packageManager": "pnpm@8.10.2",
"engines": {
@@ -23,10 +23,11 @@
"typecheck": "vue-tsc --noEmit"
},
"dependencies": {
"dayjs": "^1.11.10",
"vue-about-me": "^1.2.7"
},
"devDependencies": {
"@antfu/eslint-config": "^1.1.0",
"@antfu/eslint-config": "^1.1.1",
"@headlessui/vue": "^1.7.16",
"@iconify-json/carbon": "^1.1.21",
"@iconify-json/fe": "^1.1.7",
@@ -35,17 +36,18 @@
"@iconify-json/mdi": "^1.1.55",
"@iconify-json/ri": "^1.1.12",
"@iconify-json/twemoji": "^1.1.12",
"@nuxt/devtools": "^1.0.0",
"@nuxt/devtools": "^1.0.2",
"@nuxtjs/color-mode": "^3.3.0",
"@pinia/nuxt": "^0.5.1",
"@pinia/testing": "^0.1.3",
"@unocss/eslint-config": "^0.57.2",
"@unocss/nuxt": "^0.57.2",
"@vite-pwa/nuxt": "^0.1.1",
"@unocss/eslint-config": "^0.57.3",
"@unocss/nuxt": "^0.57.3",
"@vite-pwa/nuxt": "^0.2.1",
"@vue/test-utils": "^2.4.1",
"@vueuse/nuxt": "^10.5.0",
"@vueuse/nuxt": "^10.6.0",
"@yunlefun/vue": "0.0.8-beta.4",
"@zadigetvoltaire/nuxt-gtm": "^0.0.13",
"bumpp": "^9.2.0",
"consola": "^3.2.3",
"cross-env": "^7.0.3",
"dexie": "^3.2.4",
@@ -58,9 +60,9 @@
"pinia": "^2.1.7",
"sass": "^1.69.5",
"star-markdown-css": "^0.4.2",
"tsx": "^3.14.0",
"tsx": "^4.1.1",
"typescript": "^5.2.2",
"unocss": "^0.57.2",
"unocss": "^0.57.3",
"vitest": "^0.34.6",
"vue-tsc": "^1.8.22"
}

12
pages/recipes/collect.vue Normal file
View File

@@ -0,0 +1,12 @@
<script lang="ts" setup>
definePageMeta({
layout: 'child',
title: '我的收藏',
})
</script>
<template>
<div>
施工中...
</div>
</template>

38
pages/recipes/history.vue Normal file
View File

@@ -0,0 +1,38 @@
<script lang="ts" setup>
import dayjs from 'dayjs'
import { recipeHistories } from '~/composables/store/history'
definePageMeta({
layout: 'child',
title: '历史记录',
})
// todo
// clear one history
function clearAllHistory() {
recipeHistories.value = []
}
</script>
<template>
<div pt-2>
<div
text="blue-900 dark:blue-200"
bg="blue-300 op-20 hover:(blue-800 op-20) dark:hover:(blue-200 op-20)"
class="inline-flex items-center justify-center border border-transparent rounded-md px-4 py-2 text-sm font-medium focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-blue-500"
@click="clearAllHistory"
>
<div i-ri-eraser-line />
<span class="ml-1">清空记录</span>
</div>
<div flex="~ col">
<div v-for="history in recipeHistories" :key="history.recipe.name" mt-2>
<StapleTag :active="false">
{{ dayjs(history.time).format('YYYY-MM-DD HH:mm:ss') }}
</StapleTag>
<DishTag :dish="history.recipe" />
</div>
</div>
</div>
</template>

View File

@@ -13,6 +13,12 @@ import { links } from '~/constants'
px-2
text-left
>
<div mt-2 gap="3" grid="~ cols-3">
<YlfIconItem to="/recipes/history" icon="i-ri-history-line" label="历史记录" />
<YlfIconItem to="/recipes/collect" icon="i-ri-star-line" label="我的收藏" />
<YlfIconItem to="/cookbooks" icon="i-ri-article-line" label="自定义菜谱" />
</div>
<YlfForm>
<YlfFormItem icon="i-ri-feedback-line" label="立即反馈" :to="links.feedback" target="_blank" />
<YlfFormItem icon="i-ri-mail-send-line" label="立即投稿" :to="links.contribute" target="_blank" />
@@ -22,9 +28,9 @@ import { links } from '~/constants'
<YlfFormItem icon="i-ri-settings-line" label="设置" to="/settings" />
</YlfForm>
<YlfForm>
<YlfFormItem icon="i-ri-article-line" label="自定义菜谱" to="/cookbooks/" />
</YlfForm>
<!-- <YlfForm>
<YlfFormItem icon="i-ri-article-line" label="自定义菜谱 TODO" to="/cookbooks/" />
</YlfForm> -->
<YlfForm>
<YlfFormItem icon="i-ri-question-line" label="帮助" to="/help" />

1744
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long