Skip to content

Commit 8daf86f

Browse files
committed
Initial commit
0 parents  commit 8daf86f

292 files changed

Lines changed: 28034 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/CLAUDE.md

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<!--VITE PLUS START-->
2+
3+
# Using Vite+, the Unified Toolchain for the Web
4+
5+
This project is using Vite+, a unified toolchain built on top of Vite, Rolldown, Vitest, tsdown, Oxlint, Oxfmt, and Vite Task. Vite+ wraps runtime management, package management, and frontend tooling in a single global CLI called `vp`. Vite+ is distinct from Vite, but it invokes Vite through `vp dev` and `vp build`.
6+
7+
## Vite+ Workflow
8+
9+
`vp` is a global binary that handles the full development lifecycle. Run `vp help` to print a list of commands and `vp <command> --help` for information about a specific command.
10+
11+
### Start
12+
13+
- create - Create a new project from a template
14+
- migrate - Migrate an existing project to Vite+
15+
- config - Configure hooks and agent integration
16+
- staged - Run linters on staged files
17+
- install (`i`) - Install dependencies
18+
- env - Manage Node.js versions
19+
20+
### Develop
21+
22+
- dev - Run the development server
23+
- check - Run format, lint, and TypeScript type checks
24+
- lint - Lint code
25+
- fmt - Format code
26+
- test - Run tests
27+
28+
### Execute
29+
30+
- run - Run monorepo tasks
31+
- exec - Execute a command from local `node_modules/.bin`
32+
- dlx - Execute a package binary without installing it as a dependency
33+
- cache - Manage the task cache
34+
35+
### Build
36+
37+
- build - Build for production
38+
- pack - Build libraries
39+
- preview - Preview production build
40+
41+
### Manage Dependencies
42+
43+
Vite+ automatically detects and wraps the underlying package manager such as pnpm, npm, or Yarn through the `packageManager` field in `package.json` or package manager-specific lockfiles.
44+
45+
- add - Add packages to dependencies
46+
- remove (`rm`, `un`, `uninstall`) - Remove packages from dependencies
47+
- update (`up`) - Update packages to latest versions
48+
- dedupe - Deduplicate dependencies
49+
- outdated - Check for outdated packages
50+
- list (`ls`) - List installed packages
51+
- why (`explain`) - Show why a package is installed
52+
- info (`view`, `show`) - View package information from the registry
53+
- link (`ln`) / unlink - Manage local package links
54+
- pm - Forward a command to the package manager
55+
56+
### Maintain
57+
58+
- upgrade - Update `vp` itself to the latest version
59+
60+
These commands map to their corresponding tools. For example, `vp dev --port 3000` runs Vite's dev server and works the same as Vite. `vp test` runs JavaScript tests through the bundled Vitest. The version of all tools can be checked using `vp --version`. This is useful when researching documentation, features, and bugs.
61+
62+
## Common Pitfalls
63+
64+
- **Using the package manager directly:** Do not use pnpm, npm, or Yarn directly. Vite+ can handle all package manager operations.
65+
- **Always use Vite commands to run tools:** Don't attempt to run `vp vitest` or `vp oxlint`. They do not exist. Use `vp test` and `vp lint` instead.
66+
- **Running scripts:** Vite+ built-in commands (`vp dev`, `vp build`, `vp test`, etc.) always run the Vite+ built-in tool, not any `package.json` script of the same name. To run a custom script that shares a name with a built-in command, use `vp run <script>`. For example, if you have a custom `dev` script that runs multiple services concurrently, run it with `vp run dev`, not `vp dev` (which always starts Vite's dev server).
67+
- **Do not install Vitest, Oxlint, Oxfmt, or tsdown directly:** Vite+ wraps these tools. They must not be installed directly. You cannot upgrade these tools by installing their latest versions. Always use Vite+ commands.
68+
- **Use Vite+ wrappers for one-off binaries:** Use `vp dlx` instead of package-manager-specific `dlx`/`npx` commands.
69+
- **Import JavaScript modules from `vite-plus`:** Instead of importing from `vite` or `vitest`, all modules should be imported from the project's `vite-plus` dependency. For example, `import { defineConfig } from 'vite-plus';` or `import { expect, test, vi } from 'vite-plus/test';`. You must not install `vitest` to import test utilities.
70+
- **Type-Aware Linting:** There is no need to install `oxlint-tsgolint`, `vp lint --type-aware` works out of the box.
71+
72+
## CI Integration
73+
74+
For GitHub Actions, consider using [`voidzero-dev/setup-vp`](https://github.com/voidzero-dev/setup-vp) to replace separate `actions/setup-node`, package-manager setup, cache, and install steps with a single action.
75+
76+
```yaml
77+
- uses: voidzero-dev/setup-vp@v1
78+
with:
79+
cache: true
80+
- run: vp check
81+
- run: vp test
82+
```
83+
84+
## Review Checklist for Agents
85+
86+
- [ ] Run `vp install` after pulling remote changes and before getting started.
87+
- [ ] Run `vp check` and `vp test` to validate changes.
88+
<!--VITE PLUS END-->

.claude/rules/component.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
description: Guidelines for creating and modifying Vue components.
3+
paths: ["**/*.{vue}"]
4+
---
5+
6+
# Vue Components
7+
8+
## Reuse
9+
10+
Most native HTML elements (`<table>`, `<input>`, `<button>`, `<textarea>`, etc.) have shadcn-vue replacements. Always use the shadcn-vue equivalents instead of raw HTML elements; only fall back to native elements when absolutely necessary.
11+
12+
When creating a new component (especially a reusable one), always check shadcn-vue first for an equivalent component (install it via tooling if needed). If shadcn-vue does not provide one, check reka-ui next and apply custom styles on top. Only build a component from scratch (placed in `components/`) as a last resort.
13+
14+
## Modification
15+
16+
Never modify the source code of components under `components/ui/` (i.e. shadcn-vue components). Override styles at the usage site with `:deep` selectors. For behavioral changes, prefer creating a wrapper component.
17+
18+
## Placement
19+
20+
- **Page-specific components**: Components with no reuse value should NOT be placed in `components/`. Instead, co-locate them alongside the `+Page.vue` or `+Layout.vue` that uses them inside the `pages/` directory.
21+
- **`components/ui/` is reserved for shadcn-vue**: Never place custom components in `components/ui/`. Only shadcn-vue generated components belong there.

.claude/rules/css.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---
2+
description: Styling guidelines for Vue components emphasizing Tailwind CSS v4 utility-first approach.
3+
paths: ["**/*.{vue,css,scss,sass,less}"]
4+
---
5+
6+
# Vue Component Styling Guidelines (Tailwind CSS v4)
7+
8+
## 1. Utility-First Preference
9+
10+
- **Template-Driven Styling:** You **must** prioritize styling elements directly in the `<template>` using Tailwind CSS v4 utility classes.
11+
- **Avoid Style Blocks:** Do not create a `<style>` block unless the styling requirements cannot be reasonably achieved using inline utility classes in the template.
12+
13+
## 2. Managing Vue-Specific Selectors
14+
15+
- **Scoped Styling for Internals:** When you need to style deeply nested child components or injected slot content using Vue's specific pseudo-classes (`:deep()`, `:slotted()`, `:global()`), you are permitted to use a `<style scoped>` block.
16+
17+
## 3. Use of `@apply` and Native CSS
18+
19+
- **Prefer Tailwind utilities in `<template>`.**
20+
- **Scoped `<style>` blocks:** Use `@apply` for deep selectors only if your Tailwind config and main CSS do not break build (see below).
21+
- **Compatibility warning:** If your main CSS (e.g. `tailwind.css`) contains `@apply` rules, using `@reference` in scoped styles may cause build errors (e.g. `Cannot apply unknown utility class 'border-border'`).
22+
- **Fallback:** If `@apply` fails in scoped styles, use native CSS properties instead.
23+
24+
**Example:**
25+
26+
```vue
27+
<template>
28+
<div class="p-4 bg-white rounded-xl shadow-md">
29+
<button class="px-4 py-2 text-white bg-blue-500 rounded hover:bg-blue-600">
30+
Toggle
31+
</button>
32+
<ChildComponent class="custom-wrapper" />
33+
</div>
34+
</template>
35+
36+
<style scoped>
37+
/* Prefer @apply, but use native CSS if build fails */
38+
.custom-wrapper :deep(.child-inner-element) {
39+
/* @apply flex items-center justify-between p-2 mt-4 bg-gray-50 rounded-lg hover:bg-gray-100 transition-colors; */
40+
display: flex;
41+
align-items: center;
42+
justify-content: space-between;
43+
padding: 0.5rem;
44+
margin-top: 1rem;
45+
background-color: #f8fafc;
46+
border-radius: 0.5rem;
47+
transition: background-color 0.2s;
48+
}
49+
</style>
50+
```
51+
52+
## 4. Exceptional Cases for Native CSS
53+
54+
- Use native CSS only for:
55+
- Complex custom animations
56+
- Dynamic `calc()` with injected variables
57+
- CSS features not supported by Tailwind

.claude/rules/i18n.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
---
2+
description: Internationalization (i18n) coding guidelines for Vue components.
3+
paths: ["**/*.{vue,ts}"]
4+
---
5+
6+
# Vue-i18n Coding Guidelines
7+
8+
## 1. Mandatory i18n Usage
9+
10+
- **No Hardcoded Strings:** **Never** hardcode user-facing text (Chinese or otherwise) directly into the `<template>` or `<script setup>`. All display text must be processed through the `vue-i18n` API.
11+
12+
## 2. Setup & Initialization
13+
14+
- **Import Requirement:** Always import `useI18n` from `vue-i18n` in the script block.
15+
- **Instantiation:** Initialize the translation function at the top level of `<script setup lang="ts">`.
16+
17+
```typescript
18+
import { useI18n } from "vue-i18n";
19+
const { t } = useI18n();
20+
```
21+
22+
## 3. Translation Key Convention
23+
24+
- **Natural Language Base (Chinese):** Use the exact Chinese display text as the translation key. Do not use abstract dot-notation keys unless explicitly required by a specific module.
25+
-**Correct:** `t("概念模式")`, `t("上一页")`
26+
-**Incorrect:** `t("glossary.conceptMode")`, `t("pagination.prev")`
27+
28+
## 4. String Interpolation & Formatting
29+
30+
- **Named Variables:** Use curly braces `{}` for dynamic variables within the translation string.
31+
- **Data Object:** Pass the variables as an object in the second argument of the `t()` function.
32+
-**Correct:** `t("{amount} 个术语", { amount: concept.termCount })`
33+
-**Correct (Math/Logic):** `t("显示 {from} - {to} 条,共 {total} 条", { from: pageIndex * pageSize + 1, to: Math.min((pageIndex + 1) * pageSize, total), total: total })`
34+
35+
## 5. Attribute & Prop Localization
36+
37+
- **Dynamic Binding:** When localizing HTML attributes (like `title`, `placeholder`, `alt`) or component props, you must use `v-bind` (e.g., `:title`) and execute the `t()` function.
38+
- **Nested Translations:** If the variables themselves need translation (e.g., dynamic statuses or types), wrap them in `t()` before passing them into the main translation string's data object.
39+
-**Correct:**
40+
41+
```vue
42+
:title="t('类型:{type} | 状态:{status}', { type: t(termItem.type), status:
43+
t(termItem.status) })"
44+
```
45+
46+
## 6. Fallback & Conditional Rendering
47+
48+
- **Inline Fallbacks:** When dealing with potentially undefined data that requires a localized fallback, combine the logical OR `||` operator with `t()`.
49+
-**Correct:** `{{ concept.definition || t("—") }}`
50+
-**Correct:** `{{ concept.subject || t("(未命名)") }}`

.claude/rules/type-safety.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
description: Project context and coding guidelines for AI to follow when generating code or answering questions.
3+
paths: ["**/*.{ts,vue,js}"]
4+
---
5+
6+
# Function Syntax Preference
7+
8+
- **Arrow Functions Only:** **Never** generate `function` declarations or expressions. Always default to arrow functions.
9+
- **Exceptions:** If you firmly believe `function` is strictly required (e.g., for generator functions or specific `this` binding contexts):
10+
1. Stop and re-evaluate the design.
11+
2. Attempt a structural rewrite using arrow functions.
12+
3. Only proceed with `function` if JavaScript/TypeScript semantics make arrow functions impossible.
13+
4. **Mandatory:** You must annotate the reason explicitly in a comment alongside the generated `function`.
14+
15+
# Type Safety Restrictions
16+
17+
- **No Explicit `any`:** **Never** use the explicit `any` type or unsafe type assertions (e.g., `as any`, `as unknown as T`). Strict type safety is mandatory.
18+
- **Exceptions:** If you believe `any` or an unsafe cast is unavoidable:
19+
1. Stop and re-evaluate the type definitions.
20+
2. Attempt to use `unknown`, generics, or proper type narrowing/guards.
21+
3. Only proceed if external library types are inherently broken or strictly demand it.
22+
4. **Mandatory:** You must annotate the reason explicitly in a comment explaining why a safe type cannot be used.

.devcontainer/Dockerfile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
FROM node:24-bookworm
2+
3+
ENV COREPACK_ENABLE_DOWNLOAD_PROMPT=0
4+
ENV SHELL=/bin/bash
5+
6+
RUN corepack enable
7+
8+
ENV PNPM_HOME="/root/.local/share/pnpm"
9+
ENV PATH="${PNPM_HOME}:${PATH}"
10+
11+
RUN pnpm setup \
12+
&& pnpm add --global nx
13+
14+
RUN curl -fsSL https://vite.plus | bash

.devcontainer/devcontainer.json

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
{
2+
"name": "HRecipe",
3+
"build": {
4+
"dockerfile": "Dockerfile"
5+
},
6+
"features": {
7+
"ghcr.io/devcontainers/features/common-utils:2": {
8+
"installZsh": false,
9+
"installOhMyZsh": false,
10+
"installOhMyZshConfig": false,
11+
"upgradePackages": true,
12+
"installSsl": true,
13+
"username": "automatic",
14+
"userUid": "automatic",
15+
"userGid": "automatic"
16+
},
17+
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {
18+
"moby": true,
19+
"installDockerBuildx": true,
20+
"installDockerComposeSwitch": true,
21+
"version": "latest",
22+
"dockerDashComposeVersion": "v2"
23+
},
24+
"ghcr.io/devcontainers/features/git-lfs:1": {
25+
"autoPull": true,
26+
"version": "latest"
27+
},
28+
"ghcr.io/devcontainers/features/github-cli:1": {
29+
"installDirectlyFromGitHubRelease": true,
30+
"version": "latest"
31+
}
32+
},
33+
"customizations": {
34+
"vscode": {
35+
"extensions": [
36+
"Selemondev.shadcn-vue",
37+
"nrwl.angular-console",
38+
"antfu.iconify",
39+
"Vue.volar",
40+
"bradlc.vscode-tailwindcss",
41+
"ms-playwright.playwright",
42+
"oxc.oxc-vscode",
43+
"GitHub.copilot-chat",
44+
"ms-azuretools.vscode-docker",
45+
"ms-azuretools.vscode-containers",
46+
"vitest.explorer",
47+
"VoidZero.vite-plus-extension-pack"
48+
],
49+
"settings": {
50+
"editor.formatOnSave": true,
51+
"editor.defaultFormatter": "oxc.oxc-vscode",
52+
"[json]": {
53+
"editor.defaultFormatter": "oxc.oxc-vscode"
54+
},
55+
"[jsonc]": {
56+
"editor.defaultFormatter": "oxc.oxc-vscode"
57+
},
58+
"editor.codeActionsOnSave": {
59+
"source.fixAll.oxc": "always"
60+
}
61+
}
62+
}
63+
},
64+
"remoteUser": "root",
65+
"postCreateCommand": "pnpm install",
66+
"forwardPorts": []
67+
}

.dockerignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
node_modules
2+
dist
3+
.git
4+
.env
5+
*.db
6+
data/
7+
.agents
8+
.claude
9+
.devcontainer
10+
.github
11+
.pnpm-store
12+
.vscode
13+
uploads/

.env

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# SQLite database file path (absolute or relative to the working directory). Default: ./data/recipes.db
2+
# SQLite 数据库文件路径(绝对路径或相对于工作目录的相对路径)。默认:./data/recipes.db
3+
DATABASE_URL=./data/recipes.db
4+
# Directory for user-uploaded files (absolute or relative to the working directory). Default: ./data/uploads
5+
# 用户上传文件的储存目录(绝对路径或相对于工作目录的相对路径)。默认:./data/uploads
6+
UPLOAD_DIR=./data/uploads
7+
# Maximum upload file size in bytes. Default: 52428800 (50 MB)
8+
# 上传文件的最大大小(单位:字节)。默认:52428800(50 MB)
9+
MAX_FILE_SIZE=52428800
10+
11+
# Title of the application, displayed in the header and page title. Default: HRecipe
12+
# 应用的标题,显示在页面标题和 Header 中。默认:HRecipe
13+
TITLE=HRecipe
14+
15+
# Whether to enable reviews for recipes. Default: true
16+
# 是否启用食谱评论功能。默认:true
17+
REVIEWS_ENABLED=true
18+
19+
# Fallback locale when the user's browser language is not supported. Default: zh-CN
20+
# 当用户的浏览器语言不受支持时使用的回退语言。默认:zh-CN
21+
FALLBACK_LOCALE=zh-CN
22+
# Whether to hide the language switcher in the header (true = infer language from browser only). Default: false
23+
# 是否隐藏前端 Header 中的语言切换器(设为 true 则仅从浏览器环境推断语言)。默认:false
24+
HIDE_LANGUAGE_SWITCHER=false
25+
# Whether to lock the app language to FALLBACK_LOCALE (true = ignore browser language entirely). Default: false
26+
# 是否将应用语言固定为 FALLBACK_LOCALE 指定的语言(设为 true 则完全忽略浏览器语言)。默认:false
27+
FORCE_FALLBACK_LOCALE=false
28+
29+
# Port the application listens on. Default: 3000
30+
# 应用监听的端口。默认:3000
31+
PORT=3000

0 commit comments

Comments
 (0)