11 Commits

Author SHA1 Message Date
YunYouJun
ae6aaba912 chore: release v1.1.4 2023-07-30 21:01:43 +08:00
YunYouJun
b526aae2d0 feat: dynamic import recipe.json 2023-07-30 20:59:52 +08:00
YunYouJun
38b31a5654 fix: adjust user page width 2023-07-30 20:23:40 +08:00
YunYouJun
2db9fee8af feat: add user about page 2023-07-30 20:13:20 +08:00
YunYouJun
44c9631e70 ci: fix upload dir 2023-07-30 18:50:07 +08:00
YunYouJun
a60d5f37ed chore: release v1.1.3 2023-07-30 18:45:26 +08:00
YunYouJun
9cb0ca3c44 fix(test): fake indexedDB 2023-07-30 18:44:40 +08:00
YunYouJun
fffd6e398c chore: show pkg version in footer 2023-07-30 18:37:21 +08:00
YunYouJun
492513098a chore: bumpp 2023-07-30 18:33:36 +08:00
YunYouJun
4ea6b9d1f2 chore: release v1.1.2 2023-07-30 18:32:34 +08:00
YunYouJun
7e6ea7d94b ci: add release action 2023-07-30 18:31:50 +08:00
29 changed files with 369 additions and 1210 deletions

View File

@@ -3,9 +3,8 @@ name: Docker Image
on:
push:
branches: [main]
pull_request:
branches: [main]
tags:
- 'v*'
jobs:
build:

38
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,38 @@
name: Release
on:
push:
tags:
- 'v*'
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Install pnpm
uses: pnpm/action-setup@v2
# after pnpm
- name: Use Node.js 16
uses: actions/setup-node@v3
with:
node-version: 16
registry-url: https://registry.npmjs.org/
cache: pnpm
- name: Install dependencies
run: pnpm install
- run: npm run generate --if-present
- uses: actions/upload-artifact@v3
with:
name: Cook Dist
path: dist/
- run: npx changelogithub # or changelogithub@0.12 if ensure the stable result
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}

View File

@@ -9,6 +9,7 @@
- 网站链接:[cook.yunyoujun.cn](https://cook.yunyoujun.cn)
- 备用:[cook.yyj.moe](https://cook.yyj.moe)
- 开发版:[cook.yunle.app](https://cook.yunle.app)
### 小程序版本

View File

@@ -1,5 +1,6 @@
<script lang="ts" setup>
import { isClient } from '@vueuse/core'
import pkg from '~/package.json'
const displayICP = ref(true)
@@ -17,7 +18,7 @@ const buildDate = (new Date(Number.parseInt(now) * 1000)).toLocaleDateString()
<div p="4 t-2" class="flex flex-col items-center justify-center" text="sm">
<div v-if="commitSha && buildDate" mb-2>
<span>
当前版本{{ buildDate }}:
当前版本 v{{ pkg.version }}{{ buildDate }}:
</span>
<span>
<a border="b-1 dashed" :href="`https://github.com/YunYouJun/cook/commit/${commitSha}`" target="_blank" alt="Cook | GitHub Commit">

View File

@@ -0,0 +1,5 @@
<template>
<h1 text-2xl font="bold" my="4">
<slot />
</h1>
</template>

View File

@@ -1,15 +1,30 @@
<script lang="ts" setup>
const { random, randomRecipe } = useRandomRecipe()
const { count, inc, dec } = useCount()
const { random, randomRecipes } = useRandomRecipe(count)
</script>
<template>
<div v-show="randomRecipe">
<div class="inline-flex items-center justify-center">
<div>今天吃什么</div>
<div class="transition" hover="text-blue-500" i-ri-refresh-line inline-block cursor-pointer @click="random" />
<div inline-flex m="y-3">
<button rounded-full p-2 btn @click="dec()">
<div i-carbon-subtract />
</button>
<div font="mono" w="15" m-auto inline-block>
{{ count }}
</div>
<div m="t-2">
<DishTag v-if="randomRecipe" :dish="randomRecipe" />
<button rounded-full p-2 btn @click="inc()">
<div i-carbon-add />
</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 m="t-8" flex="~ col">
<template v-for="recipe, i in randomRecipes" :key="i">
<DishTag v-if="recipe" :dish="recipe" />
</template>
</div>
</div>
</template>

View File

@@ -3,7 +3,7 @@ import { storeToRefs } from 'pinia'
const rStore = useRecipeStore()
const { displayedRecipe, selectedStuff, curTool } = storeToRefs(rStore)
const { selectedStuff, curTool } = storeToRefs(rStore)
const showSearchInput = ref(false)
@@ -34,6 +34,14 @@ const showTooltip = computed(() => !selectedStuff.value.length && !curTool.value
你要先选食材或工具哦
</span>
<div
v-else-if="rStore.isSearching"
relative flex items-center justify-center p-6
text-xl
>
<div class="magnifying-glass" i-ri-search-line inline-flex />
</div>
<div v-else-if="rStore.displayedRecipe.length">
<DishTag v-for="item, i in rStore.displayedRecipe" :key="i" :dish="item" />
</div>
@@ -55,10 +63,22 @@ const showTooltip = computed(() => !selectedStuff.value.length && !curTool.value
</div>
</div>
</Transition>
<hr m="y-2">
<RandomRecipe />
</div>
</div>
</template>
<style>
@keyframes circle-rotate {
from {
transform: rotate(0turn) translateY(60%) rotate(1turn);
}
to {
transform: rotate(1turn) translateY(60%) rotate(0turn);
}
}
.magnifying-glass {
margin: auto;
animation: circle-rotate 4s linear infinite;
}
</style>

View File

@@ -12,14 +12,14 @@ const items: BottomMenuItem[] = [
{
icon: 'i-ri-compass-2-line',
activeIcon: 'i-ri-compass-2-fill',
title: '关于',
to: '/about',
title: '吃什么',
to: '/random',
},
// {
// icon: 'i-ri-user-line',
// activeIcon: 'i-ri-user-fill',
// title: '我的',
// to: '/user',
// icon: 'i-ri-compass-2-line',
// activeIcon: 'i-ri-compass-2-fill',
// title: '吃什么',
// to: '/about',
// },
{
icon: 'i-ri-question-line',
@@ -27,6 +27,12 @@ const items: BottomMenuItem[] = [
title: '帮助',
to: '/help',
},
{
icon: 'i-ri-user-line',
activeIcon: 'i-ri-user-fill',
title: '我的',
to: '/user',
},
]
const route = useRoute()

View File

@@ -1,10 +1,11 @@
<script lang="ts" setup>
import type { DbRecipeItem } from 'utils/db'
import { tools } from '~/data/food'
import type { RecipeItem } from '~/types'
import { getEmojisFromStuff } from '~/utils'
const props = defineProps<{
dish: RecipeItem
dish: RecipeItem | DbRecipeItem
}>()
const gtm = useGtm()

20
composables/count.ts Normal file
View File

@@ -0,0 +1,20 @@
import { useStorage } from '@vueuse/core'
export function useCount() {
const count = useStorage('count', 5)
function inc() {
count.value += 1
}
function dec() {
if (count.value <= 1)
return
count.value -= 1
}
return {
count,
inc,
dec,
}
}

View File

@@ -5,13 +5,11 @@ export function useIndexedDB() {
const dbUpdated = useStorage(`${namespace}:lastDbUpdated`, lastDbUpdated)
return {
// db,
// initDb,
init: async () => {
const count = await db.recipes.count()
if (!count || dbUpdated.value !== lastDbUpdated) {
await initDb()
dbUpdated.value = lastDbUpdated
initDb()
}
},
}

View File

@@ -1,12 +1,24 @@
import recipeData from '~/data/recipe.json'
import type { RecipeItem, Recipes } from '~/types'
import type { DbRecipeItem } from 'utils/db'
export function useRandomRecipe() {
const randomRecipe = ref<RecipeItem>()
function random() {
randomRecipe.value = generateRandomRecipe(recipeData as Recipes)
/**
* 随机几道菜
* @param total
* @returns
*/
export function useRandomRecipe(total: Ref<number>) {
const randomRecipes = ref<(DbRecipeItem | undefined)[]>([])
async function random() {
const length = await db.recipes.count()
const randomArr = generateRandomArray(length, total.value)
const result = await db.recipes.bulkGet(randomArr)
if (result)
randomRecipes.value = result.filter(item => !!item)
}
watch(total, () => {
random()
})
onMounted(() => {
random()
})
@@ -14,6 +26,6 @@ export function useRandomRecipe() {
return {
random,
randomRecipe,
randomRecipes,
}
}

View File

@@ -1,9 +1,10 @@
import { acceptHMRUpdate, defineStore } from 'pinia'
import { useStorage } from '@vueuse/core'
import { computed, ref } from 'vue'
import { computed, onMounted, ref, watch } from 'vue'
import { useGtm } from '@gtm-support/vue-gtm'
import type { RecipeItem } from 'types'
import type { StuffItem } from '../../data/food'
import { db } from '../../utils/db'
const namespace = 'cook'
@@ -69,25 +70,26 @@ export const useRecipeStore = defineStore('recipe', () => {
curStuff.value.add(name)
}
const isSearching = ref(false)
/**
* 搜索菜谱
* @returns
*/
async function searchRecipes() {
if (keyword.value) {
const result = await db.recipes.filter(item => item.name.includes(keyword.value)).toArray()
return result
}
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') {
return await db.recipes.filter((item) => {
result = await db.recipes.filter((item) => {
const stuffFlag = selectedStuff.value.every(stuff => item.stuff.includes(stuff))
const toolFlag = item.tools.includes(curTool.value)
return curTool.value ? (stuffFlag && toolFlag) : stuffFlag
}).toArray()
}
else if (curMode.value === 'loose') {
return await db.recipes.filter((item) => {
result = await db.recipes.filter((item) => {
const stuffFlag = selectedStuff.value.some(stuff => item.stuff.includes(stuff))
const toolFlag = Boolean(item.tools?.includes(curTool.value))
@@ -107,12 +109,15 @@ export const useRecipeStore = defineStore('recipe', () => {
}
// survival
else {
return await db.recipes.filter((item) => {
result = await db.recipes.filter((item) => {
const stuffFlag = item.stuff.every(stuff => selectedStuff.value.includes(stuff))
const toolFlag = item.tools?.includes(curTool.value)
return Boolean(curTool.value ? (stuffFlag && toolFlag) : stuffFlag)
}).toArray()
}
isSearching.value = false
return result
}
// 默认严格模式
@@ -158,6 +163,8 @@ export const useRecipeStore = defineStore('recipe', () => {
curMode,
selectedStuff,
isSearching,
clearKeyWord: () => { keyword.value = '' },
toggleStuff,
toggleTools,

View File

@@ -1,64 +0,0 @@
---
title: 关于
---
:AboutMenu
### **🍜 好的,今天我们来做菜!**
> 希望大家吃的开心!
<div class="inline-flex justify-center items-center">
- 代码仓库:<a class="inline-flex items-center justify-center" href="https://github.com/YunYouJun/cook" target="_blank">
<div m="r-1" inline-flex i-ri-github-line></div>YunYouJun/cook</a>
</div>
<br />
<div class="inline-flex justify-center items-center">
- 菜谱主要视频来源:
<a class="inline-flex items-center text-sm text-blue-600 dark:text-blue-400" href="https://docs.qq.com/sheet/DQk1vdkhFV0twQVNS" target="_blank">
<div m="r-1" inline-flex i-ri-bilibili-line></div>
<span class="inline-flex">隔离食用手册大全</span>
</a>
</div>
相关使用请查看 <router-link to="/help">帮助</router-link>。
## **致谢**
感谢以下小伙伴为本项目提供的数据支持和 QA
- [Runny](https://weibo.com/runny)
- 山竹太凉
- leo
- 麒麟
- 晴方啾
- 课代表阿伟
## **关于我**
Hello我是云游君。
很高兴能在这里与你相遇,也很希望这个网站可以真的帮助到你。
同时,我也以我或许不值一提的脸面保证它会以免费开源的形式维护运营下去。
此外,我也会继续尝试做一些有趣或有用的东西,并分享给大家。
你也可以在这些地方找到我。
:AboutMe
对了,给微信公众号「云游君」发送「做菜」也可以快速找到这个网址。
## 赞助者
也非常感谢至今以来的所有赞助者们!
如果觉得我的[小项目们](https://sponsors.yunyoujun.cn/projects)还算有趣的话,要不要考虑[赞助](https://sponsors.yunyoujun.cn/)我?
我会将其公开在[账簿](https://sponsors.yunyoujun.cn/account)中并投入在周边的服务器、域名、CDN 等费用上。
<a href="https://sponsors.yunyoujun.cn" target="_blank">
<img src='https://sponsors.yunyoujun.cn/sponsors.svg'/>
</a>

View File

@@ -1,7 +0,0 @@
---
title: 微信公众号
---
我的个人微信公众号「云游君」,会分享一些生活和写的[小玩具们](https://sponsors.yunyoujun.cn/projects)。
![微信公众号 - 云游君](https://cdn.jsdelivr.net/gh/YunYouJun/cdn/img/about/white-qrcode-and-search.jpg)

View File

@@ -1,5 +1,5 @@
<template>
<main class="text-center text-gray-700 dark:text-gray-200" p="b-15">
<main class="text-center text-gray-700 dark:text-gray-200" p="x-2 t-8 b-15">
<slot />
<DarkToggle absolute right-5 top-5 />
<TheBottomMenu fixed bottom-0 left-0 right-0 />

View File

@@ -15,7 +15,6 @@ export default defineNuxtConfig({
'@pinia/nuxt',
'@nuxtjs/color-mode',
'@vite-pwa/nuxt',
'@nuxt/content',
'@zadigetvoltaire/nuxt-gtm',

View File

@@ -1,6 +1,6 @@
{
"private": true,
"version": "1.1.1",
"version": "1.1.4",
"packageManager": "pnpm@8.6.10",
"engines": {
"node": ">=14"
@@ -16,7 +16,7 @@
"lint": "eslint .",
"postinstall": "nuxi prepare && npm run convert",
"preview-https": "serve dist",
"release": "bumpp --commit --push --tag",
"release": "bumpp",
"test": "vitest",
"typecheck": "vue-tsc --noEmit"
},
@@ -33,7 +33,6 @@
"@iconify-json/mdi": "^1.1.53",
"@iconify-json/ri": "^1.1.10",
"@iconify-json/twemoji": "^1.1.11",
"@nuxt/content": "^2.7.2",
"@nuxt/devtools": "^0.7.1",
"@nuxtjs/color-mode": "^3.3.0",
"@pinia/nuxt": "^0.4.11",
@@ -49,6 +48,7 @@
"cross-env": "^7.0.3",
"dexie": "^3.2.4",
"eslint": "^8.46.0",
"fake-indexeddb": "^4.0.2",
"jsdom": "^22.1.0",
"nuxt": "^3.6.5",
"pinia": "^2.1.6",

View File

@@ -1,9 +0,0 @@
<template>
<main class="markdown-body px-4 text-left">
<ContentDoc v-slot="{ doc }">
<h1>{{ doc.title }}</h1>
<ContentRenderer :value="doc" />
</ContentDoc>
</main>
<BaseFooter />
</template>

View File

@@ -1,8 +1,8 @@
<template>
<div class="w-full px-2 pt-8">
<h1 text-2xl font="bold" my="4">
<div class="w-full">
<CommonHeader>
帮助
</h1>
</CommonHeader>
<InstallPwa />
@@ -26,6 +26,9 @@
<FAQItem title="是否有微信小程序?">
因不可抗力小程序因跳转 B 站视频而被判定为导流违规下架
将不再提供小程序版本
<br>
<br>
搜索微信公众号<b>云游君</b>并发送<b>做菜</b>也可以快速找到本网站
</FAQItem>
<FAQItem title="是否有 APP?">
@@ -36,6 +39,21 @@
你可以使用浏览器打开点击上方的<b>安装到桌面</b>或在菜单中点击<b>添加到主屏幕</b>
</FAQItem>
<FAQItem title="未来是否会收费?">
该项目将以免费开源的形式运营
<br>
您可以考虑赞助本项目以支持我们的开发
我会将其投入在周边的服务器域名CDN 等费用上
<ul mt-1>
<li>
<a href="https://afdian.net/a/yunyoujun" target="_blank">爱发电赞助</a>
</li>
<li>
<a href="https://sponsors.yunyoujun.cn/" target="_blank">我要直接打钱</a>
</li>
</ul>
</FAQItem>
<FAQItem title="页面无法点击、资源加载失败?">
<blockquote>
试试无痕模式是否正常
@@ -62,35 +80,6 @@
</li>
</ol>
</FAQItem>
<FAQItem title="其他相关链接">
<ul>
<li>
相关链接
<ul>
<li>
<a href="https://docs.qq.com/form/page/DWk9GWW9oTmlXZU9V" target="_blank">居家菜谱投稿</a>
</li>
<li>
<a href="https://support.qq.com/products/507827" target="_blank">反馈建议分享兔小巢</a>
</li>
</ul>
</li>
<li>
网站相关
<ul>
<li>
故障/新功能反馈
<a href="https://github.com/YunYouJun/cook/issues" target="_blank">Issues</a>
</li>
<li>
交流/建议/分享
<a href="https://github.com/YunYouJun/cook/issues" target="_blank">Discussions</a>
</li>
</ul>
</li>
</ul>
</FAQItem>
</div>
</div>
<BaseFooter mt-4 />

View File

@@ -3,7 +3,7 @@ const rStore = useRecipeStore()
</script>
<template>
<div pt-4 text-4xl>
<div text-4xl>
<button
class="cursor-pointer transition active:text-green-800 hover:(text-green-600)"
title="重置"
@@ -16,5 +16,6 @@ const rStore = useRecipeStore()
<p text="sm" m="b-4">
好的今天我们来做菜
</p>
<ChooseFood />
</template>

10
pages/random.vue Normal file
View File

@@ -0,0 +1,10 @@
<template>
<div flex flex-col>
<CommonHeader>
今天吃什么
</CommonHeader>
<div flex flex-grow flex-col items-center justify-center>
<RandomRecipe />
</div>
</div>
</template>

View File

@@ -1,7 +1,85 @@
<template>
<div>
<button>
<div i-ri-user-line />
</button>
<div px-2>
<CommonHeader>
我的
</CommonHeader>
<FeedbackActions />
<div class="mx-auto max-w-md w-full rounded-2xl p-2" text-left>
<p my-6 text-left text-base>
很高兴能在这里与你相遇也很希望这个网站可以真的帮助到你
</p>
<FAQItem title="关于">
<div text-left>
<ul>
<li>
<div class="inline-flex items-center justify-center">
代码仓库<a class="inline-flex items-center justify-center" href="https://github.com/YunYouJun/cook" target="_blank">
<div m="r-1" i-ri-github-line inline-flex />YunYouJun/cook</a>
</div>
</li>
<li>
<div class="inline-flex items-center justify-center">
菜谱视频来源
<a class="inline-flex items-center text-sm text-blue-600 dark:text-blue-400" href="https://docs.qq.com/sheet/DQk1vdkhFV0twQVNS" target="_blank">
<div m="r-1" i-ri-bilibili-line inline-flex />
<span class="inline-flex">隔离食用手册大全</span>
</a>
</div>
</li>
</ul>
</div>
</FAQItem>
<FAQItem title="关于我">
<div text-left>
我的个人微信公众号云游君会分享一些生活和写的<a href="https://sponsors.yunyoujun.cn/projects" target="_blank">
小玩具们
</a>
<a inline-flex py-4 href="https://cdn.yunyoujun.cn/img/about/white-qrcode-and-search.jpg" target="_blank">
<img src="https://cdn.yunyoujun.cn/img/about/white-qrcode-and-search.jpg">
</a>
</div>
<AboutMe />
</FAQItem>
<FAQItem title="致谢">
<p>
感谢以下小伙伴为本项目提供的数据支持和 QA
</p>
<ul mt-2 text-left text-sm>
<li>
<a href="https://weibo.com/runny" target="_blank">Runny</a>
</li>
<li>
山竹太凉
</li>
<li>
leo
</li>
<li>
麒麟
</li>
<li>
晴方啾
</li>
<li>
课代表阿伟
</li>
</ul>
</FAQItem>
<FAQItem title="赞助者们">
<a href="https://sponsors.yunyoujun.cn" target="_blank">
<img src="https://sponsors.yunyoujun.cn/sponsors.svg">
</a>
</FAQItem>
</div>
<BaseFooter mt-4 />
</div>
</template>

1092
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

3
test/setup.ts Normal file
View File

@@ -0,0 +1,3 @@
import indexeddb from 'fake-indexeddb'
globalThis.indexedDB = indexeddb

View File

@@ -20,8 +20,8 @@ tools.forEach((item) => {
export default defineConfig({
shortcuts: [
['tag', 'text-sm cursor-pointer inline-flex justify-center items-center transition shadow hover:shadow-md'],
['btn', 'text-sm px-4 py-1 rounded inline-block bg-green-600 text-white cursor-pointer hover:bg-green-700 disabled:cursor-default disabled:bg-gray-600 disabled:opacity-50'],
['icon-btn', 'text-[0.9em] inline-block cursor-pointer select-none opacity-75 transition duration-200 ease-in-out hover:opacity-100 hover:text-green-600'],
['btn', 'text-sm px-4 py-1 rounded inline-block bg-blue-600 text-white cursor-pointer hover:bg-blue-700 disabled:cursor-default disabled:bg-gray-600 disabled:opacity-50'],
['icon-btn', 'text-[0.9em] inline-block cursor-pointer select-none opacity-75 transition duration-200 ease-in-out hover:opacity-100 hover:text-blue-600'],
],
presets: [
presetUno(),
@@ -36,12 +36,4 @@ export default defineConfig({
transformerVariantGroup(),
],
safelist,
content: {
pipeline: {
include: [
'./**/*.vue',
'./content/**/*.md',
],
},
},
})

View File

@@ -1,7 +1,6 @@
import type { Table } from 'dexie'
import Dexie from 'dexie'
import recipeData from '../data/recipe.json'
import type { RecipeItem } from '~/types'
export interface DbRecipeItem extends RecipeItem {
@@ -21,8 +20,10 @@ export class MySubClassedDexie extends Dexie {
export const db = new MySubClassedDexie()
export function initDb() {
db.recipes.bulkPut(
export async function initDb() {
const { default: recipeData } = await import('../data/recipe.json')
return db.recipes.bulkPut(
(recipeData as RecipeItem[]).map((item, i) => ({
id: i,
...item,

View File

@@ -1,10 +1,17 @@
import type { Recipes } from '../types'
/**
* 生成随机菜谱
* 生成随机数组
* @param recipes
* @returns
*/
export function generateRandomRecipe(recipes: Recipes) {
return recipes[Math.floor(Math.random() * recipes.length)]
export function generateRandomArray(length: number, total = 1) {
const randomArr: number[] = []
for (let i = 0; i < total; i++) {
const randomIndex = Math.floor(Math.random() * length)
if (randomArr.includes(randomIndex)) {
i--
continue
}
randomArr.push(randomIndex)
}
return randomArr
}

View File

@@ -7,5 +7,7 @@ export default defineConfig({
deps: {
inline: ['@vue', '@vueuse', 'vue-demi'],
},
setupFiles: ['test/setup.ts'],
},
})