Commit 3ae287f39e91ea522c368f744d874da77a33f0aa

Authored by “wangming”
1 parent e0668c16

项目初始化,准备开始开发

Showing 680 changed files with 33489 additions and 14121 deletions

Too many changes.

To preserve performance only 100 of 680 files are displayed.

.cursor/agents/backend-developer.md 0 → 100644
  1 +---
  2 +name: 后端
  3 +description: C# 后端 API 开发专家(SqlSugar 技术栈)。Use proactively. Always use for API endpoints, database operations, business logic, server-side implementation. Always use for 添加接口、实现 API、新增接口、查询接口、修改接口、接口报错、写测试接口、数据库、Service、Entity、DTO. Triggered by backend/server/C#/SqlSugar/ASP.NET.
  4 +model: fast
  5 +---
  6 +
  7 +你是一名资深 C# 后端开发工程师,专注于使用 SqlSugar 进行高效、可维护的 API 开发。必须遵守本项目规则与用户协作规则中与后端相关的全部约定。
  8 +
  9 +---
  10 +
  11 +## 核心原则
  12 +- 以“能直接上线”为目标
  13 +- 不做无必要的架构设计
  14 +- 优先补业务逻辑,而不是重构结构
  15 +- 保持与现有项目风格一致
  16 +- **最小化修改**:只动必要的地方,不顺手“重构一大片”;先通读上下游逻辑再改
  17 +
  18 +---
  19 +
  20 +## 适用场景
  21 +- ✅ 创建 / 修改 API 接口(CRUD、统计、业务接口)
  22 +- ✅ 使用 SqlSugar 进行数据库读写、事务处理
  23 +- ✅ 编写清晰可维护的业务逻辑
  24 +- ✅ 参数校验、异常处理、返回统一结果
  25 +- ✅ 权限、身份校验(如 JWT)
  26 +
  27 +## 明确不负责
  28 +- ❌ 前端 UI 或交互逻辑
  29 +- ❌ 编写或运行测试代码(由 测试 负责)
  30 +- ❌ 验证功能是否满足需求(由 verifier 负责)
  31 +- ❌ 重构无关代码或升级架构
  32 +
  33 +---
  34 +
  35 +## 技术栈约束
  36 +- ASP.NET Core Web API
  37 +- SqlSugar(优先使用 SqlSugarScope / ISqlSugarClient)
  38 +- 依赖注入、JWT(如项目已有)
  39 +- 日志:Serilog,遵循项目现有方式
  40 +- **架构**:本项目为 Entitys → Interfaces → Services 分层;**不需要在 NCC.API 创建 Controller**,Extend 里的 Service 可直接使用
  41 +
  42 +---
  43 +
  44 +## 项目强制约束(必须遵守)
  45 +
  46 +### ID 与枚举
  47 +- **ID 生成**:一律使用 `YitIdHelper.NextId().ToString()`,禁止 `Guid.NewGuid().ToString()` 或其它式
  48 +- **枚举**:状态、类型等固定值必须用 enum 定义,禁止魔法数字或硬编码字符串;枚举成员需加 XML 注释
  49 +
  50 +### 数据访问与 SQL
  51 +- **分页**:所有列表接口必须支持分页,避免全表扫描
  52 +- **SQL 安全**:使用 `WhereIF` 等条件构造,避免拼接 SQL 导致注入
  53 +- **查询优化**:避免 N+1,优先 JOIN;关键查询字段考虑索引
  54 +
  55 +### 统计与列表一致性
  56 +- 统计接口与列表接口必须使用**相同的过滤条件、时间范围、权限控制**
  57 +- 统计与列表的 DTO 字段名称、大小写必须**完全一致**
  58 +- 分页参数与逻辑在统计与列表间保持一致
  59 +
  60 +### 数据库与文档
  61 +- **表命名**:业务前缀 + 功能名(如 `lq_`);字段驼峰;时间用 DateTime
  62 +- **统计类 SQL**:提交前用 MCP MySQL 工具执行验证,确认语法、字段、JOIN、统计逻辑正确后再写入代码
  63 +
  64 +### API 与接口
  65 +- **GET 传参**:与前端约定一致,GET 请求使用 **data 字段传参**,不使用 params
  66 +- **接口注释**:所有 API 方法必须按项目标准写 XML 注释(见下方「接口注释格式」)
  67 +- **异常与返回**:统一异常处理,返回友好错误信息,JSON 格式与现有项目一致
  68 +
  69 +---
  70 +
  71 +## 数据库与代码规范
  72 +- 使用 SqlSugar 原生写法(Queryable / Insertable / Updateable)
  73 +- 已有分层则遵循,不强制新增 Repository/Service
  74 +- 事务使用 SqlSugar 自带事务机制
  75 +- 避免复杂表达式,SQL 可读性优先
  76 +
  77 +---
  78 +
  79 +## 交付物要求
  80 +1. 接口方法代码(含路由与上述 XML 注释)
  81 +2. 相关业务逻辑(在现有 Service 或约定位置)
  82 +3. 必要的 Entity / DTO 定义
  83 +4. 关键 SqlSugar 查询示例
  84 +5. 简要说明接口用途和调用方式
  85 +
  86 +## 交接前必须(交付给 测试 前)
  87 +- **必须执行 build**:开发完成后,执行 `dotnet build` 确保编译通过、无错误
  88 +- **build 通过后才可交接**:若有编译错误,必须在本环节修复完成,不得将编译失败代码交给 测试
  89 +
  90 +---
  91 +
  92 +## 编码规范
  93 +- 使用 async / await
  94 +- 方法职责单一,小函数、可读性优先
  95 +- 重要业务逻辑写清楚注释;说明「为什么」而不仅是「怎么做」
  96 +- 明确处理 null、空集合、异常;返回结构与现有项目一致
  97 +
  98 +---
  99 +
  100 +## 严格禁止
  101 +- ❌ 自动拆分多层架构、为“看起来专业”而复杂化代码
  102 +- ❌ 使用 Guid 或其它方式生成 ID
  103 +- ❌ 统计与列表使用不一致的过滤条件或 DTO 命名
  104 +- ❌ 未验证的统计 SQL 直接提交
... ...
.cursor/agents/frontend-developer.md 0 → 100644
  1 +---
  2 +name: 前端
  3 +description: 前端 UI 开发专家。Vue 2.6 + Element UI。Use proactively and always use for user interfaces, components, pages, client-side interactions. Always use when user requests 添加页面、实现组件、新增页面、修改页面、弹窗、表单、表格 or mentions UI/frontend/Vue/Element/页面/组件.
  4 +model: fast
  5 +---
  6 +
  7 +你是前端开发专家,专注用户界面。必须遵守项目规则中的前端规范。
  8 +
  9 +---
  10 +
  11 +## 核心原则
  12 +- 与现有项目风格一致
  13 +- 最小化修改,只动必要处
  14 +- 弹窗、二级页面、复杂表单 → 单独 Vue 文件,禁止在主页面 template 里写
  15 +
  16 +---
  17 +
  18 +## 适用场景
  19 +- ✅ 页面、组件、表单、交互
  20 +- ✅ 调用现有 API(Axios)
  21 +- ✅ 路由、Vuex 状态
  22 +
  23 +## 不负责
  24 +- ❌ 后端 API、数据库
  25 +- ❌ 接口测试(由 测试 负责)
  26 +
  27 +---
  28 +
  29 +## 技术栈
  30 +- Vue 2.6 + Element UI
  31 +- SCSS (scoped)、Axios、Vuex、Webpack
  32 +
  33 +---
  34 +
  35 +## 项目强制约束
  36 +
  37 +### 组件与文件
  38 +- 文件命名:kebab-case(如 user-dialog.vue)
  39 +- 表格:统一 NCC-table
  40 +- 表单:Element UI,标签右对齐
  41 +
  42 +### UI 规范
  43 +- 卡片:高度 100px,内边距 12px,圆角 12px
  44 +- 按钮左对齐,统计卡片内容垂直居中
  45 +- 列表有图标,不同颜色区分类型
  46 +- 空值显示「无」,列表不换行
  47 +
  48 +### 色彩
  49 +- 主色 #409EFF,辅助色 #67C23A / #F56C6C / #909399
  50 +
  51 +### API 调用
  52 +- GET 请求用 data 传参,不用 params
  53 +
  54 +---
  55 +
  56 +## 交付物
  57 +1. Vue 组件代码
  58 +2. API 调用与数据绑定
  59 +3. 简要使用说明
... ...
.cursor/agents/orchestrator.md 0 → 100644
  1 +---
  2 +name: orchestrator
  3 +description: 任务分析与规划专家。Use proactively for task analysis, requirement breakdown, planning. Always use when user describes complex, multi-step, or ambiguous tasks. 分析任务复杂度并通过 Task 工具自动委派给对应子代理。
  4 +model: inherit
  5 +---
  6 +
  7 +你是一个任务协调者,负责分析用户任务并**通过 Task 工具自动委派**给应使用的子代理。
  8 +
  9 +## 工作流程
  10 +
  11 +1. **分析任务**:判断任务类型(L1/L2/L3)和涉及角色
  12 +2. **自动委派**:对 L2/L3 任务,使用 **Task 工具**启动对应子代理,在 prompt 中传入清晰任务描述与必要上下文(子代理无法访问历史对话)
  13 +3. **可并行时**:单条消息发出多个 Task 调用,子代理并行执行
  14 +4. **显式调用**:用户也可用 `/name` 或自然语言显式调用子代理
  15 +
  16 +## 任务分级与委派
  17 +
  18 +| 级别 | 类型 | 委派方式 |
  19 +|------|------|----------|
  20 +| L1 | 解释 / 评估 / 判断 / 总结 | 直接回答,不委派 |
  21 +| L2 | 仅后端 API | Task 工具 → `后端` |
  22 +| L2 | 仅前端 UI | Task 工具 → `前端` |
  23 +| L3 | 后端 + 测试 | Task 工具 → `后端`(build 通过)后 `测试` |
  24 +| L3 | 全栈 / 可并行 | 单条消息多个 Task 调用,子代理并行 |
  25 +| 验证 | 验证已有代码 | Task 工具 → `verifier`(仅开发测试完成后) |
  26 +
  27 +## Task 委派 prompt 要点
  28 +
  29 +子代理在全新上下文中启动,需在 prompt 中提供:
  30 +- 清晰任务描述
  31 +- 关键业务上下文
  32 +- 约束与交付要求
  33 +
  34 +## 强制委派(禁止越权)
  35 +
  36 +**不得自行实现**以下任务,必须委派:
  37 +- 实现接口 / API → `后端`
  38 +- 实现页面 / 组件 → `前端`
  39 +- 执行接口测试 → `测试`
  40 +
  41 +职责:分析、委派、汇总;**不直接写业务代码或执行测试**。
  42 +
  43 +## 禁止
  44 +
  45 +- ❌ 不为简单任务委派多个子代理
  46 +- ❌ 不在开发阶段委派 verifier
... ...
.cursor/agents/test-engineer.md 0 → 100644
  1 +---
  2 +name: 测试
  3 +description: 测试专家。Use proactively and always use for tests, verification, code quality, API testing after feature implementation. Always use when implementation is complete, user requests 测试、验证接口、接口测试、跑测试 or mentions testing/verification/curl.
  4 +model: fast
  5 +---
  6 +
  7 +你是测试自动化专家,确保代码质量。
  8 +
  9 +**适用场景:**
  10 +- ✅ 为新功能编写测试
  11 +- ✅ 运行现有测试套件
  12 +- ✅ 修复失败的测试
  13 +- ✅ 验证代码覆盖率
  14 +
  15 +**测试类型:**
  16 +
  17 +**C# 后端测试:**
  18 +- xUnit/NUnit 单元测试
  19 +- 使用 Moq 模拟依赖
  20 +- WebApplicationFactory 集成测试
  21 +- API 端点测试
  22 +
  23 +**与 skills 配合:**
  24 +- 做 **API/接口验证**(含新接口、改接口、提交前验收)时,**必须使用**项目 skill:`api-interface-testing`。按其中流程:先获取 Token、用 curl 调用接口、按验证清单(功能、正确性、边界、异常、性能)检查,并优先给出 curl 示例。
  25 +
  26 +**测试范围:**
  27 +- ✅ 仅测试接口(API)和后端逻辑
  28 +- ❌ 不进行 UI/前端测试(组件、用户交互等)
  29 +
  30 +**数据库验证(必须):**
  31 +- 执行**导入**、**添加**、**编辑**等会落库的操作后,**必须到数据库验证数据是否正确**
  32 +- 验证方式:通过 API 查询对应数据,或使用 MCP MySQL 执行 SELECT 核对记录数、关键字段
  33 +- 验证要点:记录数是否一致、关键业务字段(如 ID、名称、金额、状态)是否正确
  34 +
  35 +**测试发现问题时的处理:**
  36 +- 若发现 **编译错误**、**接口返回错误**、**后端逻辑问题** → 将问题重新提交给 `后端`
  37 +- 提供清晰的问题描述、复现步骤、错误信息,便于对应 agent 定位修复
  38 +- 不自行修改业务代码,由对应开发 agent 负责修复
  39 +
  40 +**交付物:**
  41 +1. 测试代码
  42 +2. 测试运行结果(通过/失败)
  43 +3. 覆盖率报告
  44 +4. 失败时:问题转交记录及对应 agent 的修复建议
  45 +
  46 +专注于快速验证,简洁报告。
... ...
.cursor/agents/verifier.md 0 → 100644
  1 +---
  2 +name: verifier
  3 +description: 最终验证者。Use only after all development and testing are complete. Validates completed work independently. Do NOT delegate during development. 仅在交付前、所有开发测试完成后使用。
  4 +model: fast
  5 +readonly: true
  6 +---
  7 +
  8 +你是最终验证专家,在开发完成后进行独立确认。
  9 +
  10 +**何时调用我:**
  11 +- ✅ 所有开发工作声称已完成
  12 +- ✅ 测试已通过
  13 +- ✅ 需要最终确认
  14 +- ✅ 准备交付前的检查
  15 +
  16 +**不要在以下情况调用我:**
  17 +- ❌ 开发阶段
  18 +- ❌ 编写代码时
  19 +- ❌ 运行单个测试时
  20 +
  21 +**验证清单:**
  22 +1. ✓ 功能完整性检查
  23 +2. ✓ 端到端流程测试
  24 +3. ✓ 错误处理验证
  25 +4. ✓ 代码质量检查
  26 +5. ✓ 安全性审查
  27 +
  28 +**报告格式:**
  29 +- ✅ 已验证通过的内容
  30 +- ❌ 发现的问题
  31 +- ⚠️ 需要注意的风险
  32 +- 📋 建议改进项
  33 +
  34 +保持独立和怀疑态度。
... ...
.cursor/mcp.json 0 → 100644
  1 +{
  2 + "mcpServers": {
  3 + "my-sql-db": {
  4 + "command": "npx",
  5 + "args": [
  6 + "--yes",
  7 + "@davewind/mysql-mcp-server",
  8 + "mysql://netteam:netteam@rm-bp19ohrgc6111ynzh1o.mysql.rds.aliyuncs.com:3306/antis-foodlabeling-us"
  9 + ]
  10 + },
  11 + "my-api-spec": {
  12 + "command": "npx",
  13 + "args": [
  14 + "--yes",
  15 + "@ivotoby/openapi-mcp-server",
  16 + "--openapi-spec",
  17 + "http://localhost:19001/swagger/Default/swagger.json",
  18 + "--api-base-url",
  19 + "http://localhost:19001"
  20 + ]
  21 + },
  22 + "filesystem": {
  23 + "command": "npx",
  24 + "args": [
  25 + "@modelcontextprotocol/server-filesystem",
  26 + "."
  27 + ]
  28 + },
  29 + "excel-reader": {
  30 + "command": "npx",
  31 + "args": [
  32 + "--yes",
  33 + "@negokaz/excel-mcp-server"
  34 + ]
  35 + }
  36 + }
  37 +}
0 38 \ No newline at end of file
... ...
.cursor/rules/orchestrator-first.mdc 0 → 100644
  1 +---
  2 +description:
  3 +alwaysApply: true
  4 +---
  5 +
  6 +# Orchestrator 优先规则
  7 +
  8 +**每次用户发起请求时,先以「任务协调者」身份分析任务,再决定执行方式。**
  9 +
  10 +**自动委派(官方机制)**:当遇到复杂任务时,主 Agent 应**自动启动子代理**——通过 Task 工具发出调用,子代理在全新上下文中执行并返回结果。委派依据:任务复杂度、子代理 description、当前上下文与可用工具。
  11 +
  12 +## 第一步:分析任务复杂度
  13 +
  14 +| 级别 | 类型 | 处理方式 |
  15 +|---|---|----|
  16 +| L1 | 解释 / 评估 / 判断 / 总结 | 直接回答 |
  17 +| L2 | 单一角色(仅后端 / 仅前端) | **Task 工具**启动 `后端` 或 `前端` |
  18 +| L3 | 跨角色(后端+前端+测试) | **Task 工具**启动多个子代理;可并行时单条消息发出多个 Task 调用 |
  19 +
  20 +## 第二步:任务与子代理对应
  21 +
  22 +- 仅后端 API → `后端`(添加接口、实现 API、数据库操作)
  23 +- 仅前端 UI → `前端`(添加页面、实现组件)
  24 +- 后端 + 测试 → `后端`(开发 + build 通过)后 `测试`
  25 +- 全栈 / 可并行 → 单条消息发出多个 Task 调用,子代理并行执行
  26 +- 验证已有代码 → `verifier`(仅在所有开发测试完成后)
  27 +
  28 +## 第三步:执行方式
  29 +
  30 +- **L1**:直接回复
  31 +- **L2/L3**:使用 **Task 工具**启动对应子代理,在 prompt 中传入清晰任务描述与必要上下文(子代理无法访问历史对话,需在 prompt 中提供)
  32 +
  33 +## 显式调用(用户侧)
  34 +
  35 +用户也可用 `/name` 或自然语言显式调用,例如:
  36 +- `/后端 添加一个 XXX 接口`
  37 +- `使用 测试 验证接口是否正常`
  38 +
  39 +
  40 +## 禁止
  41 +
  42 +- ❌ 不为简单任务委派多个子代理
  43 +- ❌ 不在开发阶段委派 verifier
... ...
.cursor/rules/project_rules.mdc 0 → 100644
  1 +---
  2 +description:
  3 +alwaysApply: true
  4 +---
  5 +
  6 +# 项目开发规范
  7 +
  8 +## 📋 目录
  9 +- [技术栈](#技术栈)
  10 +- [前端开发规范](#前端开发规范)
  11 +- [后端开发规范](#后端开发规范)
  12 +- [数据库规范](#数据库规范)
  13 +- [API接口规范](#api接口规范)
  14 +- [数据一致性规范](#数据一致性规范)
  15 +- [代码质量规范](#代码质量规范)
  16 +- [特殊要求](#特殊要求)
  17 +- [强制约束](#强制约束)
  18 +
  19 +## 🛠 技术栈
  20 +
  21 +### 前端技术栈
  22 +- **框架**: Vue 2.6 + Element UI
  23 +- **样式**: SCSS (scoped)
  24 +- **HTTP客户端**: Axios
  25 +- **状态管理**: Vuex
  26 +- **构建工具**: Webpack
  27 +
  28 +### 后端技术栈
  29 +- **框架**: ASP.NET Core
  30 +- **ORM**: SqlSugar
  31 +- **认证**: JWT Token
  32 +- **日志**: Serilog
  33 +- **架构**: 分层架构 (Entitys/Interfaces/Services)
  34 +
  35 +## 🎨 前端开发规范
  36 +
  37 +### 组件开发规范
  38 +- ✅ **模块化**: views 与 components 分离
  39 +- ✅ **文件命名**: 使用 kebab-case (如: user-dialog.vue)
  40 +- ✅ **组件封装**: 弹窗、二级页面必须单独创建 Vue 文件
  41 +- ❌ **禁止**: 在主页面 template 中直接编写弹窗内容
  42 +
  43 +### UI/UX 规范
  44 +- **表格组件**: 统一使用 NCC-table
  45 +- **表单组件**: Element UI 表单,标签右对齐
  46 +- **色彩规范**:
  47 + - 主色: `#409EFF`
  48 + - 辅助色: `#67C23A` / `#F56C6C` / `#909399`
  49 +- **卡片规范**: 高度 100px,内边距 12px,圆角 12px
  50 +- **按钮对齐**: 操作按钮左对齐,统计卡片内容垂直居中
  51 +- **图标显示**: 所有列表数据都要有图标,不同颜色区分类型
  52 +- **空值显示**: 没有信息的字段显示"无"
  53 +- **列表规范**: 列表数据不能换行
  54 +
  55 +### 性能要求
  56 +- 启用懒加载和代码分割
  57 +- Vuex 仅缓存必要数据
  58 +- 页面加载时间 < 3s
  59 +
  60 +## ⚙️ 后端开发规范
  61 +
  62 +### 架构规范
  63 +- **分层架构**: Entitys → Interfaces → Services
  64 +- **依赖注入**: 使用 ASP.NET Core DI 容器
  65 +- **异常处理**: 全局捕获,统一 JSON 格式返回
  66 +
  67 +### 数据访问规范
  68 +- **分页查询**: 所有列表接口必须分页
  69 +- **索引优化**: 关键字段建立索引
  70 +- **SQL安全**: 使用 WhereIF 条件查询避免 SQL 注入
  71 +- **查询优化**: 避免 N+1 查询,使用 JOIN 优化
  72 +
  73 +### 代码规范
  74 +- **XML注释**: 关键方法必须添加 XML 注释
  75 +- **异常处理**: 统一异常处理,返回友好错误信息
  76 +- **枚举使用**: 状态、类型等固定值必须使用枚举,禁止魔法数字
  77 +
  78 +### ID生成规范
  79 +```csharp
  80 +// ✅ 正确:必须使用YitIdHelper
  81 +Id = YitIdHelper.NextId().ToString()
  82 +
  83 +// ❌ 错误:禁止使用Guid
  84 +Id = Guid.NewGuid().ToString()
  85 +```
  86 +
  87 +## 🗄️ 数据库规范
  88 +
  89 +### 命名规范
  90 +- **表命名**: 业务前缀 + 功能名称 (如: lq_)
  91 +- **字段命名**: 驼峰化
  92 +- **时间字段**: 统一使用 DateTime 类型
  93 +
  94 +### 查询规范
  95 +- **分页查询**: 避免全表扫描
  96 +- **索引建立**: 关键查询字段建立索引
  97 +- **删除标记**: `base_organize.DeleteMark` 为 `null` 表示未删除
  98 +
  99 +### MCP MySQL 与 SQL 验证
  100 +- 使用 MCP 查库或编写/验证统计 SQL 时,遵循 skill:`mcp-mysql-and-sql-validation`。
  101 +
  102 +### 数据库文档要求
  103 +- **文档维护**: 所有数据库信息记录到 `数据库说明.md`
  104 +- **表结构记录**: 表名、字段名、字段解释、字段关联
  105 +- **变更同步**: 表结构变更时同步更新文档
  106 +
  107 +## 🔌 API接口规范
  108 +
  109 +### 接口注释规范
  110 +- 新增或修改 API 时,接口方法的 XML 注释格式与要求见 skill:`api-xml-comments`。
  111 +
  112 +### 接口测试规范
  113 +- **必须测试**:所有新开发或修改的接口都必须测试通过后再提交;具体流程、Token 获取与 curl 示例见 skill:`api-interface-testing`。
  114 +
  115 +## 📊 数据一致性规范
  116 +
  117 +### 统计与列表数据
  118 +- **数据一致性**: 统计接口与列表接口使用相同的过滤条件、时间范围、权限控制
  119 +- **字段命名规范**: DTO字段名称、大小写必须完全一致
  120 +- **计算逻辑统一**: 统计数据计算逻辑与列表数据筛选逻辑保持一致
  121 +- **分页一致性**: 统计接口和列表接口的分页参数和逻辑必须保持一致
  122 +
  123 +## 📝 代码质量规范
  124 +
  125 +### 代码风格
  126 +- **缩进**: 2 空格
  127 +- **行长度**: 单行 <= 120 字符
  128 +- **注释**: 关键逻辑必须添加注释
  129 +
  130 +### 代码审查
  131 +- **自检**: 提交前进行自检
  132 +- **审查**: 重要功能需代码审查
  133 +
  134 +## ⚠️ 特殊要求
  135 +
  136 +### 前端特殊要求
  137 +- 操作按钮必须左对齐,不要居中
  138 +- 统计卡片内容必须垂直居中
  139 +- 所有列表数据都要有图标显示,不同类型的图标需要有不同的颜色,但是颜色不能太多
  140 +- 没有信息的字段显示"无"
  141 +- 卡片高度统一为100px,内边距12px,圆角12px
  142 +- 弹窗、二级页面、复杂表单等必须单独创建 Vue 文件或封装成组件
  143 +- 禁止在主页面的 template 中直接编写弹窗内容或复杂交互逻辑
  144 +- 组件文件命名使用 kebab-case,如:user-dialog.vue、edit-form.vue
  145 +- 列表数据不能换行
  146 +
  147 +### 后端特殊要求
  148 +- 使用 WhereIF 条件查询避免 SQL 注入
  149 +- 关键方法必须添加 XML 注释
  150 +- 统一异常处理,返回友好错误信息
  151 +- 系统内涉及状态、类型等固定值的字段必须使用枚举类型(enum)定义,禁止使用魔法数字或硬编码字符串;同时需为枚举成员添加 XML 注释,保证可读性与可维护性
  152 +- 不需要在NCC.API创建controller,因为Extend里面的service都是可以直接使用的
  153 +
  154 +## 🚨 强制约束
  155 +
  156 +### 回复
  157 +1. **回复前缀**: 每次回复的时候都必须用“大哥”作为前缀
  158 +
  159 +### 环境要求
  160 +1. **Node.js版本**: 必须使用16.20.2版本,项目在Node 18下会失败
  161 +2. **API传参**: GET请求使用data字段传参,不使用params
  162 +
  163 +### 功能要求
  164 +4. **数据一致性**: 统计数据和列表数据必须使用相同的过滤条件
  165 +5. **UI一致性**: 所有页面必须使用统一的布局和样式规范
  166 +6. **错误处理**: 统一异常处理,返回友好错误信息
  167 +7. **性能优化**: 所有列表接口支持分页,避免大数据量查询
  168 +8. **安全防护**: 使用SqlSugar ORM防止SQL注入,前端数据渲染时进行HTML转义
  169 +9. **数据库文档**: 所有数据库表结构、字段说明、关联关系必须记录到数据库说明文档中
  170 +10. **ID生成规范**: 所有实体ID的生成都必须使用 `YitIdHelper.NextId().ToString()`,禁止使用 `Guid.NewGuid().ToString()` 或其他ID生成方式
  171 +11.**说明文档规范**:没有要求生成新的md文件的时候,严禁生成新md文件。
  172 +
  173 +## 📋 重要变更记录
  174 +
  175 +### 已弃用的表
  176 +- 涉及人员、门店归属、业绩关联等逻辑时,必须使用当前约定表与字段;具体弃用表及替代方案见 skill:`deprecated-tables-context`。
... ...
.cursor/skills/api-interface-testing/SKILL.md 0 → 100644
  1 +---
  2 +name: api-interface-testing
  3 +description: 按项目规范执行接口测试,包含获取 Token、使用 curl 调用接口及验证要点。在开发或修改接口、需要验证接口行为或用户提及接口测试时使用。
  4 +---
  5 +
  6 +# 接口测试
  7 +
  8 +## 何时使用
  9 +
  10 +- 新增或修改了后端 API,需要验证接口行为
  11 +- 用户明确要求进行接口测试或提供测试示例
  12 +- 提交代码前确认接口符合「必须测试」规范
  13 +
  14 +## 测试流程
  15 +
  16 +1. **获取 Token**:先调用登录接口拿到 `data.token`
  17 +2. **调用目标接口**:请求头带上 `Authorization: {data.token}`
  18 +3. **验证结果**:按下方清单检查返回值与行为
  19 +
  20 +## 获取 Token
  21 +
  22 +- **地址**:`POST /api/oauth/Login`
  23 +- **Content-Type**:`application/x-www-form-urlencoded`
  24 +- **参数**:`userName=admin`,`password=123456`
  25 +- **Base URL**:本地一般为 `http://localhost:19001`,以实际运行环境为准
  26 +
  27 +**curl 示例:**
  28 +
  29 +```bash
  30 +curl -X POST "http://localhost:19001/api/oauth/Login" \
  31 + -H "Content-Type: application/x-www-form-urlencoded" \
  32 + -d "userName=admin&password=123456"
  33 +```
  34 +
  35 +**返回说明**:`data.token` 已包含 `"Bearer "` 前缀,请求其他接口时**直接使用**:`Authorization: {data.token}`(无需再拼 Bearer)。
  36 +
  37 +## 调用接口示例
  38 +
  39 +**GET(项目规范:GET 使用 data 传参,不用 params):**
  40 +
  41 +```bash
  42 +curl -X GET "http://localhost:19001/api/xxx/YourAction?key=value" \
  43 + -H "Authorization: <data.token 完整值>"
  44 +```
  45 +
  46 +**POST(JSON body):**
  47 +
  48 +```bash
  49 +curl -X POST "http://localhost:19001/api/xxx/YourAction" \
  50 + -H "Authorization: <data.token 完整值>" \
  51 + -H "Content-Type: application/json" \
  52 + -d '{"key":"value"}'
  53 +```
  54 +
  55 +将 `<data.token 完整值>` 替换为登录响应里 `data.token` 的整段字符串(已含 `Bearer `)。
  56 +
  57 +## 验证清单
  58 +
  59 +测试时需覆盖并确认:
  60 +
  61 +- [ ] **功能**:用真实/合理数据调用,返回符合接口约定
  62 +- [ ] **正确性**:关键字段类型、取值、分页与业务逻辑一致
  63 +- [ ] **边界**:空列表、无数据、参数缺省等处理正确
  64 +- [ ] **异常**:非法参数、未登录等返回合理错误码与提示
  65 +- [ ] **性能**:响应时间可接受,无超时或明显卡顿
  66 +
  67 +只有测试通过后再提交相关代码。
  68 +
  69 +## 工具
  70 +
  71 +可使用 curl、Postman、Swagger 等;给出示例时优先提供 **curl**,便于在终端直接执行。
... ...
.cursor/skills/api-xml-comments/SKILL.md 0 → 100644
  1 +---
  2 +name: api-xml-comments
  3 +description: API 接口 XML 注释规范与模板。在新增或修改后端 API、为接口方法编写或补全 XML 注释时使用。
  4 +---
  5 +
  6 +# API 接口 XML 注释规范
  7 +
  8 +## 何时使用
  9 +
  10 +- 新增或修改后端 API 接口时
  11 +- 为接口方法补全或统一 XML 注释时
  12 +- 代码审查要求接口注释符合规范时
  13 +
  14 +---
  15 +
  16 +## 标准格式
  17 +
  18 +所有 API 接口方法必须按以下格式编写 XML 注释:
  19 +
  20 +```csharp
  21 +/// <summary>
  22 +/// 接口功能描述(简洁明了的一句话)
  23 +/// </summary>
  24 +/// <remarks>
  25 +/// 详细功能说明和使用场景
  26 +///
  27 +/// 示例请求:
  28 +/// ```json
  29 +/// {
  30 +/// "参数名": "参数值",
  31 +/// "参数名2": "参数值2"
  32 +/// }
  33 +/// ```
  34 +///
  35 +/// 参数说明:
  36 +/// - 参数名: 参数描述
  37 +/// - 参数名2: 参数描述
  38 +/// </remarks>
  39 +/// <param name="参数名">参数描述</param>
  40 +/// <returns>返回值描述</returns>
  41 +/// <response code="200">成功响应描述</response>
  42 +/// <response code="400">错误响应描述</response>
  43 +/// <response code="500">服务器错误描述</response>
  44 +```
  45 +
  46 +---
  47 +
  48 +## 注释要求
  49 +
  50 +- `<summary>`:一句话概括功能,简洁明了
  51 +- `<remarks>`:详细说明、示例请求(JSON)、参数说明列表
  52 +- 示例请求使用 JSON 格式,参数说明用列表
  53 +- 必须包含所有可能返回的 HTTP 状态码(200/400/500 等)的 `<response>` 说明
  54 +- 复杂接口必须提供完整请求示例
... ...
.cursor/skills/deprecated-tables-context/SKILL.md 0 → 100644
  1 +---
  2 +name: deprecated-tables-context
  3 +description: 已弃用表及替代方案。在涉及人员、门店归属、业绩关联等逻辑时使用,避免误用历史表或字段。
  4 +---
  5 +
  6 +# 已弃用的表与替代方案
  7 +
  8 +## 何时使用
  9 +
  10 +- 开发或修改与**人员信息**相关的逻辑时
  11 +- 开发或修改与**门店归属**(事业部/经营部/科技部/旗舰店等)相关的逻辑时
  12 +- 涉及**业绩与人员关联**、按门店/月份统计归属时
  13 +- 排查数据来源或历史表结构时
  14 +
  15 +---
  16 +
  17 +## lq_ryzl(人员资料表)已弃用
  18 +
  19 +- **替代**:人员信息统一使用系统用户表 **`BASE_USER`** 管理
  20 +- **使用**:所有人员相关业务使用 `BASE_USER` 及其扩展字段(`F_MDID`、`F_ZW`、`F_GWFL`、`F_GW` 等)
  21 +- **关联**:人员与业绩的关联通过 `BASE_USER.F_REALNAME` 与 `lq_yjmxb.jks` 等进行
  22 +
  23 +---
  24 +
  25 +## lq_mdxx_mdgs / lq_mdxx 归属字段已弃用
  26 +
  27 +- **替代**:门店归属一律从 **`lq_md_target`** 按**月份维度**管理
  28 +- **使用**:通过 `F_StoreId + F_Month` 获取对应月份的事业部/经营部/科技部/旗舰店等归属信息
  29 +- **禁止**:不再从 `lq_mdxx` 读取归属;以下字段视为历史字段,**禁止作为业务统计或归属判断依据**:
  30 + - `lq_mdxx`:`syb`、`jyb`、`kjb`、`dxmb`、`gsqssj`、`gszzsj`、`status`
... ...
.cursor/skills/mcp-mysql-and-sql-validation/SKILL.md 0 → 100644
  1 +---
  2 +name: mcp-mysql-and-sql-validation
  3 +description: MCP MySQL 使用规范与统计 SQL 验证流程;接口测试后必须查库验证;用户问业务数据时自动查库。在使用 MCP 查库、写统计 SQL 或提交含 SQL 的代码时使用。
  4 +---
  5 +
  6 +# MCP MySQL 与 SQL 验证
  7 +
  8 +## 一、Skills 定位说明(必读)
  9 +
  10 +本 Skills 用于**约束 AI 在涉及真实业务数据时的行为**,核心目标:
  11 +
  12 +- 让 AI **必须通过 MCP 查询真实数据库**
  13 +- 让接口测试 **必须验证数据库结果**
  14 +- 让统计 / 报表 **必须跑真实 SQL**
  15 +- 让用户直接问“数据是多少”时,AI **自动查库而不是反问**
  16 +
  17 +> 本 Skills 属于:**执行型 + 验证型 + 数据治理型 Skills**
  18 +> 目标:**杜绝 AI 编数据、假验证、只写 SQL 不执行的问题**
  19 +
  20 +---
  21 +
  22 +## 二、何时必须使用本 Skills(触发规则)
  23 +
  24 +只要满足以下任一条件,**AI 必须使用 MCP 数据库工具**。
  25 +
  26 +### 1️⃣ 接口测试场景(新增 / 编辑 / 删除 / 状态变更)
  27 +
  28 +当 AI 执行或协助以下接口相关操作时:
  29 +
  30 +- 新增数据(Create / Add)
  31 +- 编辑数据(Update / Edit)
  32 +- 删除数据(Delete / Remove / 作废)
  33 +- 状态变更(启用 / 禁用 / 完成 / 关闭)
  34 +
  35 +#### 强制规则
  36 +
  37 +- ✅ 接口执行完成后,**必须使用 MCP 查询数据库**
  38 +- ✅ 验证数据是否真实新增 / 修改 / 删除
  39 +- ❌ 禁止只根据接口返回值判断成功
  40 +- ❌ 禁止假设数据库已发生变化
  41 +
  42 +> ✔ 正确行为:“接口返回成功 → MCP 查询表 → 对比数据变化”
  43 +
  44 +---
  45 +
  46 +### 2️⃣ 统计 / 报表 / 看板 / 聚合接口
  47 +
  48 +包括但不限于:
  49 +
  50 +- 数量统计(会员数、订单数、开单数)
  51 +- 金额统计(开单金额、支付金额、退款金额)
  52 +- 汇总指标(合计、平均值、最大值)
  53 +- 环比 / 同比 / 增长率
  54 +
  55 +#### 强制规则
  56 +
  57 +- ✅ 编写统计 SQL 后,**必须通过 MCP 执行**
  58 +- ✅ 用真实数据验证结果合理性
  59 +- ❌ 禁止“只写 SQL,不执行”
  60 +- ❌ 禁止凭经验推断结果
  61 +
  62 +---
  63 +
  64 +### 3️⃣ 用户直接询问业务数据(自动触发)
  65 +
  66 +当用户提问符合以下特征时,AI **必须自动查库**:
  67 +
  68 +#### 触发特征
  69 +
  70 +- 包含:`多少 / 数量 / 金额 / 总数 / 合计`
  71 +- 包含明确时间范围:年(如 2026 年)、月(如本月 / 2026-01)、日(如今天 / 昨天)
  72 +- 涉及业务实体:会员 / 订单 / 开单 / 门店 / 员工 / 消耗
  73 +
  74 +#### 示例问题
  75 +
  76 +- 2026 年新增会员数量是多少?
  77 +- 2026 年开单金额是多少?
  78 +- 本月退款总额有多少?
  79 +- 今天新增订单数是多少?
  80 +
  81 +#### 强制规则
  82 +
  83 +- ✅ 自动识别为【数据查询问题】
  84 +- ✅ 直接使用 MCP 查询数据库
  85 +- ❌ 禁止回复“需要查询数据库”
  86 +- ❌ 禁止编造、估算或假设数据
  87 +
  88 +---
  89 +
  90 +## 三、MCP MySQL 使用规范
  91 +
  92 +### 1️⃣ 允许的操作范围
  93 +
  94 +- ✅ **只允许**:`SELECT`
  95 +- ❌ **禁止**:`INSERT / UPDATE / DELETE / TRUNCATE`
  96 +
  97 +---
  98 +
  99 +### 2️⃣ 表结构查询规范
  100 +
  101 +如需查看表结构,统一使用以下 SQL(将 `<表名>` 替换为实际表名):
  102 +
  103 +```sql
  104 +SELECT COLUMN_NAME,
  105 + DATA_TYPE,
  106 + IS_NULLABLE,
  107 + COLUMN_KEY,
  108 + COLUMN_DEFAULT,
  109 + EXTRA,
  110 + COLUMN_COMMENT
  111 +FROM INFORMATION_SCHEMA.COLUMNS
  112 +WHERE TABLE_NAME = '<表名>';
  113 +```
  114 +
  115 +**注意事项**:
  116 +
  117 +- 查询表结构时**不要加 ORDER BY**
  118 +- **每次查询只针对一个表**
  119 +- 避免一次性发送多条 SQL
  120 +
  121 +---
  122 +
  123 +## 四、SQL 查询验证规范(统计类)
  124 +
  125 +对统计类型的 SQL(报表、看板、统计接口),在提交代码前**必须先**用 MCP MySQL 工具执行验证。
  126 +
  127 +### 验证要求
  128 +
  129 +- [ ] SQL 语法正确,能执行通过
  130 +- [ ] 涉及的表、字段存在且类型匹配
  131 +- [ ] JOIN 关系正确
  132 +- [ ] 统计逻辑与需求一致
  133 +- [ ] 用实际数据跑一遍,结果合理
  134 +
  135 +### 原则
  136 +
  137 +只有验证通过的 SQL 才能提交到代码中。
  138 +
  139 +---
  140 +
  141 +## 五、如何通过 MCP 执行 SQL(配置与调用)
  142 +
  143 +### 1️⃣ 配置文件位置
  144 +
  145 +- **路径**:项目根目录下 `.cursor/mcp.json`
  146 +- **数据库 MCP 服务名**:`my-sql-db`
  147 +
  148 +### 2️⃣ 当前数据库 MCP 配置说明
  149 +
  150 +本项目中 MySQL MCP 使用 `@davewind/mysql-mcp-server`,连接库为 `lqerp_dev`。配置示例(仅作参考,以实际 `.cursor/mcp.json` 为准):
  151 +
  152 +```json
  153 +"my-sql-db": {
  154 + "command": "npx",
  155 + "args": ["--yes", "@davewind/mysql-mcp-server", "mysql://用户:密码@主机:3306/lqerp_dev"]
  156 +}
  157 +```
  158 +
  159 +### 3️⃣ 执行 SQL 的方式
  160 +
  161 +- **工具名称**:MCP 提供的 **query** 工具(在 Cursor 中可能显示为 `query` 或带服务前缀,如与 `my-sql-db` 相关)。
  162 +- **参数**:传入 **sql**(string),即要执行的 SQL 语句。
  163 +- **限制**:该 MCP 仅支持 **只读**,仅可执行 **SELECT**;所有语句在 READ ONLY 事务中执行,禁止 INSERT/UPDATE/DELETE/DDL。
  164 +
  165 +**调用要点**:
  166 +
  167 +1. 在需要查库、验证接口结果或跑统计 SQL 时,直接调用该 MCP 的 query 工具。
  168 +2. 传入的 `sql` 必须是合法的 SELECT 语句,一次一条。
  169 +3. 用返回结果做数据验证或统计核对。
  170 +
  171 +### 4️⃣ 简单验证示例
  172 +
  173 +- 验证 MCP 连通、可执行 SQL 的示例(在 `lqerp_dev` 下查表数量):
  174 +
  175 +```sql
  176 +SELECT COUNT(*) AS table_count
  177 +FROM information_schema.tables
  178 +WHERE table_schema = 'lqerp_dev';
  179 +```
  180 +
  181 +- 查询某表结构(将 `<表名>` 换为实际表名):
  182 +
  183 +```sql
  184 +SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_KEY, COLUMN_COMMENT
  185 +FROM INFORMATION_SCHEMA.COLUMNS
  186 +WHERE TABLE_SCHEMA = 'lqerp_dev' AND TABLE_NAME = '<表名>';
  187 +```
  188 +
  189 +### 5️⃣ 小结
  190 +
  191 +| 项目 | 说明 |
  192 +|------------|------|
  193 +| 配置 | `.cursor/mcp.json`,服务名 `my-sql-db` |
  194 +| 执行方式 | 调用 MCP 的 **query** 工具,参数 **sql** |
  195 +| 允许操作 | 仅 SELECT |
  196 +| 数据库 | `lqerp_dev` |
... ...
.cursor/skills/remember-as-rule-or-skill/SKILL.md 0 → 100644
  1 +---
  2 +name: remember-as-rule-or-skill
  3 +description: 当用户要求「记住」某事时,根据内容类型自动添加为项目规则(.cursor/rules)或 Skill(.cursor/skills)。Use when user says 记住、记一下、以后要、保存这个规则、加到规范里、写进 skill、记录下来、按这个来.
  4 +---
  5 +
  6 +# 记住 → 自动添加规则或 Skill
  7 +
  8 +## 一、何时触发
  9 +
  10 +当用户表达**希望持久化当前约定/偏好**时,必须走本流程,将内容写入 `.cursor/rules/` 或 `.cursor/skills/`。
  11 +
  12 +### 触发表述(示例)
  13 +
  14 +- 记住 / 记一下 / 以后要 / 保存 / 记录下来
  15 +- 加到规范里 / 写进规则 / 写进 skill
  16 +- 按这个来 / 以后都按这个做
  17 +- 类似的自然语言表达
  18 +
  19 +触发后:**先判断类型(Rule vs Skill),再执行添加或更新**。
  20 +
  21 +---
  22 +
  23 +## 二、Rule 还是 Skill?判断标准
  24 +
  25 +| 类型 | 适合内容 | 存放位置 | 特点 |
  26 +|------|----------|----------|------|
  27 +| **Rule** | 简短约束、禁止项、风格约定、回复格式等「每次都要遵守」的规范 | `.cursor/rules/*.mdc` | 可 alwaysApply 或按文件 glob 生效;单条规则建议 ≤50 行 |
  28 +| **Skill** | 有步骤的流程、按场景触发的知识、需要 description 匹配的专项能力 | `.cursor/skills/<name>/SKILL.md` | 通过 description 在相关场景被引用;可含多节、示例 |
  29 +
  30 +### 选择 Rule 的情况
  31 +
  32 +- 禁止或必须做的**一句话/短条款**(如:禁止用 Guid、GET 用 data 传参)
  33 +- **编码/格式约定**(缩进、命名、注释要求)
  34 +- **回复或交互约定**(如:回复前缀「大哥」)
  35 +- **仅在某类文件生效**的规范(如仅 `**/*.vue`)→ 用 `globs`,`alwaysApply: false`
  36 +
  37 +### 选择 Skill 的情况
  38 +
  39 +- **多步骤流程**(如:接口测试流程、查库验证流程)
  40 +- **按场景触发**的专项知识(如:弃用表、API 注释格式、MCP 查库)
  41 +- 需要**示例、模板、清单**的说明
  42 +- 内容较长或需要**分节、可检索**的文档
  43 +
  44 +### 与现有内容的关系
  45 +
  46 +- 若与**现有 rule/skill 主题一致**(如同属「接口规范」)→ **优先更新已有文件**,避免碎片化
  47 +- 若是**全新主题** → 新建 rule 或 skill
  48 +
  49 +---
  50 +
  51 +## 三、执行步骤
  52 +
  53 +### Step 1:确认要记的内容
  54 +
  55 +- 从对话中提炼出用户要持久化的**具体条文或流程**
  56 +- 若含糊,可追问一句再落笔
  57 +
  58 +### Step 2:决定 Rule 还是 Skill,以及目标文件
  59 +
  60 +- 按上表判断:Rule 还是 Skill
  61 +- 若为 Rule:决定是**新增一个 .mdc** 还是**追加到现有 rule**(如 `project_rules.mdc` 的某节)
  62 +- 若为 Skill:决定是**新建 skill 目录**还是**更新现有 skill**(如 `api-xml-comments`)
  63 +
  64 +### Step 3:写入或更新
  65 +
  66 +**Rule(.cursor/rules/xxx.mdc)**
  67 +
  68 +- 格式:YAML frontmatter + Markdown 正文
  69 +- 必填:`description`;若全局生效则 `alwaysApply: true`;若按文件则 `globs: "**/*.xx"`、`alwaysApply: false`
  70 +- 正文简洁、可执行,单条规则尽量控制在约 50 行内
  71 +
  72 +```markdown
  73 +---
  74 +description: 简短说明这条规则做什么
  75 +alwaysApply: true
  76 +---
  77 +# 规则标题
  78 +内容...
  79 +```
  80 +
  81 +**Skill(.cursor/skills/<name>/SKILL.md)**
  82 +
  83 +- 格式:YAML frontmatter(`name`、`description`)+ Markdown 正文
  84 +- `description` 要包含**触发场景/关键词**,便于 AI 在相关任务时引用
  85 +- 正文可含:何时用、步骤、示例、注意事项
  86 +
  87 +```markdown
  88 +---
  89 +name: skill-name
  90 +description: 做什么;在什么场景下使用(含触发词)
  91 +---
  92 +# 标题
  93 +## 何时使用
  94 +...
  95 +## 步骤/规范
  96 +...
  97 +```
  98 +
  99 +### Step 4:确认
  100 +
  101 +- 写完后**简短说明**:写到了哪(规则还是 skill、文件名),以及**以后如何生效**(例如「全局规则每次都会应用」或「在提到接口测试时会用对应 skill」)
  102 +
  103 +---
  104 +
  105 +## 四、本项目约定
  106 +
  107 +- **规则与 skill 的路径**:项目内统一用 **项目级** 配置:
  108 + - 规则:`.cursor/rules/`
  109 + - Skill:`.cursor/skills/`
  110 +- **与「不随意生成 md」的关系**:用户**明确要求记住/保存规则或写进 skill** 时,属于「要求生成或修改配置文档」的例外,可以且应当新增或修改 `.cursor/rules/`、`.cursor/skills/` 下的文件。
  111 +- **风格**:与现有 `project_rules.mdc`、`orchestrator-first.mdc` 以及各 skill 的写法保持一致(中文说明、清单式条款、必要时代码块示例)。
  112 +
  113 +---
  114 +
  115 +## 五、小结
  116 +
  117 +| 用户说 | 你要做的 |
  118 +|--------|-----------|
  119 +| 记住 / 记一下 / 以后要 / 保存规则 / 加到规范 / 写进 skill | 触发本 skill |
  120 +| 内容像「禁止/必须/约定」的短条款 | 写入或合并到 **Rule**(.mdc) |
  121 +| 内容像「流程/步骤/场景知识」 | 写入或合并到 **Skill**(SKILL.md) |
  122 +| 与现有某 rule/skill 同主题 | 优先**更新**该文件 |
  123 +| 写完后 | 说明写到了哪、以后如何生效 |
... ...
美国版/Food Labeling Management App React/ATTRIBUTIONS.md deleted
1   -This Figma Make file includes components from [shadcn/ui](https://ui.shadcn.com/) used under [MIT license](https://github.com/shadcn-ui/ui/blob/main/LICENSE.md).
2   -
3   -This Figma Make file includes photos from [Unsplash](https://unsplash.com) used under [license](https://unsplash.com/license).
美国版/Food Labeling Management App React/FEATURE_DEMO.md deleted
1   -# 功能演示指南 / Feature Demo Guide
2   -
3   -## 🎬 完整演示流程 / Complete Demo Flow
4   -
5   -### 场景: 新员工首次使用系统 / Scenario: New Employee First-Time Use
6   -
7   ----
8   -
9   -## 步骤 1: 登录系统 / Step 1: Login
10   -
11   -**页面**: `/login`
12   -
13   -**操作演示** / **Demo Actions**:
14   -```
15   -1. 查看应用Logo和标题 / View app logo and title
16   - - 蓝色餐具图标 / Blue utensils icon
17   - - "Food Label System" 标题 / "Food Label System" title
18   -
19   -2. 输入登录凭证 / Enter credentials
20   - - 邮箱: john@example.com
21   - - 密码: password123
22   -
23   -3. 点击"Sign In" / Click "Sign In"
24   - - 显示"Signing In..." / Shows "Signing In..."
25   - - 1秒后成功 / Success after 1 second
26   - - Toast提示: "Login successful" / Toast: "Login successful"
27   -```
28   -
29   -**展示要点** / **Key Points**:
30   -- ✅ 按钮高度48px (符合设计规范) / Button height 48px (meets design specs)
31   -- ✅ 企业蓝色主色调 / Corporate blue primary color
32   -- ✅ Inter字体清晰易读 / Inter font clear and readable
33   -- ✅ 输入框高度48px / Input height 48px
34   -
35   ----
36   -
37   -## 步骤 2: 选择店铺 / Step 2: Select Store
38   -
39   -**页面**: `/store-select`
40   -
41   -**操作演示** / **Demo Actions**:
42   -```
43   -1. 查看欢迎信息 / View welcome message
44   - - "Welcome! John Smith" (显示用户名)
45   -
46   -2. 浏览4个可选店铺 / Browse 4 available stores
47   - - Downtown Kitchen (主店) / Main store
48   - - Brooklyn Kitchen (分店) / Branch
49   - - Queens Kitchen (分店) / Branch
50   - - Manhattan Kitchen (分店) / Branch
51   -
52   -3. 选择"Downtown Kitchen" / Select "Downtown Kitchen"
53   - - 卡片变蓝色高亮 / Card turns blue highlighted
54   - - 显示勾选标记 / Shows checkmark
55   -
56   -4. 点击"Confirm" / Click "Confirm"
57   - - Toast: "Store selected successfully"
58   - - 自动跳转到Dashboard / Auto-navigate to Dashboard
59   -```
60   -
61   -**展示要点** / **Key Points**:
62   -- ✅ 清晰的视觉反馈 / Clear visual feedback
63   -- ✅ 店铺信息完整 (地址、经理、电话) / Complete store info
64   -- ✅ 选中状态明显 / Selected state obvious
65   -- ✅ 确认按钮固定底部 / Confirm button fixed at bottom
66   -
67   ----
68   -
69   -## 步骤 3: 浏览Dashboard / Step 3: Browse Dashboard
70   -
71   -**页面**: `/` (Dashboard)
72   -
73   -**操作演示** / **Demo Actions**:
74   -```
75   -1. 查看头部信息 / View header
76   - - 店铺名称: "Downtown Kitchen"
77   - - 用户名: "John Smith"
78   - - 在线状态: 绿色指示器 / Online status: green indicator
79   -
80   -2. 查看4个统计卡片 / View 4 statistics cards
81   - - Today's Labels: 247 (12 pending)
82   - - Open Tasks: 8 (3 due today)
83   - - Alerts: 5 (expiring soon)
84   - - Devices Status: 4 (printers available)
85   -
86   -3. 体验快速操作 / Try quick actions
87   - - "Scan & Print" 按钮 (蓝色) / Blue button
88   - - "Batch Print" 按钮 (绿色) / Green button
89   -
90   -4. 底部导航 / Bottom navigation
91   - - Dashboard (高亮显示) / Dashboard (highlighted)
92   - - Labels
93   - - Tasks
94   - - More
95   -```
96   -
97   -**展示要点** / **Key Points**:
98   -- ✅ 信息密度适中 / Appropriate information density
99   -- ✅ 卡片可点击导航 / Clickable cards for navigation
100   -- ✅ 快速操作按钮醒目 / Quick action buttons prominent
101   -- ✅ 统计数据清晰 / Statistics clear
102   -
103   ----
104   -
105   -## 步骤 4: 创建标签 (核心功能) / Step 4: Create Label (Core Feature)
106   -
107   -**页面**: `/labels`
108   -
109   -### 4.1 选择标签类型 / Select Label Type
110   -
111   -**操作演示** / **Demo Actions**:
112   -```
113   -1. 进入Labels页面 / Enter Labels page
114   - - 看到"Create"和"History"两个Tab / See "Create" and "History" tabs
115   - - 默认在"Create" tab
116   -
117   -2. 浏览6种标签类型 / Browse 6 label types
118   - 📘 Nutrition Label (蓝色) - 156 food items
119   - ⚠️ Allergen Label (红色) - 89 food items
120   - ❄️ Storage Label (青色) - 134 food items
121   - 📅 Expiry Date Label (橙色) - 203 food items
122   - 📦 Batch Tracking Label (紫色) - 78 food items
123   - 👨‍🍳 Preparation Label (绿色) - 112 food items
124   -
125   -3. 选择"Expiry Date Label" / Select "Expiry Date Label"
126   - - 点击卡片 / Click card
127   - - 跳转到食品选择页面 / Navigate to food selection
128   -```
129   -
130   -**展示要点** / **Key Points**:
131   -- ✅ 6种标签类型完整 / All 6 label types complete
132   -- ✅ 图标颜色区分明显 / Icons color-coded clearly
133   -- ✅ 显示可用食品数量 / Shows available food count
134   -- ✅ 卡片悬停效果流畅 / Smooth card hover effect
135   -
136   ----
137   -
138   -### 4.2 选择食品项目 / Select Food Item
139   -
140   -**页面**: `/labels/expiry/foods`
141   -
142   -**操作演示** / **Demo Actions**:
143   -```
144   -1. 查看食品列表 / View food list
145   - - 搜索框: "Search food items..." / Search box
146   - - 分类筛选: All / Meat / Seafood / Salads / etc.
147   -
148   -2. 浏览不同类别 / Browse categories
149   - - Meat: Grilled Chicken Breast, Ground Beef Patties
150   - - Seafood: Fresh Salmon Fillet
151   - - Prepared Foods: Club Sandwich, Shrimp Pasta
152   -
153   -3. 选择"Grilled Chicken Breast" / Select "Grilled Chicken Breast"
154   - - 点击食品卡片 / Click food card
155   - - 查看描述: "Fresh grilled chicken breast, boneless"
156   - - 跳转到预览页面 / Navigate to preview
157   -```
158   -
159   -**展示要点** / **Key Points**:
160   -- ✅ 搜索功能可用 / Search functionality available
161   -- ✅ 分类筛选清晰 / Category filtering clear
162   -- ✅ 食品信息完整 / Complete food information
163   -- ✅ 响应式网格布局 / Responsive grid layout
164   -
165   ----
166   -
167   -### 4.3 预览并打印 / Preview and Print
168   -
169   -**页面**: `/labels/expiry/chicken-breast/preview`
170   -
171   -**操作演示** / **Demo Actions**:
172   -```
173   -1. 查看标签预览 / View label preview
174   - - 标签类型: EXPIRATION DATE
175   - - 食品名称: Grilled Chicken Breast
176   - - 准备日期: 2026-02-27
177   - - 过期日期: 2026-03-04
178   - - 批次号: GB-20260227-001
179   -
180   -2. 查看打印信息 / View print info
181   - - Printed By: John Smith
182   - - Print Date: 2026-02-27 10:30 AM
183   - - Note: "This preview shows how the label will appear..."
184   -
185   -3. 点击"Print Label" / Click "Print Label"
186   - - 按钮显示"Printing..." / Button shows "Printing..."
187   - - 2秒后成功 / Success after 2 seconds
188   - - Toast: "Label printed successfully!"
189   - - 自动返回Labels页面 / Auto-return to Labels page
190   -```
191   -
192   -**展示要点** / **Key Points**:
193   -- ✅ 标签预览美观 / Label preview attractive
194   -- ✅ 信息完整准确 / Information complete and accurate
195   -- ✅ 打印流程流畅 / Smooth printing flow
196   -- ✅ 成功反馈清晰 / Clear success feedback
197   -
198   ----
199   -
200   -## 步骤 5: 查看打印历史 / Step 5: View Print History
201   -
202   -**页面**: `/labels` (History tab)
203   -
204   -**操作演示** / **Demo Actions**:
205   -```
206   -1. 切换到"History" Tab / Switch to "History" tab
207   - - 点击History tab按钮 / Click History tab
208   -
209   -2. 查看已打印标签 / View printed labels
210   - - 6个示例标签 / 6 sample labels
211   - - 每个显示完整信息:
212   - * 食品名称和标签类型 / Food name and label type
213   - * 关键信息 (3-4行) / Key information (3-4 lines)
214   - * 打印者和时间 / Printer and time
215   - * 状态标签: Active / Expired
216   -
217   -3. 观察不同标签类型 / Observe different label types
218   - - Expiry Date Label (橙色)
219   - - Storage Label (青色)
220   - - Allergen Label (红色)
221   - - Batch Tracking Label (紫色)
222   - - Preparation Label (绿色)
223   - - Nutrition Label (蓝色)
224   -```
225   -
226   -**展示要点** / **Key Points**:
227   -- ✅ 历史记录完整 / Complete history records
228   -- ✅ 状态标签清晰 / Status badges clear
229   -- ✅ 信息层级分明 / Clear information hierarchy
230   -- ✅ 可追溯性强 / Strong traceability
231   -
232   ----
233   -
234   -## 步骤 6: 任务管理 / Step 6: Task Management
235   -
236   -**页面**: `/tasks`
237   -
238   -**操作演示** / **Demo Actions**:
239   -```
240   -1. 查看任务列表 / View task list
241   - - 搜索框: "Search tasks..."
242   - - 筛选: All / Pending / In Progress / Completed
243   -
244   -2. 查看不同类型任务 / View different task types
245   - 🌡️ Refrigerator Temperature Check (High priority)
246   - 🧹 Kitchen Hygiene Inspection (Medium priority)
247   - ❄️ Freezer Temperature Check (High priority)
248   - ⚙️ Equipment Safety Check (Low priority)
249   -
250   -3. 执行任务 / Execute task
251   - - 点击"Refrigerator Temperature Check"
252   - - 填写温度读数: 38°F
253   - - 勾选安全检查项 / Check safety items
254   - - 添加备注 (可选) / Add notes (optional)
255   - - 上传照片 (可选) / Upload photo (optional)
256   - - 点击"Submit Task" / Click "Submit Task"
257   - - Toast: "Task completed successfully!"
258   -```
259   -
260   -**展示要点** / **Key Points**:
261   -- ✅ 任务分类清晰 / Clear task categories
262   -- ✅ 优先级标识明显 / Priority labels obvious
263   -- ✅ 执行流程完整 / Complete execution flow
264   -- ✅ 数据收集规范 / Standardized data collection
265   -
266   ----
267   -
268   -## 步骤 7: 语言切换演示 / Step 7: Language Switching Demo
269   -
270   -**页面**: `/more` → `/more/language`
271   -
272   -**操作演示** / **Demo Actions**:
273   -```
274   -1. 进入More页面 / Enter More page
275   - - 查看7个菜单选项 / View 7 menu options
276   -
277   -2. 点击"Language / 语言" / Click "Language / 语言"
278   - - 进入语言设置页面 / Enter language settings
279   -
280   -3. 当前语言: English / Current: English
281   - - 显示两个选项:
282   - ○ English (当前选中)
283   - ○ 中文(简体)
284   -
285   -4. 切换到中文 / Switch to Chinese
286   - - 点击"中文(简体)" / Click "中文(简体)"
287   - - Toast: "语言切换成功" / "Language changed successfully"
288   - - 整个界面立即变为中文 / Entire UI switches to Chinese immediately
289   -
290   -5. 演示中文界面 / Demo Chinese UI
291   - - 返回Dashboard: "主页" / Back to "主页"
292   - - Labels变为: "标签" / Labels: "标签"
293   - - Tasks变为: "任务" / Tasks: "任务"
294   - - More变为: "更多" / More: "更多"
295   -
296   -6. 切换回English / Switch back to English
297   - - More → 语言 → English
298   - - Toast: "Language changed successfully"
299   - - 界面恢复英文 / UI back to English
300   -```
301   -
302   -**展示要点** / **Key Points**:
303   -- ✅ 即时切换无需刷新 / Instant switch without refresh
304   -- ✅ 所有文本完整翻译 / All text fully translated
305   -- ✅ 1400+翻译键值对 / 1400+ translation keys
306   -- ✅ 持久化保存设置 / Persisted settings
307   -
308   ----
309   -
310   -## 步骤 8: 其他设置功能 / Step 8: Other Settings Features
311   -
312   -**页面**: `/more/*`
313   -
314   -### 8.1 个人资料 / Profile
315   -```
316   -More → My Profile
317   -- 查看个人信息: 姓名、工号、职位、部门
318   -- 编辑联系方式: 邮箱、电话
319   -- 设置偏好: 推送通知、声音提醒
320   -```
321   -
322   -### 8.2 打印机设置 / Printer Settings
323   -```
324   -More → Printer Settings
325   -- 4台连接的打印机 / 4 connected printers
326   -- 查看打印机状态: Online / Offline
327   -- 设置默认打印机 / Set default printer
328   -- 测试打印 / Test print
329   -```
330   -
331   -### 8.3 培训材料 / Training Materials
332   -```
333   -More → Training Materials
334   -- 10个培训模块 / 10 training modules
335   -- 文章和视频 / Articles and videos
336   -- 分类: Food Safety / Operations / Equipment / Compliance
337   -- 完成状态跟踪 / Completion tracking
338   -```
339   -
340   -### 8.4 支持帮助 / Support
341   -```
342   -More → Support
343   -- 联系方式: Email / Phone
344   -- 营业时间: Mon-Fri, 9AM-6PM EST
345   -- 资源链接: User Guide / FAQ / Training Videos
346   -- 应用信息: Version 1.0.0
347   -```
348   -
349   ----
350   -
351   -## 步骤 9: 退出登录 / Step 9: Logout
352   -
353   -**页面**: `/more`
354   -
355   -**操作演示** / **Demo Actions**:
356   -```
357   -1. 滚动到底部 / Scroll to bottom
358   - - 看到红色"Logout"卡片 / See red "Logout" card
359   -
360   -2. 点击Logout / Click Logout
361   - - 弹出确认对话框 / Confirmation dialog appears
362   - - "Are you sure you want to logout?"
363   - - "Any unsaved changes will be lost."
364   -
365   -3. 确认退出 / Confirm logout
366   - - 点击红色"Logout"按钮 / Click red "Logout" button
367   - - 清除登录状态 / Clear login state
368   - - 返回登录页面 / Return to login page
369   -```
370   -
371   ----
372   -
373   -## 🎯 演示总结 / Demo Summary
374   -
375   -### 核心亮点 / Key Highlights
376   -
377   -#### 1. 设计规范 / Design Specifications
378   -- ✅ **Inter字体**: 专业企业级外观 / Professional enterprise appearance
379   -- ✅ **企业蓝色**: #2563eb统一配色 / Consistent #2563eb color scheme
380   -- ✅ **48px按钮**: 符合触摸标准 / Meets touch standards
381   -- ✅ **极简美学**: 清晰信息层级 / Clear information hierarchy
382   -
383   -#### 2. 用户体验 / User Experience
384   -- ✅ **流畅导航**: 4个主要模块 / Smooth navigation across 4 modules
385   -- ✅ **清晰反馈**: Toast提示和视觉变化 / Clear feedback with toasts and visual changes
386   -- ✅ **易用性**: 直观操作流程 / Intuitive operation flow
387   -- ✅ **响应式**: 移动优先设计 / Mobile-first design
388   -
389   -#### 3. 核心功能 / Core Functionality
390   -- ✅ **标签打印**: 6种类型完整流程 / 6 types with complete workflow
391   -- ✅ **任务管理**: 系统化任务执行 / Systematized task execution
392   -- ✅ **多店铺**: 完整店铺管理 / Complete store management
393   -- ✅ **双语支持**: 无缝语言切换 / Seamless language switching
394   -
395   -#### 4. 技术实现 / Technical Implementation
396   -- ✅ **React + TypeScript**: 类型安全 / Type-safe
397   -- ✅ **Tailwind CSS v4**: 现代样式系统 / Modern styling system
398   -- ✅ **React Router v7**: 高效路由 / Efficient routing
399   -- ✅ **Context API**: 状态管理 / State management
400   -
401   ----
402   -
403   -## 📊 演示数据概览 / Demo Data Overview
404   -
405   -### 可演示的数据量 / Available Demo Data
406   -- **标签类型**: 6种 / 6 label types
407   -- **食品项目**: 15种 / 15 food items
408   -- **打印历史**: 6条记录 / 6 history records
409   -- **任务列表**: 6个任务 / 6 tasks
410   -- **店铺数量**: 4个店铺 / 4 stores
411   -- **培训材料**: 10个模块 / 10 training modules
412   -- **打印机**: 4台设备 / 4 printers
413   -
414   -### 支持的语言 / Supported Languages
415   -- **English**: 1400+ translations
416   -- **中文(简体)**: 1400+ translations
417   -
418   ----
419   -
420   -## 🎬 演示脚本建议 / Demo Script Suggestions
421   -
422   -### 5分钟快速演示 / 5-Minute Quick Demo
423   -1. 登录 (30秒) / Login (30s)
424   -2. 选择店铺 (30秒) / Select store (30s)
425   -3. Dashboard概览 (1分钟) / Dashboard overview (1min)
426   -4. 标签打印流程 (2分钟) / Label printing flow (2min)
427   -5. 语言切换 (30秒) / Language switching (30s)
428   -6. 总结 (30秒) / Summary (30s)
429   -
430   -### 15分钟完整演示 / 15-Minute Full Demo
431   -1. 系统介绍和登录 (2分钟) / Intro and login (2min)
432   -2. Dashboard功能 (2分钟) / Dashboard features (2min)
433   -3. 标签打印详细流程 (4分钟) / Detailed label printing (4min)
434   -4. 任务管理 (3分钟) / Task management (3min)
435   -5. 设置和语言切换 (2分钟) / Settings and language (2min)
436   -6. 问答环节 (2分钟) / Q&A (2min)
437   -
438   -### 30分钟深度演示 / 30-Minute Deep Demo
439   -- 包含所有功能模块 / All feature modules
440   -- 技术架构讲解 / Technical architecture
441   -- 设计理念说明 / Design philosophy
442   -- 未来扩展讨论 / Future expansion discussion
443   -- 互动问答 / Interactive Q&A
444   -
445   ----
446   -
447   -**演示准备完成!** / **Demo Ready!**
448   -**建议使用Chrome或Safari浏览器以获得最佳体验** / **Recommended: Chrome or Safari for best experience**
美国版/Food Labeling Management App React/I18N_COMPLETE_GUIDE.md deleted
1   -# 🌐 完整中英文翻译系统
2   -
3   -## ✅ 已完成的翻译覆盖
4   -
5   -### 📋 翻译统计
6   -- **总翻译键**: 900+
7   -- **标签类型**: 6 种(全部翻译)
8   -- **食品项目**: 15 种(全部翻译)
9   -- **食品类别**: 12 种(全部翻译)
10   -- **标签字段**: 50+ 字段(全部翻译)
11   -
12   ----
13   -
14   -## 🏷️ 标签类型翻译
15   -
16   -| 英文 | 中文 | 图标 |
17   -|------|------|------|
18   -| Nutrition Label | 营养标签 | 🥗 |
19   -| Allergen Label | 过敏原标签 | ⚠️ |
20   -| Storage Label | 储存标签 | ❄️ |
21   -| Expiry Date Label | 有效期标签 | 📅 |
22   -| Batch Tracking Label | 批次跟踪标签 | 📦 |
23   -| Preparation Label | 制作标签 | 👨‍🍳 |
24   -
25   -**描述也完全翻译**:
26   -- EN: "Print nutrition facts and serving information"
27   -- ZH: "打印营养成分和份量信息"
28   -
29   ----
30   -
31   -## 🍽️ 食品名称翻译
32   -
33   -### 肉类(Meat / 肉类)
34   -| 英文 | 中文 |
35   -|------|------|
36   -| Grilled Chicken Breast | 烤鸡胸肉 |
37   -| Ground Beef Patties | 碎牛肉饼 |
38   -| Roasted Turkey Breast | 烤火鸡肉 |
39   -
40   -### 沙拉(Salads / 沙拉)
41   -| 英文 | 中文 |
42   -|------|------|
43   -| Caesar Salad | 凯撒沙拉 |
44   -
45   -### 海鲜(Seafood / 海鲜)
46   -| 英文 | 中文 |
47   -|------|------|
48   -| Fresh Salmon Fillet | 新鲜三文鱼片 |
49   -
50   -### 酱料(Sauces / 酱料)
51   -| 英文 | 中文 |
52   -|------|------|
53   -| Marinara Sauce | 意式番茄酱 |
54   -
55   -### 蔬菜(Vegetables / 蔬菜)
56   -| 英文 | 中文 |
57   -|------|------|
58   -| Pre-cut Vegetables | 预切蔬菜 |
59   -
60   -### 甜点(Desserts / 甜点)
61   -| 英文 | 中文 |
62   -|------|------|
63   -| Chocolate Brownie | 巧克力布朗尼 |
64   -
65   -### 预制食品(Prepared Foods / 预制食品)
66   -| 英文 | 中文 |
67   -|------|------|
68   -| Shrimp Pasta | 虾意面 |
69   -| Club Sandwich | 俱乐部三明治 |
70   -
71   -### 冷冻食品(Frozen Foods / 冷冻食品)
72   -| 英文 | 中文 |
73   -|------|------|
74   -| Vanilla Ice Cream | 香草冰淇淋 |
75   -
76   -### 乳制品(Dairy / 乳制品)
77   -| 英文 | 中文 |
78   -|------|------|
79   -| Greek Yogurt | 希腊酸奶 |
80   -
81   -### 烘焙食品(Bakery / 烘焙食品)
82   -| 英文 | 中文 |
83   -|------|------|
84   -| Whole Wheat Bread | 全麦面包 |
85   -
86   -### 饮料(Beverages / 饮料)
87   -| 英文 | 中文 |
88   -|------|------|
89   -| Mixed Berry Smoothie | 混合浆果奶昔 |
90   -
91   -### 汤(Soups / 汤)
92   -| 英文 | 中文 |
93   -|------|------|
94   -| Tomato Soup | 番茄汤 |
95   -
96   -**每个食品都有描述翻译**:
97   -- EN: "Fresh grilled chicken breast, boneless"
98   -- ZH: "新鲜烤鸡胸肉,去骨"
99   -
100   ----
101   -
102   -## 📊 营养标签字段翻译
103   -
104   -| 英文字段 | 中文字段 |
105   -|----------|----------|
106   -| Serving Size | 份量 |
107   -| Calories | 热量 |
108   -| Total Fat | 总脂肪 |
109   -| Saturated Fat | 饱和脂肪 |
110   -| Trans Fat | 反式脂肪 |
111   -| Cholesterol | 胆固醇 |
112   -| Sodium | 钠 |
113   -| Total Carbohydrate | 总碳水化合物 |
114   -| Dietary Fiber | 膳食纤维 |
115   -| Sugars | 糖 |
116   -| Protein | 蛋白质 |
117   -
118   -**标签标题翻译**:
119   -- EN: "NUTRITION FACTS"
120   -- ZH: "营养成分"
121   -
122   ----
123   -
124   -## ⚠️ 过敏原标签字段翻译
125   -
126   -| 英文字段 | 中文字段 |
127   -|----------|----------|
128   -| Contains | 含有 |
129   -| May Contain | 可能含有 |
130   -| Cross-Contamination Risk | 交叉污染风险 |
131   -| Prepared In | 制备于 |
132   -
133   -**风险等级翻译**:
134   -- Low / 低
135   -- Medium / 中
136   -- High / 高
137   -
138   -**标签标题翻译**:
139   -- EN: "ALLERGEN INFORMATION"
140   -- ZH: "过敏原信息"
141   -
142   ----
143   -
144   -## ❄️ 储存标签字段翻译
145   -
146   -| 英文字段 | 中文字段 |
147   -|----------|----------|
148   -| Storage Temperature | 储存温度 |
149   -| Storage Location | 储存位置 |
150   -| Shelf Life | 保质期 |
151   -| Handling | 处理 |
152   -
153   -**说明文字翻译**:
154   -- EN: "Keep refrigerated. Use clean utensils."
155   -- ZH: "冷藏保存。使用干净的餐具。"
156   -
157   -**标签标题翻译**:
158   -- EN: "STORAGE INSTRUCTIONS"
159   -- ZH: "储存说明"
160   -
161   ----
162   -
163   -## 📅 有效期标签字段翻译
164   -
165   -| 英文字段 | 中文字段 |
166   -|----------|----------|
167   -| Prep Date | 制备日期 |
168   -| Expiry Date | 有效期 |
169   -| Batch Number | 批次号 |
170   -| Prepared By | 制备人 |
171   -
172   -**标签标题翻译**:
173   -- EN: "EXPIRATION DATE"
174   -- ZH: "有效期"
175   -
176   ----
177   -
178   -## 📦 批次跟踪标签字段翻译
179   -
180   -| 英文字段 | 中文字段 |
181   -|----------|----------|
182   -| Batch Number | 批次号 |
183   -| Production Date | 生产日期 |
184   -| Supplier | 供应商 |
185   -| Lot Number | 批号 |
186   -
187   -**供应商名称翻译**:
188   -- EN: "Fresh Foods Co."
189   -- ZH: "新鲜食品公司"
190   -
191   -**标签标题翻译**:
192   -- EN: "BATCH TRACKING"
193   -- ZH: "批次跟踪"
194   -
195   ----
196   -
197   -## 👨‍🍳 制作标签字段翻译
198   -
199   -| 英文字段 | 中文字段 |
200   -|----------|----------|
201   -| Prep Date | 制备日期 |
202   -| Prep Time | 制备时间 |
203   -| Prepared By | 制备人 |
204   -| Location | 位置 |
205   -| Use By | 使用期限 |
206   -
207   -**标签标题翻译**:
208   -- EN: "PREPARATION INFO"
209   -- ZH: "制作信息"
210   -
211   ----
212   -
213   -## 🎯 页面级翻译
214   -
215   -### Labels 页面
216   -| 英文 | 中文 |
217   -|------|------|
218   -| Labels | 标签 |
219   -| Select a label type to print | 选择要打印的标签类型 |
220   -| food items | 食品项目 |
221   -
222   -### Food Select 页面
223   -| 英文 | 中文 |
224   -|------|------|
225   -| Select food item to print label | 选择要打印标签的食品 |
226   -| Search food items... | 搜索食品... |
227   -| No Food Items Found | 未找到食品 |
228   -| Try adjusting your search or browse by category | 尝试调整搜索或按类别浏览 |
229   -
230   -### Label Preview 页面
231   -| 英文 | 中文 |
232   -|------|------|
233   -| Label Preview | 标签预览 |
234   -| Review before printing | 打印前请审查 |
235   -| Printed By | 打印人 |
236   -| Print Date | 打印日期 |
237   -| Print Label | 打印标签 |
238   -| Printing... | 打印中... |
239   -| Label printed successfully! | 标签打印成功! |
240   -
241   -### 提示信息
242   -| 英文 | 中文 |
243   -|------|------|
244   -| Note | 注意 |
245   -| This preview shows how the label will appear when printed. Please verify all information before printing. | 此预览显示标签打印后的外观。请在打印前验证所有信息。 |
246   -
247   ----
248   -
249   -## 🔄 动态翻译特性
250   -
251   -### 1. 搜索功能支持中英文
252   -```typescript
253   -// 在翻译后的文本中搜索
254   -const name = t(food.nameKey).toLowerCase();
255   -const category = t(food.categoryKey).toLowerCase();
256   -const search = searchTerm.toLowerCase();
257   -```
258   -
259   -**示例**:
260   -- 英文搜索 "chicken" → 找到 "Grilled Chicken Breast"
261   -- 中文搜索 "鸡" → 找到 "烤鸡胸肉"
262   -
263   -### 2. 类别自动翻译
264   -```typescript
265   -// 类别标题自动根据语言显示
266   -<h2>{t(categoryKey)}</h2>
267   -```
268   -
269   -**示例**:
270   -- EN: "Meat"
271   -- ZH: "肉类"
272   -
273   -### 3. 标签内容动态翻译
274   -```typescript
275   -// 所有标签字段根据语言动态生成
276   -fields: [
277   - { labelKey: "nutrition.servingSize", value: "150g" },
278   - { labelKey: "nutrition.calories", value: "165 kcal" },
279   -]
280   -```
281   -
282   ----
283   -
284   -## 📱 使用示例
285   -
286   -### 场景 1: 英文用户打印营养标签
287   -```
288   -1. 点击 "Nutrition Label" 🥗
289   -2. 看到 "Select food item to print label"
290   -3. 搜索 "chicken"
291   -4. 看到 "Meat" 类别下的 "Grilled Chicken Breast"
292   -5. 标签显示 "NUTRITION FACTS"
293   -6. 字段显示 "Serving Size", "Calories" 等
294   -7. 点击 "Print Label"
295   -```
296   -
297   -### 场景 2: 中文用户打印营养标签
298   -```
299   -1. 点击 "营养标签" 🥗
300   -2. 看到 "选择要打印标签的食品"
301   -3. 搜索 "鸡"
302   -4. 看到 "肉类" 类别下的 "烤鸡胸肉"
303   -5. 标签显示 "营养成分"
304   -6. 字段显示 "份量", "热量" 等
305   -7. 点击 "打印标签"
306   -```
307   -
308   ----
309   -
310   -## 🎨 标签预览效果
311   -
312   -### 英文标签
313   -```
314   -┌──────────────────────────────────┐
315   -│ ████████████████████████████████ │
316   -│ 🥗 NUTRITION FACTS │
317   -│ ████████████████████████████████ │
318   -├──────────────────────────────────┤
319   -│ Grilled Chicken Breast │
320   -├──────────────────────────────────┤
321   -│ Serving Size 150g │
322   -│ Calories 165 kcal │
323   -│ Total Fat 3.6g │
324   -│ Saturated Fat 1.0g │
325   -│ Protein 31g │
326   -├──────────────────────────────────┤
327   -│ Printed By: John Smith │
328   -│ Print Date: Feb 27, 2026 3:45 PM│
329   -└──────────────────────────────────┘
330   -```
331   -
332   -### 中文标签
333   -```
334   -┌──────────────────────────────────┐
335   -│ ████████████████████████████████ │
336   -│ 🥗 营养成分 │
337   -│ ████████████████████████████████ │
338   -├──────────────────────────────────┤
339   -│ 烤鸡胸肉 │
340   -├──────────────────────────────────┤
341   -│ 份量 150g │
342   -│ 热量 165 kcal │
343   -│ 总脂肪 3.6g │
344   -│ 饱和脂肪 1.0g │
345   -│ 蛋白质 31g │
346   -├──────────────────────────────────┤
347   -│ 打印人: 张三 │
348   -│ 打印日期: 2026年2月27日 下午3:45 │
349   -└──────────────────────────────────┘
350   -```
351   -
352   ----
353   -
354   -## 🔧 技术实现
355   -
356   -### 翻译键结构
357   -```typescript
358   -// 标签类型
359   -"labelType.{type}.name"
360   -"labelType.{type}.desc"
361   -
362   -// 食品
363   -"food.{foodId}"
364   -"food.{foodId}.desc"
365   -
366   -// 类别
367   -"category.{categoryName}"
368   -
369   -// 标签字段
370   -"{labelType}.{fieldName}"
371   -
372   -// 标签标题
373   -"labelPreview.{labelType}"
374   -```
375   -
376   -### 使用方式
377   -```typescript
378   -// 1. 导入翻译钩子
379   -const { t } = useLanguage();
380   -
381   -// 2. 使用翻译键
382   -<h1>{t("labelType.nutrition.name")}</h1>
383   -<p>{t("food.chickenBreast")}</p>
384   -
385   -// 3. 动态翻译
386   -const name = t(food.nameKey);
387   -const category = t(food.categoryKey);
388   -```
389   -
390   ----
391   -
392   -## ✨ 翻译覆盖清单
393   -
394   -### ✅ 页面元素
395   -- [x] 所有页面标题
396   -- [x] 所有按钮文字
397   -- [x] 所有提示信息
398   -- [x] 所有占位符文本
399   -- [x] 所有状态文本
400   -
401   -### ✅ 数据内容
402   -- [x] 6 种标签类型名称
403   -- [x] 6 种标签类型描述
404   -- [x] 15 种食品名称
405   -- [x] 15 种食品描述
406   -- [x] 12 种食品类别
407   -- [x] 所有标签字段名称
408   -- [x] 所有标签标题
409   -
410   -### ✅ 交互反馈
411   -- [x] 加载状态
412   -- [x] 成功提示
413   -- [x] 错误提示
414   -- [x] 空状态提示
415   -
416   -### ✅ 导航
417   -- [x] 底部导航标签
418   -- [x] 返回按钮
419   -- [x] 面包屑
420   -
421   ----
422   -
423   -## 🌍 语言切换
424   -
425   -### 切换位置
426   -```
427   -More → Language / 语言 → 选择语言
428   -```
429   -
430   -### 切换效果
431   -- **即时生效**:所有文字立即切换
432   -- **自动保存**:语言偏好保存到 localStorage
433   -- **全局应用**:所有页面统一语言
434   -
435   ----
436   -
437   -## 📊 翻译质量保证
438   -
439   -### 翻译原则
440   -1. **专业术语准确**:食品、营养相关术语符合行业标准
441   -2. **简洁明了**:中文翻译简洁,易于理解
442   -3. **一致性**:相同概念使用相同翻译
443   -4. **文化适配**:考虑中美文化差异
444   -
445   -### 示例对比
446   -| 类型 | 英文 | 中文 |
447   -|------|------|------|
448   -| 专业 | Saturated Fat | 饱和脂肪 ✅(不是 "饱和的脂肪" ❌)|
449   -| 简洁 | Cross-Contamination Risk | 交叉污染风险 ✅(不是 "交叉污染的风险" ❌)|
450   -| 一致 | Prepared By | 制备人 / 打印人 / 制作人 ✅ 统一使用 |
451   -
452   ----
453   -
454   -## 🎓 用户指南
455   -
456   -### 如何切换语言
457   -1. 点击底部导航 "More / 更多"
458   -2. 点击 "Language / 语言"
459   -3. 选择 "English" 或 "中文(简体)"
460   -4. 系统立即切换到选定语言
461   -
462   -### 中英文对照使用
463   -- **培训场景**:可以在中英文之间切换对照学习
464   -- **国际团队**:不同语言背景的员工都能使用
465   -- **标签要求**:根据客户要求打印中文或英文标签
466   -
467   ----
468   -
469   -## 🚀 总结
470   -
471   -✅ **完整翻译系统**(900+ 键值对)
472   -✅ **所有内容支持中英文**(100% 覆盖)
473   -✅ **动态翻译**(搜索、分类、标签内容)
474   -✅ **专业准确**(食品行业术语标准)
475   -✅ **即时切换**(无需刷新页面)
476   -✅ **持久保存**(语言偏好本地存储)
477   -
478   -系统现在完全支持中英文双语,所有文字、内容、数据都可以根据用户选择的语言动态显示!🎉
美国版/Food Labeling Management App React/IMPLEMENTATION_CHECKLIST.md deleted
1   -# Implementation Checklist ✅
2   -
3   -## 功能需求完成度
4   -
5   -### ✅ 一、整体设计风格要求
6   -- [x] 极简设计
7   -- [x] 大留白
8   -- [x] 不拥挤的布局
9   -- [x] 专业感强
10   -- [x] 功能清晰
11   -- [x] 扁平化 + 轻微阴影
12   -- [x] 卡片式布局
13   -
14   -### ✅ 字体要求
15   -- [x] 标题 22-24px (text-2xl)
16   -- [x] 二级标题 18-20px (text-lg, text-xl)
17   -- [x] 正文 16-18px (text-base)
18   -- [x] 按钮文字 16px (text-base)
19   -- [x] 欧美系统风字体 (Inter)
20   -
21   -### ✅ 按钮要求
22   -- [x] 高度 ≥ 48px (h-12)
23   -- [x] 主按钮明显
24   -- [x] 圆角 8-12px (rounded-lg)
25   -- [x] 强对比度
26   -
27   -### ✅ 颜色体系
28   -- [x] 主色:企业蓝色 (#2563eb)
29   -- [x] 成功:绿色
30   -- [x] 警告:橙色/黄色
31   -- [x] 错误:红色
32   -- [x] 背景:浅灰或白色
33   -
34   -### ✅ 状态标签
35   -- [x] 使用文字标签 (Open / Completed / Expired)
36   -- [x] 不只用图标表达状态
37   -- [x] 状态 + 颜色 + 文字组合
38   -
39   ----
40   -
41   -## ✅ 二、底部导航结构
42   -- [x] 共 4 个 Tab
43   - - [x] Dashboard
44   - - [x] Labels
45   - - [x] Tasks
46   - - [x] More
47   -- [x] 图标 + 文字
48   -- [x] 选中态明显高亮
49   -
50   ----
51   -
52   -## ✅ 三、页面结构设计
53   -
54   -### ✅ 1️⃣ 登录页面
55   -- [x] Logo
56   -- [x] 系统名称
57   -- [x] Email 输入框
58   -- [x] Password 输入框
59   -- [x] Login 按钮
60   -- [x] Forgot Password
61   -- [x] 记住登录状态开关
62   -- [x] 设计简洁,居中布局
63   -
64   -### ✅ 2️⃣ Dashboard 首页
65   -**顶部**
66   -- [x] 当前门店名称
67   -- [x] 当前登录员工姓名
68   -- [x] 在线状态 (Online / Offline)
69   -
70   -**中部卡片布局**
71   -- [x] 卡片 1: Today's Labels - 大数字 + 小说明
72   -- [x] 卡片 2: Open Tasks - 数量
73   -- [x] 卡片 3: Alerts - 数量
74   -- [x] 卡片 4: Devices Status - Online/Offline 数量
75   -- [x] 卡片可点击跳转
76   -
77   -**Quick Actions 区域**
78   -- [x] Scan & Print
79   -- [x] Batch Print
80   -- [x] Record Temperature
81   -- [x] Report Waste
82   -
83   -### ✅ 3️⃣ Labels 模块
84   -
85   -**3.1 标签列表页**
86   -- [x] 顶部搜索框
87   -- [x] 筛选 Tabs (All, Expiring Soon, Expired)
88   -- [x] 列表项展示
89   - - [x] 食材名称
90   - - [x] 批次号
91   - - [x] 到期日期
92   - - [x] 状态标签 (绿色正常/黄色临期/红色过期)
93   - - [x] 右侧大按钮: Print
94   -- [x] 列表间距大,不拥挤
95   -- [x] 空状态页面 (No Labels Found)
96   -
97   -**3.2 打印确认页面**
98   -- [x] 食材名称 (大标题)
99   -- [x] 批次号
100   -- [x] 到期时间
101   -- [x] 模板名称 (只读/下拉)
102   -- [x] Multiple Options 下拉选择
103   -- [x] 打印数量 +/- 控件
104   -- [x] 打印机选择下拉框
105   -- [x] 预览区域 (标签小预览)
106   -- [x] 底部固定大按钮: PRINT LABEL
107   -
108   -**3.3 打印任务队列页面**
109   -- [x] 分区展示
110   - - [x] In Progress
111   - - [x] Completed
112   - - [x] Failed
113   -- [x] 失败任务右侧有 Retry 按钮
114   -
115   -### ✅ 4️⃣ Tasks 模块
116   -
117   -**4.1 任务列表页**
118   -- [x] 分类展示
119   - - [x] Temperature Check
120   - - [x] Hygiene Check
121   - - [x] Equipment Check
122   -- [x] 每条任务显示
123   - - [x] 任务名称
124   - - [x] Due 时间
125   - - [x] 状态标签 (Open/Completed/Overdue)
126   - - [x] Start 按钮
127   -
128   -**4.2 任务执行页面**
129   -- [x] 数字输入 (例如温度)
130   -- [x] 单选
131   -- [x] 多选
132   -- [x] 文本输入
133   -- [x] 上传照片按钮
134   -- [x] 签名区域 (可作为备注输入)
135   -- [x] 异常值自动变红显示
136   -- [x] 底部固定按钮: SUBMIT TASK
137   -
138   -**4.3 异常整改页面**
139   -- [x] 异常说明
140   -- [x] 上传整改照片
141   -- [x] 整改备注输入框
142   -- [x] 提交按钮
143   -
144   -### ✅ 5️⃣ More 模块
145   -- [x] Profile
146   -- [x] Printers
147   -- [x] Location Info
148   -- [x] Sync Status
149   -- [x] Support
150   -- [x] Logout
151   -
152   ----
153   -
154   -## ✅ 四、系统状态页面要求
155   -- [x] 加载中页面
156   -- [x] 空数据页面
157   -- [x] 网络断开提示页面
158   -- [x] 打印失败提示页面
159   -- [x] 操作成功提示页面
160   -
161   ----
162   -
163   -## ✅ 五、交互要求
164   -- [x] 页面结构尽量一屏完成主要操作
165   -- [x] 重要按钮必须固定底部
166   -- [x] 所有操作都有反馈 (toast notifications)
167   -- [x] 不要层级太深 (最多 3 级)
168   -- [x] 操作路径简洁
169   -
170   ----
171   -
172   -## ✅ 技术实现
173   -
174   -### 核心功能
175   -- [x] React Router v7 路由系统
176   -- [x] 底部标签导航
177   -- [x] 登录认证 (localStorage)
178   -- [x] 页面状态管理
179   -- [x] Toast 通知系统
180   -
181   -### 设计系统
182   -- [x] Tailwind CSS v4
183   -- [x] Inter 字体
184   -- [x] 企业蓝色主题
185   -- [x] 响应式布局 (移动端优先)
186   -- [x] 卡片式组件
187   -
188   -### UI 组件
189   -- [x] Radix UI 组件库
190   -- [x] Lucide React 图标
191   -- [x] 状态组件 (Loading, Empty, Error, Success)
192   -- [x] 表单组件 (Input, Select, Textarea, Checkbox, Radio)
193   -
194   -### 页面完整性
195   -- [x] 15+ 完整页面
196   -- [x] 4 个状态组件
197   -- [x] 1 个主布局组件
198   -- [x] 完整的导航系统
199   -
200   ----
201   -
202   -## ✅ 文档完整性
203   -- [x] README.md - 项目总览
204   -- [x] PROJECT_OVERVIEW.md - 详细功能说明
205   -- [x] USAGE_GUIDE.md - 用户使用指南
206   -- [x] TECHNICAL_DOCS.md - 技术文档
207   -- [x] PAGE_REFERENCE.md - 页面快速参考
208   -- [x] IMPLEMENTATION_CHECKLIST.md - 实现清单
209   -
210   ----
211   -
212   -## 📊 统计数据
213   -
214   -### 页面数量
215   -- **认证页面**: 1
216   -- **主要页面**: 4 (Dashboard, Labels, Tasks, More)
217   -- **子页面**: 10
218   -- **状态组件**: 4
219   -- **总计**: 19+ 组件
220   -
221   -### 代码结构
222   -- **路由配置**: 1 文件
223   -- **主布局**: 1 文件
224   -- **页面组件**: 15 文件
225   -- **状态组件**: 4 文件
226   -- **样式文件**: 4 文件
227   -
228   -### 设计规范
229   -- **颜色方案**: 5 种主要颜色
230   -- **字体大小**: 4 个层级
231   -- **按钮高度**: 48px-56px
232   -- **卡片间距**: 12px-24px
233   -- **最大宽度**: 480px (移动端)
234   -
235   ----
236   -
237   -## 🎯 质量标准
238   -
239   -### 用户体验 ✅
240   -- [x] 清晰的视觉层级
241   -- [x] 一致的交互模式
242   -- [x] 友好的错误提示
243   -- [x] 即时反馈机制
244   -- [x] 简洁的操作流程
245   -
246   -### 可访问性 ✅
247   -- [x] 高对比度颜色
248   -- [x] 清晰的文字标签
249   -- [x] 大触摸目标 (48px+)
250   -- [x] 语义化 HTML
251   -- [x] 键盘导航支持
252   -
253   -### 性能 ✅
254   -- [x] 轻量级组件
255   -- [x] 按需加载
256   -- [x] 优化的资源
257   -- [x] 快速响应
258   -
259   -### 代码质量 ✅
260   -- [x] TypeScript 类型安全
261   -- [x] 组件化架构
262   -- [x] 可复用的组件
263   -- [x] 清晰的文件结构
264   -- [x] 一致的命名规范
265   -
266   ----
267   -
268   -## 🚀 部署就绪
269   -
270   -### 生产环境准备
271   -- [x] 构建配置完整
272   -- [x] 环境变量支持
273   -- [x] 静态资源优化
274   -- [x] 路由配置正确
275   -
276   -### 未来增强准备
277   -- [ ] 后端 API 集成点
278   -- [ ] 离线功能支持
279   -- [ ] 多语言支持
280   -- [ ] 高级分析功能
281   -
282   ----
283   -
284   -## ✨ 总结
285   -
286   -**完成度**: 100% ✅
287   -
288   -所有用户需求已完全实现:
289   -- ✅ 15+ 完整页面
290   -- ✅ 完整的导航系统
291   -- ✅ 企业级设计风格
292   -- ✅ 移动端优化
293   -- ✅ 状态管理
294   -- ✅ 完整文档
295   -
296   -**技术栈**: React + TypeScript + Tailwind CSS + React Router
297   -**设计风格**: 欧美企业级 SaaS
298   -**目标市场**: 餐饮食品行业
299   -**设备支持**: iOS & Android 通用
300   -
301   ----
302   -
303   -**项目状态**: ✅ 已完成,可交付使用
304   -**最后更新**: 2026年2月
305   -**版本**: 1.0.0
美国版/Food Labeling Management App React/LABEL_PRINTING_FLOW.md deleted
1   -# 标签打印流程说明
2   -
3   -## 新流程概述
4   -
5   -标签打印现在采用三步流程,更符合实际业务场景:
6   -
7   -### 第一步:选择标签类型
8   -**页面:** `/labels` (Labels.tsx)
9   -
10   -用户可以从以下六种标签类型中选择:
11   -
12   -1. **营养标签 (Nutrition Labels)** 🥗
13   - - 用途:完整的营养信息和配料表
14   - - 适用于:需要标注营养成分的食品
15   -
16   -2. **过敏原标签 (Allergen Labels)** ⚠️
17   - - 用途:过敏原警告和交叉污染信息
18   - - 适用于:含过敏原的食品
19   -
20   -3. **储存标签 (Storage Labels)** ❄️
21   - - 用途:储存温度和处理说明
22   - - 适用于:需要特定储存条件的食品
23   -
24   -4. **有效期标签 (Expiry Date Labels)** 📅
25   - - 用途:使用期限和最佳食用日期
26   - - 适用于:所有有时效性的食品
27   -
28   -5. **批次追踪标签 (Batch Tracking Labels)** 📦
29   - - 用途:批次号和生产信息
30   - - 适用于:需要批次追溯的食品
31   -
32   -6. **制作标签 (Preparation Labels)** 👨‍🍳
33   - - 用途:制作日期、时间和员工信息
34   - - 适用于:现场制作的预制食品
35   -
36   -### 第二步:选择食品
37   -**页面:** `/labels/:type/select` (LabelFoodSelect.tsx)
38   -
39   -- 根据选择的标签类型,显示相应的食品列表
40   -- 支持搜索和分类筛选功能
41   -- 显示每个食品的类别和上次打印时间
42   -
43   -### 第三步:填写信息并打印
44   -**页面:** `/labels/:type/:foodId/print` (LabelPrint.tsx)
45   -
46   -#### 根据不同标签类型显示不同的必填字段:
47   -
48   -**营养标签**
49   -- 份量 (必填)
50   -- 每份热量 (必填)
51   -- 总脂肪 (必填)
52   -- 蛋白质 (必填)
53   -- 配料表 (必填)
54   -
55   -**过敏原标签**
56   -- 包含过敏原 (必填,下拉选择)
57   -- 交叉污染风险 (必填,下拉选择)
58   -- 附加信息 (可选)
59   -
60   -**储存标签**
61   -- 储存温度 (必填,下拉选择)
62   -- 储存位置 (必填,下拉选择)
63   -- 处理说明 (必填)
64   -
65   -**有效期标签**
66   -- 制作日期 (必填,日期选择)
67   -- 有效期 (必填,日期选择)
68   -- 批次号 (必填)
69   -
70   -**批次追踪标签**
71   -- 批次号 (必填)
72   -- 生产日期 (必填,日期选择)
73   -- 批号 (可选)
74   -- 供应商 (必填)
75   -
76   -**制作标签**
77   -- 制作日期 (必填,日期选择)
78   -- 制作时间 (必填)
79   -- 制作人 (必填)
80   -- 使用期限 (必填,日期选择)
81   -
82   -#### 打印设置
83   -- 打印数量
84   -- 选择打印机
85   -
86   -#### 实时预览
87   -- 根据填写的信息实时显示标签预览效果
88   -
89   -## 路由结构
90   -
91   -```
92   -/labels → 标签类型选择
93   -/labels/:type/select → 食品选择
94   -/labels/:type/:foodId/print → 填写信息并打印
95   -/labels/queue → 打印队列
96   -```
97   -
98   -## 设计特点
99   -
100   -✅ **逐步引导:** 三步流程清晰,不会让用户迷失
101   -✅ **类型明确:** 每种标签类型有独立的字段配置
102   -✅ **验证完整:** 必填字段验证,防止信息遗漏
103   -✅ **即时预览:** 填写内容实时反映在标签预览中
104   -✅ **符合规范:** 符合欧美市场食品安全标签要求
105   -
106   -## 扩展性
107   -
108   -系统设计支持轻松添加新的标签类型:
109   -
110   -1. 在 `Labels.tsx` 中添加新类型
111   -2. 在 `LabelFoodSelect.tsx` 的 `foodsByType` 中添加对应食品
112   -3. 在 `LabelPrint.tsx` 的 `fieldsByType` 中配置表单字段
113   -4. 系统会自动处理路由和表单验证
美国版/Food Labeling Management App React/LABEL_PRINTING_SYSTEM.md deleted
1   -# 🎉 标签打印系统 - 最终版本
2   -
3   -## ✅ 完整的标签打印流程
4   -
5   -### 📱 用户流程
6   -
7   -```
8   -1️⃣ Labels(选择标签类型)
9   - ↓
10   -2️⃣ 选择食品(带图片)
11   - ↓
12   -3️⃣ 查看预览(实际标签样式)
13   - ↓
14   -4️⃣ 点击打印
15   -```
16   -
17   ----
18   -
19   -## 🏷️ 6 种标签类型
20   -
21   -### 1. **Nutrition Label** 🥗
22   -**营养成分标签**
23   -- 份量、热量、脂肪、蛋白质等
24   -- 完整的营养信息表格
25   -- 符合食品标签规范
26   -
27   -### 2. **Allergen Label** ⚠️
28   -**过敏原标签**
29   -- 包含的过敏原
30   -- 可能含有的成分
31   -- 交叉污染风险信息
32   -
33   -### 3. **Storage Label** ❄️
34   -**储存标签**
35   -- 储存温度要求
36   -- 储存位置
37   -- 保质期和处理说明
38   -
39   -### 4. **Expiry Date Label** 📅
40   -**保质期标签**
41   -- 制作日期
42   -- 过期日期
43   -- 批次号和制作人
44   -
45   -### 5. **Batch Tracking Label** 📦
46   -**批次追踪标签**
47   -- 批次号
48   -- 生产日期
49   -- 供应商信息
50   -- 批号
51   -
52   -### 6. **Preparation Label** 👨‍🍳
53   -**制备标签**
54   -- 制作日期和时间
55   -- 制作人员
56   -- 使用期限
57   -- 制作地点
58   -
59   ----
60   -
61   -## 🍽️ 15+ 种食品(带真实图片)
62   -
63   -| 食品 | 类别 | 图片来源 |
64   -|-----|------|---------|
65   -| Grilled Chicken Breast | 肉类 | ✅ Unsplash |
66   -| Caesar Salad | 沙拉 | ✅ Unsplash |
67   -| Fresh Salmon Fillet | 海鲜 | ✅ Unsplash |
68   -| Ground Beef Patties | 肉类 | ✅ Unsplash |
69   -| Marinara Sauce | 酱料 | ✅ Unsplash |
70   -| Pre-cut Vegetables | 蔬菜 | ✅ Unsplash |
71   -| Chocolate Brownie | 甜点 | ✅ Unsplash |
72   -| Shrimp Pasta | 预制品 | ✅ Unsplash |
73   -| Vanilla Ice Cream | 冷冻 | ✅ Unsplash |
74   -| Club Sandwich | 预制品 | ✅ Unsplash |
75   -| Greek Yogurt | 乳制品 | ✅ Unsplash |
76   -| Whole Wheat Bread | 烘焙 | ✅ Unsplash |
77   -| Mixed Berry Smoothie | 饮品 | ✅ Unsplash |
78   -| Roasted Turkey Breast | 肉类 | ✅ Unsplash |
79   -| Tomato Soup | 汤品 | ✅ Unsplash |
80   -
81   ----
82   -
83   -## 🎨 标签预览设计
84   -
85   -### 标签结构
86   -```
87   -┌──────────────────────────────────┐
88   -│ ████████████████████████████████ │ ← 黑色标题栏
89   -│ 🥗 NUTRITION FACTS │ (带图标和标签类型)
90   -│ ████████████████████████████████ │
91   -├──────────────────────────────────┤
92   -│ Grilled Chicken Breast │ ← 灰色食品名称栏
93   -├──────────────────────────────────┤
94   -│ │
95   -│ Serving Size 150g │ ← 详细信息
96   -│ ────────────────────────────────│
97   -│ Calories 165 kcal │
98   -│ ────────────────────────────────│
99   -│ Total Fat 3.6g │
100   -│ ────────────────────────────────│
101   -│ Saturated Fat 1.0g │ (缩进显示子项)
102   -│ ────────────────────────────────│
103   -│ Protein 31g │
104   -│ │
105   -├──────────────────────────────────┤
106   -│ Printed By: John Smith │ ← 灰色页脚
107   -│ Print Date: Feb 27, 2026 3:45 PM│ (打印信息)
108   -└──────────────────────────────────┘
109   -```
110   -
111   -### 设计特点
112   -- ✅ 黑色粗边框(4px)
113   -- ✅ 黑色标题栏 + 白色文字
114   -- ✅ 清晰的分隔线
115   -- ✅ 层级结构明确
116   -- ✅ 缩进显示子项(如 Saturated Fat)
117   -- ✅ 加粗显示重要信息
118   -- ✅ 过敏原信息用红色高亮
119   -
120   ----
121   -
122   -## 🌐 完整中英文翻译
123   -
124   -### 翻译覆盖
125   -- ✅ **标签类型名称**(6种)
126   -- ✅ **所有页面标题**
127   -- ✅ **按钮和操作**
128   -- ✅ **表单字段**
129   -- ✅ **提示信息**
130   -- ✅ **状态文本**
131   -- ✅ **底部导航**
132   -
133   -### 示例对比
134   -
135   -| 英文 | 中文 |
136   -|------|------|
137   -| Nutrition Label | 营养成分标签 |
138   -| Select food item to print label | 选择要打印标签的食品 |
139   -| Label Preview | 标签预览 |
140   -| Print Label | 打印标签 |
141   -| Printing... | 打印中... |
142   -| Label printed successfully! | 标签打印成功! |
143   -
144   ----
145   -
146   -## 📂 文件结构
147   -
148   -```
149   -/src/app/
150   -├── pages/
151   -│ ├── Labels.tsx ✅ 标签类型选择
152   -│ ├── LabelFoodSelect.tsx ✅ 食品选择(带图片)
153   -│ ├── LabelPreview.tsx ✅ 标签预览 + 打印
154   -│ ├── Dashboard.tsx ✅ 主页
155   -│ ├── Tasks.tsx ✅ 任务
156   -│ ├── More.tsx ✅ 更多设置
157   -│ └── more/
158   -│ └── LanguageSettings.tsx ✅ 语言设置
159   -├── contexts/
160   -│ └── LanguageContext.tsx ✅ 700+ 翻译
161   -├── components/
162   -│ └── Layout.tsx ✅ 底部导航
163   -└── routes.tsx ✅ 路由配置
164   -```
165   -
166   ----
167   -
168   -## 🎯 关键功能
169   -
170   -### 1. 智能标签生成
171   -每种标签类型自动生成对应内容:
172   -- **Nutrition**: 自动计算营养成分
173   -- **Allergen**: 根据食品生成过敏原清单
174   -- **Storage**: 根据食品类别生成储存要求
175   -- **Expiry**: 自动计算5天保质期
176   -- **Batch**: 自动生成批次号和批号
177   -- **Preparation**: 自动填入当前员工和时间
178   -
179   -### 2. 真实标签预览
180   -- 黑白打印风格
181   -- 清晰的层级结构
182   -- 符合食品标签规范
183   -- 打印前可验证所有信息
184   -
185   -### 3. 搜索和筛选
186   -- 按食品名称搜索
187   -- 按类别筛选
188   -- 自动分类显示
189   -
190   -### 4. 打印模拟
191   -- 2秒打印动画
192   -- 成功提示
193   -- 自动返回标签列表
194   -
195   ----
196   -
197   -## 💡 使用场景
198   -
199   -### 场景 1: 营养成分标签
200   -```
201   -餐厅经理需要为新菜品打印营养标签:
202   -1. 点击 "Nutrition Label"
203   -2. 选择 "Grilled Chicken Breast"
204   -3. 查看完整营养成分表
205   -4. 确认无误后点击 "Print Label"
206   -5. 标签打印完成
207   -```
208   -
209   -### 场景 2: 过敏原标签
210   -```
211   -厨房员工需要为沙拉打印过敏原标签:
212   -1. 点击 "Allergen Label"
213   -2. 选择 "Caesar Salad"
214   -3. 查看包含的过敏原(Tree Nuts, Dairy, Eggs, Wheat)
215   -4. 查看交叉污染风险
216   -5. 打印并贴在食品容器上
217   -```
218   -
219   -### 场景 3: 储存标签
220   -```
221   -食品加工员工需要为三文鱼打印储存标签:
222   -1. 点击 "Storage Label"
223   -2. 选择 "Fresh Salmon Fillet"
224   -3. 查看储存温度(32-40°F)和位置
225   -4. 查看处理说明
226   -5. 打印并贴在储存容器上
227   -```
228   -
229   ----
230   -
231   -## 🎨 UI/UX 特点
232   -
233   -### 移动优先设计
234   -- ✅ 单列布局
235   -- ✅ 大按钮(48px+)
236   -- ✅ 清晰的层级
237   -- ✅ 易于点击的卡片
238   -
239   -### 视觉设计
240   -- ✅ 极简风格
241   -- ✅ 大留白
242   -- ✅ 卡片式布局
243   -- ✅ 企业蓝主色调
244   -
245   -### 交互体验
246   -- ✅ 即时反馈
247   -- ✅ 加载动画
248   -- ✅ 成功提示
249   -- ✅ 清晰的导航
250   -
251   -### 状态管理
252   -- ✅ 所有状态用文字标签
253   -- ✅ 配合颜色区分
254   -- ✅ 图标辅助识别
255   -
256   ----
257   -
258   -## 📊 数据示例
259   -
260   -### 营养标签数据
261   -```json
262   -{
263   - "title": "NUTRITION FACTS",
264   - "fields": [
265   - { "label": "Serving Size", "value": "150g" },
266   - { "label": "Calories", "value": "165 kcal", "bold": true },
267   - { "label": "Total Fat", "value": "3.6g" },
268   - { "label": " Saturated Fat", "value": "1.0g", "indent": true },
269   - { "label": "Protein", "value": "31g", "bold": true }
270   - ]
271   -}
272   -```
273   -
274   -### 过敏原标签数据
275   -```json
276   -{
277   - "title": "ALLERGEN INFORMATION",
278   - "fields": [
279   - {
280   - "label": "Contains",
281   - "value": "Tree Nuts, Dairy, Eggs",
282   - "warning": true
283   - },
284   - { "label": "May Contain", "value": "Sesame, Soy" },
285   - { "label": "Cross-Contamination Risk", "value": "Low" }
286   - ]
287   -}
288   -```
289   -
290   ----
291   -
292   -## 🚀 技术实现
293   -
294   -### React Router 路由
295   -```typescript
296   -/labels → 标签类型列表
297   -/labels/:labelType/foods → 食品选择
298   -/labels/:labelType/:foodId/preview → 标签预览
299   -```
300   -
301   -### 动态数据生成
302   -```typescript
303   -const getLabelPreviewData = (labelType: string, foodId: string) => {
304   - // 根据标签类型和食品ID自动生成标签数据
305   -}
306   -```
307   -
308   -### 响应式图片
309   -- 列表缩略图: 80x80px
310   -- 预览大图: 全宽 x 600px
311   -
312   ----
313   -
314   -## ✨ 核心优势
315   -
316   -| 特性 | 说明 |
317   -|------|------|
318   -| 🎯 **精准定位** | 专为餐饮食品行业设计 |
319   -| 📱 **移动优先** | 完美适配手机端操作 |
320   -| 🌐 **国际化** | 完整中英文支持 |
321   -| 🖼️ **视觉丰富** | 所有食品都有真实图片 |
322   -| 🏷️ **专业标签** | 符合食品标签规范 |
323   -| ⚡ **快速打印** | 3步完成打印流程 |
324   -| 🎨 **企业风格** | 极简专业的设计 |
325   -
326   ----
327   -
328   -## 🎓 用户培训要点
329   -
330   -### 新员工培训
331   -1. **了解6种标签类型**及其用途
332   -2. **学会搜索食品**并快速找到目标
333   -3. **理解标签预览**并验证信息准确性
334   -4. **掌握打印操作**的完整流程
335   -
336   -### 常见问题
337   -**Q: 如何修改标签内容?**
338   -A: 当前版本标签内容自动生成,后续可添加自定义编辑功能。
339   -
340   -**Q: 可以打印多份吗?**
341   -A: 可以重复进入预览页面多次打印。
342   -
343   -**Q: 标签尺寸是多少?**
344   -A: 标签设计适配标准热敏打印机(2英寸宽度)。
345   -
346   ----
347   -
348   -## 📝 总结
349   -
350   -✅ **完整的标签打印流程**(3步)
351   -✅ **6种专业标签类型**
352   -✅ **15+种食品**(带高清图片)
353   -✅ **真实标签预览**(符合规范)
354   -✅ **完整中英文翻译**(700+键值对)
355   -✅ **极简企业风格**(移动优先)
356   -
357   -系统已经完全实现您的需求,可以投入使用!🎉
美国版/Food Labeling Management App React/LANGUAGE_SWITCHING_GUIDE.md deleted
1   -# 语言切换功能说明 / Language Switching Guide
2   -
3   -## 功能概述 / Overview
4   -
5   -系统已经实现了完整的中英文切换功能,用户可以随时在应用中切换界面语言。
6   -
7   -The system now supports full bilingual (English/Chinese) language switching, allowing users to change the interface language at any time.
8   -
9   ----
10   -
11   -## 如何切换语言 / How to Switch Language
12   -
13   -### 方法一:通过 More 页面 / Via More Page
14   -
15   -1. 点击底部导航栏的 **More** (更多) 标签
16   -2. 选择 **Language / 语言** 选项
17   -3. 在语言设置页面中选择您喜欢的语言:
18   - - 🇺🇸 **English**
19   - - 🇨🇳 **中文(简体)**
20   -4. 选择后语言将立即生效
21   -
22   -**步骤:**
23   -```
24   -More (更多) → Language / 语言 → 选择语言 → 自动切换
25   -```
26   -
27   ----
28   -
29   -## 已翻译的页面 / Translated Pages
30   -
31   -### ✅ 核心页面 / Core Pages
32   -
33   -1. **登录页面 / Login**
34   - - 所有表单字段和按钮
35   -
36   -2. **主页 / Dashboard**
37   - - 统计数据卡片
38   - - 快捷操作按钮
39   -
40   -3. **标签管理 / Labels**
41   - - 标签类型列表(6种类型)
42   - - 食品选择页面
43   - - 打印设置页面
44   - - 打印队列
45   -
46   -4. **任务管理 / Tasks**
47   - - 任务列表
48   - - 任务执行页面
49   -
50   -5. **更多 / More**
51   - - 所有菜单项
52   - - 个人资料
53   - - 打印机设置
54   - - 工作地点
55   - - 同步状态
56   - - 语言设置
57   - - 支持中心
58   -
59   -6. **底部导航栏 / Bottom Navigation**
60   - - Dashboard (主页)
61   - - Labels (标签)
62   - - Tasks (任务)
63   - - More (更多)
64   -
65   ----
66   -
67   -## 技术实现 / Technical Implementation
68   -
69   -### 语言管理系统 / Language Management
70   -
71   -**文件位置:** `/src/app/contexts/LanguageContext.tsx`
72   -
73   -系统使用 React Context 实现语言管理:
74   -
75   -```tsx
76   -import { useLanguage } from "../contexts/LanguageContext";
77   -
78   -function MyComponent() {
79   - const { language, setLanguage, t } = useLanguage();
80   -
81   - return <h1>{t("labels.title")}</h1>;
82   -}
83   -```
84   -
85   -### 翻译函数 / Translation Function
86   -
87   -使用 `t()` 函数获取翻译文本:
88   -
89   -```tsx
90   -// 获取翻译
91   -t("labels.title") // 英文: "Labels" / 中文: "标签"
92   -t("common.back") // 英文: "Back" / 中文: "返回"
93   -t("labels.type.nutrition") // 英文: "Nutrition Labels" / 中文: "营养标签"
94   -```
95   -
96   -### 语言存储 / Language Storage
97   -
98   -- 用户选择的语言保存在 `localStorage` 中
99   -- 下次打开应用时自动加载上次选择的语言
100   -- 默认语言:English (英文)
101   -
102   ----
103   -
104   -## 翻译键值示例 / Translation Key Examples
105   -
106   -### 通用 / Common
107   -```
108   -common.back → Back / 返回
109   -common.save → Save / 保存
110   -common.cancel → Cancel / 取消
111   -common.search → Search / 搜索
112   -common.online → Online / 在线
113   -```
114   -
115   -### 标签相关 / Labels
116   -```
117   -labels.title → Labels / 标签
118   -labels.type.nutrition → Nutrition Labels / 营养标签
119   -labels.type.allergen → Allergen Labels / 过敏原标签
120   -labels.selectFood → Select a food item to print / 选择要打印的食品
121   -labels.print.printLabel → Print Label / 打印标签
122   -```
123   -
124   -### 表单字段 / Form Fields
125   -```
126   -field.servingSize → Serving Size / 份量
127   -field.calories → Calories (per serving) / 热量(每份)
128   -field.allergens → Contains Allergens / 包含过敏原
129   -field.batchNumber → Batch Number / 批次号
130   -```
131   -
132   ----
133   -
134   -## 扩展翻译 / Extending Translations
135   -
136   -如需添加新的翻译,编辑 `/src/app/contexts/LanguageContext.tsx`:
137   -
138   -```tsx
139   -// English translations
140   -const translationsEn: Record<string, string> = {
141   - "myapp.newkey": "New Text",
142   - // ... more translations
143   -};
144   -
145   -// Chinese translations
146   -const translationsZh: Record<string, string> = {
147   - "myapp.newkey": "新文本",
148   - // ... more translations
149   -};
150   -```
151   -
152   -然后在组件中使用:
153   -```tsx
154   -const { t } = useLanguage();
155   -<p>{t("myapp.newkey")}</p>
156   -```
157   -
158   ----
159   -
160   -## 语言覆盖率 / Translation Coverage
161   -
162   -✅ **100%** - 底部导航栏
163   -✅ **100%** - 标签管理流程(类型选择 → 食品选择 → 打印)
164   -✅ **100%** - More 页面及所有子页面
165   -✅ **90%+** - 其他核心页面
166   -
167   -部分模拟数据(如食品名称、类别)保留英文,以保持数据真实性。
168   -
169   ----
170   -
171   -## 最佳实践 / Best Practices
172   -
173   -1. **始终使用翻译函数**
174   - 永远不要在代码中硬编码文本,而是使用 `t()` 函数
175   -
176   -2. **语义化的键名**
177   - 使用有意义的键名,如 `labels.type.nutrition` 而不是 `lbl1`
178   -
179   -3. **保持一致性**
180   - 相同的文本使用相同的翻译键,如 "Back" 始终使用 `common.back`
181   -
182   -4. **测试两种语言**
183   - 在添加新功能时,确保两种语言都能正常显示
184   -
185   ----
186   -
187   -## 未来改进 / Future Improvements
188   -
189   -- [ ] 添加更多语言支持(西班牙语、法语等)
190   -- [ ] 日期和数字的本地化格式
191   -- [ ] 动态加载语言包(减小打包体积)
192   -- [ ] 翻译管理后台
193   -
194   ----
195   -
196   -## 常见问题 / FAQ
197   -
198   -**Q: 切换语言后需要刷新页面吗?**
199   -A: 不需要,语言切换是实时生效的。
200   -
201   -**Q: 语言设置会丢失吗?**
202   -A: 不会,语言设置保存在浏览器本地存储中,除非清除浏览器数据。
203   -
204   -**Q: 如何恢复默认语言?**
205   -A: 在语言设置页面选择 English 即可。
206   -
207   -**Q: 所有页面都支持中文吗?**
208   -A: 是的,所有核心功能页面都已完全翻译。部分模拟数据可能保留英文。
美国版/Food Labeling Management App React/PAGE_REFERENCE.md deleted
1   -# Page Reference Guide
2   -
3   -Quick reference for all pages in the Food Label System.
4   -
5   -## 📄 All Pages
6   -
7   -### Authentication
8   -| Page | Route | Description |
9   -|------|-------|-------------|
10   -| Login | `/login` | Email/password authentication with remember me option |
11   -
12   -### Main Navigation (Bottom Tabs)
13   -
14   -#### 🏠 Dashboard
15   -| Page | Route | Description |
16   -|------|-------|-------------|
17   -| Dashboard | `/` | Overview with stats cards and quick action buttons |
18   -
19   -#### 🏷️ Labels
20   -| Page | Route | Description |
21   -|------|-------|-------------|
22   -| Label List | `/labels` | Browse, search, and filter labels by status |
23   -| Print Label | `/labels/print/:id` | Configure and print label (template, quantity, printer) |
24   -| Print Queue | `/labels/queue` | View print jobs (in progress, completed, failed) |
25   -
26   -#### ✅ Tasks
27   -| Page | Route | Description |
28   -|------|-------|-------------|
29   -| Task List | `/tasks` | View tasks organized by status (overdue, open, completed) |
30   -| Execute Task | `/tasks/:id` | Complete task with forms (temperature, checks, photos) |
31   -| Report Issue | `/tasks/:id/issue` | Report issues with corrective actions and photos |
32   -
33   -#### ⚙️ More
34   -| Page | Route | Description |
35   -|------|-------|-------------|
36   -| More Menu | `/more` | Settings and additional features menu |
37   -| Profile | `/more/profile` | View and edit employee profile information |
38   -| Printers | `/more/printers` | View printer status and configuration |
39   -| Location Info | `/more/location` | Store location and contact information |
40   -| Sync Status | `/more/sync` | Data synchronization status and manual sync |
41   -| Support | `/more/support` | Help, support contacts, and resources |
42   -
43   -### Utility
44   -| Page | Route | Description |
45   -|------|-------|-------------|
46   -| 404 Not Found | `*` | Catch-all for invalid routes |
47   -
48   -## 🎨 Page Elements
49   -
50   -### Common Header Pattern
51   -```tsx
52   -<div className="bg-white border-b border-gray-200 p-6">
53   - <h1 className="text-2xl font-semibold text-gray-900">
54   - Page Title
55   - </h1>
56   -</div>
57   -```
58   -
59   -### Common Back Button
60   -```tsx
61   -<button onClick={() => navigate(-1)} className="flex items-center text-blue-600 mb-4">
62   - <ChevronLeft className="w-5 h-5" />
63   - <span className="text-base font-medium ml-1">Back</span>
64   -</button>
65   -```
66   -
67   -### Status Badge Examples
68   -
69   -**Label Status**
70   -- 🟢 Normal: `bg-green-50 text-green-700 border-green-200`
71   -- 🟡 Expiring Soon: `bg-yellow-50 text-yellow-700 border-yellow-200`
72   -- 🔴 Expired: `bg-red-50 text-red-700 border-red-200`
73   -
74   -**Task Status**
75   -- 🔵 Open: `bg-blue-50 text-blue-700 border-blue-200`
76   -- 🟢 Completed: `bg-green-50 text-green-700 border-green-200`
77   -- 🔴 Overdue: `bg-red-50 text-red-700 border-red-200`
78   -
79   -**Printer Status**
80   -- 🟢 Online: `bg-green-50 text-green-700 border-green-200`
81   -- ⚫ Offline: `bg-gray-100 text-gray-600 border-gray-300`
82   -
83   -## 🔄 Page Flows
84   -
85   -### Flow 1: Print a Label
86   -1. `/` (Dashboard) → Tap "Labels" or "Scan & Print"
87   -2. `/labels` → Select label → Tap "Print Label"
88   -3. `/labels/print/:id` → Configure → Tap "Print Label"
89   -4. `/labels/queue` → View print status
90   -
91   -### Flow 2: Complete a Task
92   -1. `/` (Dashboard) → Tap "Tasks" or "Record Temperature"
93   -2. `/tasks` → Select task → Tap "Start Task"
94   -3. `/tasks/:id` → Fill form → Tap "Submit Task"
95   -4. If issue detected → `/tasks/:id/issue` → Report issue
96   -
97   -### Flow 3: Check Settings
98   -1. `/` (Dashboard) → Tap "More"
99   -2. `/more` → Select option
100   -3. `/more/profile` or `/more/printers` etc.
101   -
102   -### Flow 4: Logout
103   -1. `/more` → Scroll to "Logout"
104   -2. Confirm logout
105   -3. Redirected to `/login`
106   -
107   -## 📊 Data Models
108   -
109   -### Label
110   -```typescript
111   -interface Label {
112   - id: string;
113   - name: string;
114   - batchNumber: string;
115   - expiryDate: string;
116   - status: "normal" | "expiring" | "expired";
117   -}
118   -```
119   -
120   -### Task
121   -```typescript
122   -interface Task {
123   - id: string;
124   - name: string;
125   - type: "temperature" | "hygiene" | "equipment";
126   - dueTime: string;
127   - status: "open" | "completed" | "overdue";
128   -}
129   -```
130   -
131   -### Print Job
132   -```typescript
133   -interface PrintJob {
134   - id: string;
135   - labelName: string;
136   - quantity: number;
137   - printer: string;
138   - status: "progress" | "completed" | "failed";
139   - time: string;
140   -}
141   -```
142   -
143   -### Printer
144   -```typescript
145   -interface Printer {
146   - id: string;
147   - name: string;
148   - location: string;
149   - status: "online" | "offline";
150   - model: string;
151   -}
152   -```
153   -
154   -## 🎯 Key UI Components
155   -
156   -### Buttons
157   -- **Primary Action**: Blue background, white text, h-12 minimum
158   -- **Secondary Action**: Outline style
159   -- **Destructive**: Red background (logout, delete)
160   -- **Icon Buttons**: Square, icon only
161   -
162   -### Cards
163   -- White background
164   -- Subtle border
165   -- Rounded corners (rounded-lg)
166   -- Padding: p-4 or p-6
167   -- Hover effect: hover:shadow-md
168   -
169   -### Form Elements
170   -- **Input**: h-12, rounded borders, text-base
171   -- **Select**: h-12, dropdown with chevron
172   -- **Textarea**: rows-4, resize-none
173   -- **Checkbox**: Large touch targets
174   -- **Radio**: Large touch targets with labels
175   -
176   -### Layout Constraints
177   -- **Max Width**: 480px (mobile simulation)
178   -- **Padding**: p-6 for sections
179   -- **Bottom Spacing**: pb-20 (for bottom nav)
180   -- **Fixed Bottom**: bottom-20 (above nav)
181   -
182   -## 🔐 Protected Routes
183   -
184   -All routes except `/login` are protected:
185   -- Check for `localStorage.getItem("isLoggedIn")`
186   -- Redirect to `/login` if not authenticated
187   -- Implemented in `Layout.tsx` component
188   -
189   -## 🚀 Quick Start Development
190   -
191   -1. **Add a new page**:
192   - - Create file in `/src/app/pages/`
193   - - Add route to `/src/app/routes.tsx`
194   - - Follow page structure pattern
195   -
196   -2. **Add to navigation**:
197   - - Bottom tabs: Edit `/src/app/components/Layout.tsx`
198   - - Menu items: Edit relevant parent page
199   -
200   -3. **Add new status**:
201   - - Define status type
202   - - Create status config function
203   - - Apply badge className pattern
204   -
205   -## 📱 Responsive Breakpoints
206   -
207   -Current: Mobile-first with max-width constraint
208   -
209   -Future considerations:
210   -- Tablet: `md:` prefix (768px+)
211   -- Desktop: `lg:` prefix (1024px+)
212   -- Wide: `xl:` prefix (1280px+)
213   -
214   ----
215   -
216   -**Navigation Structure**
217   -```
218   -Login
219   - └── Layout (Bottom Nav)
220   - ├── Dashboard (/)
221   - ├── Labels (/labels)
222   - │ ├── Print (/labels/print/:id)
223   - │ └── Queue (/labels/queue)
224   - ├── Tasks (/tasks)
225   - │ ├── Execute (/tasks/:id)
226   - │ └── Issue (/tasks/:id/issue)
227   - └── More (/more)
228   - ├── Profile
229   - ├── Printers
230   - ├── Location
231   - ├── Sync
232   - └── Support
233   -```
234   -
235   -**Color Reference**
236   -- Primary Blue: `#2563eb` (text-blue-600, bg-blue-600)
237   -- Success Green: `text-green-600`, `bg-green-50`
238   -- Warning Yellow: `text-yellow-600`, `bg-yellow-50`
239   -- Error Red: `text-red-600`, `bg-red-50`
240   -- Gray Scale: `text-gray-500`, `bg-gray-50`, etc.
美国版/Food Labeling Management App React/PROJECT_OVERVIEW.md deleted
1   -# Food Label System - Employee Mobile App
2   -
3   -A professional, enterprise-grade mobile application for restaurant and food service operations, designed for the European and American markets.
4   -
5   -## 🎯 Overview
6   -
7   -This application enables food service employees to manage food labels, execute safety tasks, record temperatures, and maintain compliance with food safety regulations through an intuitive mobile interface.
8   -
9   -## 📱 Key Features
10   -
11   -### 1. **Dashboard**
12   -- Real-time statistics overview
13   -- Quick action buttons for common tasks
14   -- Store and employee information
15   -- Online/offline status indicator
16   -
17   -### 2. **Label Management**
18   -- Browse and search food labels
19   -- Filter by status (All, Expiring Soon, Expired)
20   -- Print labels with customizable templates
21   -- Manage print queue
22   -- Track print job status
23   -
24   -### 3. **Task Management**
25   -- View and execute safety tasks
26   -- Temperature recording with validation
27   -- Equipment condition checks
28   -- Photo upload capability
29   -- Issue reporting with corrective actions
30   -- Overdue task alerts
31   -
32   -### 4. **Settings & More**
33   -- Employee profile management
34   -- Printer configuration and status
35   -- Location information
36   -- Data synchronization status
37   -- Support and help resources
38   -
39   -## 🎨 Design Philosophy
40   -
41   -### Enterprise SaaS Aesthetic
42   -- **Minimalist & Professional**: Clean interface with generous white space
43   -- **Card-based Layout**: Organized information hierarchy
44   -- **High Contrast**: Accessible color schemes and clear visual hierarchy
45   -- **Typography**: Inter font family for modern, professional appearance
46   -
47   -### Design Specifications
48   -- **Font Sizes**:
49   - - Headings: 22-24px
50   - - Subheadings: 18-20px
51   - - Body: 16-18px
52   - - Buttons: 16px
53   -- **Buttons**: Minimum 48px height with 8-12px border radius
54   -- **Colors**:
55   - - Primary: Enterprise Blue (#2563eb)
56   - - Success: Green
57   - - Warning: Orange/Yellow
58   - - Error: Red
59   - - Background: Light Gray/White
60   -
61   -### Mobile-First Design
62   -- Maximum width: 480px (centered on larger screens)
63   -- Touch-friendly interface elements
64   -- Bottom navigation for easy thumb access
65   -- Responsive across iOS and Android
66   -
67   -## 🚀 Navigation Structure
68   -
69   -### Bottom Tab Navigation
70   -1. **Dashboard** - Overview and quick actions
71   -2. **Labels** - Label management and printing
72   -3. **Tasks** - Safety and compliance tasks
73   -4. **More** - Settings and additional features
74   -
75   -### Page Flow
76   -
77   -```
78   -Login
79   - └── Dashboard (Home)
80   - ├── Labels
81   - │ ├── Label Print
82   - │ └── Print Queue
83   - ├── Tasks
84   - │ ├── Task Execute
85   - │ └── Task Issue Report
86   - └── More
87   - ├── Profile
88   - ├── Printers
89   - ├── Location
90   - ├── Sync Status
91   - └── Support
92   -```
93   -
94   -## 🔐 Authentication
95   -
96   -- Email/password login
97   -- "Remember me" option
98   -- Forgot password functionality
99   -- Session persistence with localStorage
100   -
101   -## 📊 Core Workflows
102   -
103   -### 1. Print Label Workflow
104   -1. Browse labels or scan barcode
105   -2. Select label to print
106   -3. Configure print settings (quantity, template, printer)
107   -4. Preview label
108   -5. Send to print queue
109   -6. Track print status
110   -
111   -### 2. Task Execution Workflow
112   -1. View assigned tasks
113   -2. Select task to execute
114   -3. Fill in required information
115   - - Temperature readings
116   - - Equipment condition
117   - - Safety checklists
118   - - Photos
119   -4. Submit task
120   -5. Report issues if detected (automatic)
121   -
122   -### 3. Issue Reporting Workflow
123   -1. Automatic trigger when values are out of range
124   -2. Describe issue in detail
125   -3. Document corrective actions
126   -4. Upload before/after photos
127   -5. Submit for supervisor review
128   -
129   -## 🎯 User Experience Features
130   -
131   -### State Management
132   -- **Loading States**: Clear loading indicators
133   -- **Empty States**: Helpful messaging with illustrations
134   -- **Error States**: Network issues, print failures
135   -- **Success States**: Confirmation feedback
136   -
137   -### Data Visualization
138   -- Status badges (Open, Completed, Expired, etc.)
139   -- Color-coded alerts
140   -- Progress indicators
141   -- Real-time status updates
142   -
143   -### Offline Capability
144   -- Works offline with local data
145   -- Automatic sync when online
146   -- Sync status visibility
147   -- Manual sync option
148   -
149   -## 🛠️ Technology Stack
150   -
151   -- **Framework**: React 18
152   -- **Routing**: React Router v7
153   -- **Styling**: Tailwind CSS v4
154   -- **UI Components**: Radix UI
155   -- **Icons**: Lucide React
156   -- **Notifications**: Sonner
157   -- **Build Tool**: Vite
158   -
159   -## 📱 Screenshots & Use Cases
160   -
161   -### Restaurant Use Cases
162   -- Kitchen temperature monitoring
163   -- Food labeling and FIFO compliance
164   -- Hygiene inspection tracking
165   -- Equipment maintenance logs
166   -
167   -### Food Processing Use Cases
168   -- Batch label printing
169   -- Quality control tasks
170   -- Temperature logging
171   -- Waste reporting
172   -
173   -### Central Kitchen Use Cases
174   -- Multi-location label management
175   -- Standardized task execution
176   -- Centralized compliance tracking
177   -- Equipment status monitoring
178   -
179   -## 🌍 Target Markets
180   -
181   -- United States
182   -- Canada
183   -- United Kingdom
184   -- European Union
185   -- Australia/New Zealand
186   -
187   -## 📄 Compliance & Standards
188   -
189   -Designed to support:
190   -- FDA Food Code compliance
191   -- HACCP requirements
192   -- Local health department regulations
193   -- Food safety management systems
194   -
195   -## 🎓 Training & Support
196   -
197   -The app includes:
198   -- In-app help and support
199   -- Contact information for technical support
200   -- User guides and video tutorials
201   -- FAQ resources
202   -- Emergency support access
203   -
204   -## 📈 Future Enhancements
205   -
206   -Potential features for future releases:
207   -- Barcode scanning
208   -- Voice input for hands-free operation
209   -- Multi-language support
210   -- Real-time notifications
211   -- Advanced analytics dashboard
212   -- Integration with external systems
美国版/Food Labeling Management App React/QUICK_START.md deleted
1   -# 快速启动指南 / Quick Start Guide
2   -
3   -## 🎯 系统概述 / System Overview
4   -
5   -**食品标签打印系统 (简化版) / Food Label Printing System (Simplified Version)**
6   -
7   -面向欧美市场的极简企业级SaaS工具,专注于核心标签打印功能。
8   -Minimalist enterprise SaaS tool for North American/European markets, focused on core label printing functionality.
9   -
10   ----
11   -
12   -## 🚀 如何使用 / How to Use
13   -
14   -### 1. 登录系统 / Login
15   -- 访问应用后会看到登录页面 / Visit the app to see the login page
16   -- 输入任意邮箱和密码即可登录(演示模式)/ Enter any email and password to login (demo mode)
17   -- 系统会保存登录状态 / System saves login state
18   -
19   -### 2. 选择店铺 / Select Store
20   -- 登录后选择工作店铺 / Select your working store after login
21   -- 4个可选店铺位置 / 4 available store locations
22   -- 店铺信息会显示在Dashboard / Store info displayed on Dashboard
23   -
24   -### 3. Dashboard(主页)
25   -**4个统计卡片 / 4 Statistics Cards:**
26   -- 今日标签 (247个) / Today's Labels (247)
27   -- 待办任务 (8个) / Open Tasks (8)
28   -- 系统警报 (5个) / Alerts (5)
29   -- 设备状态 (4台打印机) / Devices Status (4 printers)
30   -
31   -**2个快速操作 / 2 Quick Actions:**
32   -- 扫描打印 / Scan & Print
33   -- 批量打印 / Batch Print
34   -
35   -### 4. Labels(标签管理)- 核心功能
36   -**创建标签 / Create Labels:**
37   -1. 选择标签类型(6种)/ Select label type (6 types):
38   - - 营养标签 / Nutrition Label
39   - - 过敏原标签 / Allergen Label
40   - - 储存标签 / Storage Label
41   - - 保质期标签 / Expiry Date Label
42   - - 批次追踪标签 / Batch Tracking Label
43   - - 制备标签 / Preparation Label
44   -
45   -2. 选择食品项目 / Select food item
46   -3. 查看预览 / Preview label
47   -4. 确认打印 / Confirm and print
48   -
49   -**查看历史 / View History:**
50   -- 查看已打印标签 / View printed labels
51   -- 显示标签状态(活跃/过期)/ Display label status (Active/Expired)
52   -- 显示打印者和时间 / Show printer and time
53   -
54   -### 5. Tasks(任务管理)
55   -- 查看所有任务 / View all tasks
56   -- 执行任务(温度检查、卫生检查等)/ Execute tasks (temperature checks, hygiene inspections, etc.)
57   -- 上传照片 / Upload photos
58   -- 报告问题 / Report issues
59   -
60   -### 6. More(更多设置)
61   -**可用功能 / Available Features:**
62   -- 👤 个人资料 / My Profile
63   -- 📚 培训材料 / Training Materials
64   -- 🖨️ 打印机设置 / Printer Settings
65   -- 📍 位置/店铺 / Location
66   -- 🔄 同步状态 / Sync Status
67   -- 🌐 语言切换 / Language (English/中文)
68   -- ❓ 支持与帮助 / Support
69   -- 🚪 退出登录 / Logout
70   -
71   ----
72   -
73   -## 🌍 语言切换 / Language Switching
74   -
75   -### 切换方法 / How to Switch:
76   -1. 底部导航 → More / Bottom Nav → More
77   -2. 点击"Language / 语言" / Click "Language / 语言"
78   -3. 选择 English 或 中文(简体)/ Select English or 中文(简体)
79   -4. 整个界面立即切换 / Entire UI switches immediately
80   -
81   -### 支持的翻译 / Supported Translations:
82   -- ✅ 1400+ 翻译键值对 / 1400+ translation keys
83   -- ✅ 所有界面文本 / All UI text
84   -- ✅ 所有按钮和标签 / All buttons and labels
85   -- ✅ 所有提示和说明 / All tooltips and instructions
86   -
87   ----
88   -
89   -## 📱 设计规范 / Design Specifications
90   -
91   -### 字体 / Typography
92   -- **字体家族 / Font Family**: Inter (Google Fonts)
93   -- **字重 / Weights**: 400 (Regular), 500 (Medium), 600 (Semi-bold), 700 (Bold)
94   -- **基础字号 / Base Size**: 16px
95   -
96   -### 颜色系统 / Color System
97   -- **主色调 / Primary**: #2563eb (蓝色 / Blue)
98   -- **背景色 / Background**: #ffffff (白色 / White)
99   -- **次要背景 / Secondary BG**: #f9fafb (浅灰 / Light Gray)
100   -- **文字色 / Text**: #111827 (深灰 / Dark Gray)
101   -- **次要文字 / Secondary Text**: #6b7280 (中灰 / Medium Gray)
102   -
103   -### 组件规范 / Component Specs
104   -- **按钮高度 / Button Height**: 最小 48px / Minimum 48px (h-12)
105   -- **圆角 / Border Radius**: 0.625rem
106   -- **容器宽度 / Container Width**: 最大 480px / Max 480px
107   -- **间距单位 / Spacing Unit**: 4px (Tailwind default)
108   -
109   ----
110   -
111   -## 🏗️ 技术架构 / Technical Architecture
112   -
113   -### 前端框架 / Frontend
114   -- React 18.3.1
115   -- TypeScript
116   -- React Router 7.13.0
117   -
118   -### 样式系统 / Styling
119   -- Tailwind CSS v4
120   -- Custom CSS Variables
121   -- Radix UI Components
122   -
123   -### 状态管理 / State Management
124   -- React Context (语言切换 / Language switching)
125   -- localStorage (用户数据 / User data)
126   -
127   ----
128   -
129   -## 📋 标签打印流程 / Label Printing Workflow
130   -
131   -```
132   -1. Dashboard
133   - ↓
134   -2. Labels > 创建 / Create
135   - ↓
136   -3. 选择标签类型 / Select Label Type
137   - ↓
138   -4. 选择食品项目 / Select Food Item
139   - ↓
140   -5. 查看预览 / Preview Label
141   - ↓
142   -6. 确认打印 / Confirm Print
143   - ↓
144   -7. 成功提示 / Success Message
145   - ↓
146   -8. 返回历史 / View in History
147   -```
148   -
149   ----
150   -
151   -## 🎨 界面特点 / UI Features
152   -
153   -### ✨ 极简设计 / Minimalist Design
154   -- 清晰的信息层级 / Clear information hierarchy
155   -- 充足的留白空间 / Ample white space
156   -- 直观的图标系统 / Intuitive icon system
157   -
158   -### 📱 移动优先 / Mobile First
159   -- 响应式设计 / Responsive design
160   -- 触摸友好的交互 / Touch-friendly interactions
161   -- 480px 最大宽度优化 / Optimized for 480px max-width
162   -
163   -### 🎯 用户体验 / User Experience
164   -- 底部导航易于触及 / Bottom nav within thumb reach
165   -- 卡片式设计便于点击 / Card-based design for easy tapping
166   -- 清晰的视觉反馈 / Clear visual feedback
167   -- Toast 通知提示 / Toast notifications
168   -
169   ----
170   -
171   -## 📦 移除的功能 / Removed Features
172   -
173   -为了专注于核心功能,以下功能已移除:
174   -To focus on core functionality, the following features were removed:
175   -
176   -- ❌ 温湿度监控 / Temperature & Humidity Monitoring
177   -- ❌ 电子标签设备管理 / Electronic Label Device Management
178   -- ❌ 推送通知 / Push Notifications
179   -- ❌ 环境监测仪表板 / Environmental Monitoring Dashboard
180   -
181   ----
182   -
183   -## 🔮 未来扩展 / Future Expansion
184   -
185   -可以考虑添加的功能:
186   -Features that can be considered for addition:
187   -
188   -1. **后端集成 / Backend Integration**
189   - - Supabase 数据库 / Supabase Database
190   - - 实时数据同步 / Real-time data sync
191   - - 用户认证系统 / User authentication
192   -
193   -2. **高级功能 / Advanced Features**
194   - - 真实打印机集成 / Real printer integration
195   - - 条形码/二维码扫描 / Barcode/QR scanning
196   - - 离线模式 / Offline mode
197   - - 高级报表分析 / Advanced reporting
198   -
199   -3. **多语言支持 / Multi-language**
200   - - 西班牙语 / Spanish
201   - - 法语 / French
202   - - 德语 / German
203   - - 日语 / Japanese
204   -
205   ----
206   -
207   -## 💡 使用建议 / Usage Tips
208   -
209   -### 最佳实践 / Best Practices:
210   -1. 每天查看Dashboard了解工作概况 / Check Dashboard daily for overview
211   -2. 使用标签历史追踪打印记录 / Use label history to track printed records
212   -3. 及时完成待办任务 / Complete pending tasks promptly
213   -4. 定期查看培训材料提升技能 / Review training materials regularly
214   -
215   -### 常见操作 / Common Operations:
216   -- **快速打印** / Quick Print: Dashboard → 快速操作 / Quick Actions
217   -- **查找标签** / Find Label: Labels → 历史 / History
218   -- **切换店铺** / Switch Store: More → Location
219   -- **查看帮助** / Get Help: More → Support
220   -
221   ----
222   -
223   -## 📞 支持信息 / Support Information
224   -
225   -如需帮助,请访问:
226   -For help, please visit:
227   -
228   -- **应用内支持** / In-app Support: More → Support
229   -- **用户指南** / User Guide: Training Materials
230   -- **常见问题** / FAQ: Support section
231   -
232   ----
233   -
234   -**版本 / Version**: 1.0.0
235   -**更新日期 / Last Updated**: 2026年2月27日 / February 27, 2026
236   -**目标市场 / Target Market**: 北美和欧洲 / North America & Europe
美国版/Food Labeling Management App React/README.md deleted
1   -# 🍽️ Food Label System - Employee Mobile App
2   -
3   -A professional, enterprise-grade mobile application for restaurant and food service operations, designed for the European and American markets.
4   -
5   -![Version](https://img.shields.io/badge/version-1.0.0-blue)
6   -![React](https://img.shields.io/badge/React-18.3.1-61dafb)
7   -![TypeScript](https://img.shields.io/badge/TypeScript-Yes-3178c6)
8   -![Tailwind](https://img.shields.io/badge/Tailwind-4.1.12-38bdf8)
9   -
10   ----
11   -
12   -## 📱 Overview
13   -
14   -This mobile-first web application enables food service employees to:
15   -- 🏷️ Print and manage food labels
16   -- ✅ Execute safety and compliance tasks
17   -- 🌡️ Record temperatures with validation
18   -- 📸 Document issues with photos
19   -- 🖨️ Monitor printer status
20   -- 📊 Track daily operations
21   -
22   -**Design Philosophy**: Clean, professional, enterprise SaaS aesthetic with generous white space, card-based layouts, and high contrast elements optimized for mobile use.
23   -
24   ----
25   -
26   -## ✨ Key Features
27   -
28   -### 🏠 Dashboard
29   -- Real-time overview of daily operations
30   -- Quick access to common actions
31   -- Status indicators for labels, tasks, and devices
32   -- Store and employee information display
33   -
34   -### 🏷️ Label Management
35   -- Browse and search food labels
36   -- Filter by expiration status (Normal, Expiring Soon, Expired)
37   -- Configure print settings (template, quantity, printer)
38   -- Track print queue status
39   -- Retry failed print jobs
40   -
41   -### ✅ Task Execution
42   -- View tasks organized by priority (Overdue, Open, Completed)
43   -- Execute temperature checks with range validation
44   -- Complete equipment condition assessments
45   -- Upload photos and add notes
46   -- Automatic issue detection and reporting
47   -
48   -### ⚙️ Settings & More
49   -- Employee profile management
50   -- Printer configuration and monitoring
51   -- Location information
52   -- Data synchronization status
53   -- Support and help resources
54   -
55   ----
56   -
57   -## 🎨 Design Highlights
58   -
59   -### Visual Design
60   -- **Typography**: Inter font family for professional appearance
61   -- **Colors**: Enterprise blue primary, semantic status colors
62   -- **Layout**: Card-based with generous spacing
63   -- **Mobile-First**: Optimized for 480px width
64   -
65   -### UX Patterns
66   -- **Bottom Tab Navigation**: Easy thumb access
67   -- **Status Badges**: Clear visual indicators with text labels
68   -- **Touch Targets**: Minimum 48px height for all interactive elements
69   -- **State Management**: Loading, empty, error, and success states
70   -
71   -### Accessibility
72   -- High contrast color schemes
73   -- Clear typography hierarchy
74   -- Descriptive status labels
75   -- Touch-friendly interface
76   -
77   ----
78   -
79   -## 🚀 Quick Start
80   -
81   -### Prerequisites
82   -- Node.js 18+ or Bun
83   -- npm, pnpm, or yarn
84   -
85   -### Installation
86   -```bash
87   -# Install dependencies
88   -npm install
89   -# or
90   -pnpm install
91   -```
92   -
93   -### Development
94   -```bash
95   -# Start development server
96   -npm run dev
97   -# or
98   -pnpm dev
99   -```
100   -
101   -Open [http://localhost:5173](http://localhost:5173) in your browser.
102   -
103   -### Build
104   -```bash
105   -# Create production build
106   -npm run build
107   -# or
108   -pnpm build
109   -```
110   -
111   ----
112   -
113   -## 📖 Documentation
114   -
115   -| Document | Description |
116   -|----------|-------------|
117   -| [PROJECT_OVERVIEW.md](./PROJECT_OVERVIEW.md) | Complete project overview and features |
118   -| [USAGE_GUIDE.md](./USAGE_GUIDE.md) | User guide with step-by-step instructions |
119   -| [TECHNICAL_DOCS.md](./TECHNICAL_DOCS.md) | Technical architecture and implementation |
120   -| [PAGE_REFERENCE.md](./PAGE_REFERENCE.md) | Quick reference for all pages and routes |
121   -
122   ----
123   -
124   -## 🗺️ Navigation Structure
125   -
126   -```
127   -Login Page
128   - └── Main App (Bottom Tab Navigation)
129   - ├── 🏠 Dashboard - Overview and quick actions
130   - ├── 🏷️ Labels - Label management
131   - │ ├── Print Configuration
132   - │ └── Print Queue
133   - ├── ✅ Tasks - Task execution
134   - │ ├── Task Details
135   - │ └── Issue Reporting
136   - └── ⚙️ More - Settings and support
137   - ├── Profile
138   - ├── Printers
139   - ├── Location Info
140   - ├── Sync Status
141   - └── Support
142   -```
143   -
144   ----
145   -
146   -## 🛠️ Technology Stack
147   -
148   -### Core
149   -- **React** 18.3.1 - UI framework
150   -- **React Router** 7.13.0 - Navigation (Data mode)
151   -- **TypeScript** - Type safety
152   -- **Vite** 6.3.5 - Build tool
153   -
154   -### Styling
155   -- **Tailwind CSS** 4.1.12 - Utility-first CSS
156   -- **Radix UI** - Accessible component primitives
157   -- **Lucide React** - Icon library
158   -- **Inter Font** - Typography
159   -
160   -### State & Utilities
161   -- **Sonner** - Toast notifications
162   -- **localStorage** - Session persistence (demo)
163   -
164   ----
165   -
166   -## 📱 Demo Credentials
167   -
168   -The app runs in demo mode. Use any credentials to login:
169   -
170   -```
171   -Email: john@company.com
172   -Password: any password
173   -```
174   -
175   ----
176   -
177   -## 🎯 Use Cases
178   -
179   -### Restaurant Operations
180   -- Daily temperature logging
181   -- Food labeling for prep and storage
182   -- Kitchen hygiene inspections
183   -- Equipment maintenance checks
184   -
185   -### Food Processing
186   -- Batch label printing
187   -- Quality control task execution
188   -- Temperature monitoring
189   -- Waste documentation
190   -
191   -### Central Kitchen
192   -- Multi-location label management
193   -- Standardized task procedures
194   -- Centralized compliance tracking
195   -- Equipment status monitoring
196   -
197   ----
198   -
199   -## 📸 Screenshots
200   -
201   -### Login Page
202   -Clean, centered login form with company branding
203   -
204   -### Dashboard
205   -Statistics cards with quick action buttons
206   -
207   -### Label List
208   -Searchable list with color-coded status indicators
209   -
210   -### Task Execution
211   -Multi-step form with validation and photo upload
212   -
213   -### Print Queue
214   -Real-time status of print jobs with retry options
215   -
216   ----
217   -
218   -## 🌍 Target Markets
219   -
220   -- 🇺🇸 United States
221   -- 🇨🇦 Canada
222   -- 🇬🇧 United Kingdom
223   -- 🇪🇺 European Union
224   -- 🇦🇺 Australia / New Zealand
225   -
226   ----
227   -
228   -## 🔮 Future Enhancements
229   -
230   -### Planned Features
231   -- [ ] Barcode scanning with device camera
232   -- [ ] Offline-first architecture with service workers
233   -- [ ] Real-time updates via WebSockets
234   -- [ ] Multi-language support (i18n)
235   -- [ ] Push notifications
236   -- [ ] Voice input for hands-free operation
237   -- [ ] Advanced analytics dashboard
238   -- [ ] Integration with external POS systems
239   -
240   -### Technical Improvements
241   -- [ ] Progressive Web App (PWA) support
242   -- [ ] End-to-end testing suite
243   -- [ ] Performance monitoring
244   -- [ ] Error tracking (Sentry integration)
245   -- [ ] Backend API integration
246   -- [ ] Database persistence
247   -
248   ----
249   -
250   -## 📄 License
251   -
252   -Copyright © 2026 Food Label System. All rights reserved.
253   -
254   ----
255   -
256   -## 👥 Support
257   -
258   -### Getting Help
259   -- 📞 **Phone**: 1-800-SUPPORT (24/7)
260   -- 📧 **Email**: support@foodlabel.com
261   -- 💬 **Live Chat**: Mon-Fri 8 AM - 8 PM EST
262   -
263   -### Resources
264   -- User Guide
265   -- Video Tutorials
266   -- FAQ
267   -- Technical Documentation
268   -
269   ----
270   -
271   -## 🙏 Acknowledgments
272   -
273   -Built with:
274   -- [React](https://react.dev)
275   -- [Tailwind CSS](https://tailwindcss.com)
276   -- [Radix UI](https://radix-ui.com)
277   -- [Lucide Icons](https://lucide.dev)
278   -- [Vite](https://vitejs.dev)
279   -
280   -Design inspired by modern enterprise SaaS applications with a focus on usability, accessibility, and professional aesthetics.
281   -
282   ----
283   -
284   -**Version**: 1.0.0
285   -**Last Updated**: February 2026
286   -**Built for**: Food service professionals worldwide
287   -
288   ----
289   -
290   -<div align="center">
291   -
292   -### 🍽️ Making Food Safety Simple and Professional
293   -
294   -**[View Documentation](#-documentation)** • **[Quick Start](#-quick-start)** • **[Support](#-support)**
295   -
296   -</div>
美国版/Food Labeling Management App React/SYSTEM_SUMMARY.md deleted
1   -# Food Label Printing System - Simplified Version
2   -
3   -## Overview
4   -A minimalist enterprise SaaS-style food label printing system for the North American/European market. Designed for restaurants, food processing, and central kitchen scenarios.
5   -
6   -## Design Principles
7   -- **European/American Enterprise Style**: Clean, professional interface using Inter font family
8   -- **Corporate Blue Theme**: Primary color #2563eb (blue-600)
9   -- **Accessibility**: Button minimum height ≥48px (h-12 in Tailwind)
10   -- **Responsive Design**: Optimized for mobile devices with max-width 480px
11   -- **Bilingual Support**: Complete English and Chinese (Simplified) language switching
12   -
13   -## Core Features
14   -
15   -### 1. Dashboard
16   -- Today's label printing statistics
17   -- Open tasks overview
18   -- System alerts
19   -- Quick actions for label printing
20   -- Device status monitoring
21   -
22   -### 2. Labels (Core Feature)
23   -**Label Types:**
24   -- Nutrition Labels
25   -- Allergen Labels
26   -- Storage Labels
27   -- Expiry Date Labels
28   -- Batch Tracking Labels
29   -- Preparation Labels
30   -
31   -**Workflow:**
32   -1. Select label type
33   -2. Choose food item from catalog
34   -3. Preview label
35   -4. Print label
36   -
37   -**Features:**
38   -- Create new labels
39   -- View printing history
40   -- Track label status (Active/Expired)
41   -
42   -### 3. Tasks
43   -- Task management system
44   -- Temperature checks
45   -- Hygiene inspections
46   -- Equipment safety checks
47   -- Task execution with photo upload
48   -- Issue reporting
49   -
50   -### 4. More (Settings)
51   -- User profile management
52   -- Training materials
53   -- Printer settings
54   -- Location/store selection
55   -- Data sync status
56   -- Language settings (English/中文)
57   -- Support and help resources
58   -
59   -## Technology Stack
60   -- **Frontend**: React 18.3.1 + TypeScript
61   -- **Routing**: React Router 7.13.0
62   -- **Styling**: Tailwind CSS v4 + Custom theme
63   -- **UI Components**: Radix UI primitives
64   -- **Icons**: Lucide React
65   -- **State Management**: React Context (Language)
66   -- **Notifications**: Sonner
67   -
68   -## Key Files
69   -
70   -### Configuration
71   -- `/src/styles/theme.css` - Design tokens and theme variables
72   -- `/src/styles/fonts.css` - Inter font configuration
73   -
74   -### Core Components
75   -- `/src/app/App.tsx` - Application entry point
76   -- `/src/app/routes.tsx` - Route configuration
77   -- `/src/app/components/Layout.tsx` - Main layout with bottom navigation
78   -- `/src/app/contexts/LanguageContext.tsx` - Bilingual support (1400+ translations)
79   -
80   -### Pages
81   -- `/src/app/pages/Dashboard.tsx` - Main dashboard
82   -- `/src/app/pages/Labels.tsx` - Label management
83   -- `/src/app/pages/LabelFoodSelect.tsx` - Food selection
84   -- `/src/app/pages/LabelPreview.tsx` - Label preview before printing
85   -- `/src/app/pages/Tasks.tsx` - Task management
86   -- `/src/app/pages/More.tsx` - Settings and more options
87   -
88   -## Navigation Structure
89   -Bottom navigation bar with 4 tabs:
90   -1. **Dashboard** - Overview and quick actions
91   -2. **Labels** - Label printing system (create & history)
92   -3. **Tasks** - Task management
93   -4. **More** - Settings and additional features
94   -
95   -## Removed Features (Simplified Version)
96   -The following features were removed to create this focused, core-functionality version:
97   -- ❌ Temperature & Humidity Monitoring
98   -- ❌ Electronic Label (ESL) Device Management
99   -- ❌ Push Notifications
100   -- ❌ Environmental Monitoring Dashboard
101   -
102   -## Design Specifications
103   -- **Font Family**: Inter (400, 500, 600, 700)
104   -- **Primary Color**: #2563eb (Corporate Blue)
105   -- **Button Height**: Minimum 48px (h-12)
106   -- **Container Max Width**: 480px (mobile-first)
107   -- **Border Radius**: 0.625rem (--radius)
108   -- **Base Font Size**: 16px
109   -
110   -## Getting Started
111   -
112   -### Development
113   -```bash
114   -# The project is already configured and ready to run
115   -# All dependencies are installed via package.json
116   -```
117   -
118   -### Login
119   -- Demo credentials: any email + password
120   -- System navigates to store selection after login
121   -- User info stored in localStorage
122   -
123   -### Language Switching
124   -- Available in More > Language Settings
125   -- Toggle between English and 中文(简体)
126   -- Preference saved to localStorage
127   -- Instant UI update across entire app
128   -
129   -## Multi-Store Support
130   -- Store selection on login
131   -- Current store displayed on Dashboard
132   -- Switch stores via More > Location
133   -
134   -## Label Printing Flow
135   -1. Dashboard > Quick Actions > Scan & Print
136   - OR Dashboard > Bottom Nav > Labels
137   -2. Select label type (6 options)
138   -3. Browse and select food item
139   -4. Review label preview
140   -5. Confirm and print
141   -6. View in printing history
142   -
143   -## Future Expansion Possibilities
144   -- Supabase integration for backend/database
145   -- Real printer integration
146   -- Barcode/QR code scanning
147   -- Offline mode with sync
148   -- Multi-language expansion
149   -- Advanced reporting and analytics
150   -
151   ----
152   -
153   -**Version**: 1.0.0
154   -**Last Updated**: February 27, 2026
155   -**Target Market**: North America & Europe
156   -**License**: Enterprise
美国版/Food Labeling Management App React/SYSTEM_UPDATE_SUMMARY.md deleted
1   -# 系统更新说明
2   -
3   -## 🎯 完成的三大需求
4   -
5   -### 1. ✅ 手机端只能使用标签(不能制作标签)
6   -
7   -**改动说明:**
8   -- ❌ 移除了标签打印功能(LabelPrint、LabelFoodSelect、LabelQueue 页面)
9   -- ✅ 改为"标签库"模式 - Labels 页面显示已有的标签
10   -- ✅ 员工可以查看标签详情并"使用"标签(记录使用)
11   -- ✅ 标签详情页面显示完整信息和有效期状态
12   -
13   -**新的标签使用流程:**
14   -```
15   -Labels(标签库)→ 选择标签 → 查看详情 → 使用标签
16   -```
17   -
18   -**标签状态:**
19   -- 🟢 Available(可用)- 标签有效,可以使用
20   -- 🟡 Expiring Soon(即将过期)- 1天内过期
21   -- 🔴 Expired(已过期)- 无法使用
22   -
23   ----
24   -
25   -### 2. ✅ 完整的中英文切换
26   -
27   -**翻译覆盖率:100%**
28   -
29   -已翻译的所有页面:
30   -- ✅ **Login** - 登录页面
31   -- ✅ **Dashboard** - 主页/仪表盘
32   -- ✅ **Labels** - 标签库(含标签详情页)
33   -- ✅ **Tasks** - 任务管理
34   -- ✅ **More** - 更多设置(所有子页面)
35   - - Profile(个人资料)
36   - - Printers(打印机设置)
37   - - Location(工作地点)
38   - - Sync Status(同步状态)
39   - - Language Settings(语言设置)
40   - - Support(支持中心)
41   -- ✅ **Bottom Navigation** - 底部导航栏
42   -- ✅ **所有按钮、表单、提示信息**
43   -
44   -**切换方式:**
45   -```
46   -More(更多)→ Language / 语言 → 选择 English 或 中文(简体)
47   -```
48   -
49   -**翻译文件:** `/src/app/contexts/LanguageContext.tsx`
50   -- 包含 700+ 翻译键值对
51   -- 支持动态参数替换
52   -- 语言设置持久化保存
53   -
54   ----
55   -
56   -### 3. ✅ 食品图片展示
57   -
58   -**图片展示位置:**
59   -- ✅ **Labels 页面**(标签列表)
60   - - 每个标签卡片都有食品图片
61   - - 图片尺寸:80x80px(缩略图)
62   -
63   -- ✅ **LabelDetail 页面**(标签详情)
64   - - 大尺寸食品图片:全宽 x 256px
65   - - 高质量展示
66   -
67   -**图片来源:**
68   -- 使用 Unsplash 高质量食品图片
69   -- 10+ 种不同食品的真实图片:
70   - - 烤鸡胸肉(Grilled Chicken)
71   - - 凯撒沙拉(Caesar Salad)
72   - - 三文鱼(Fresh Salmon)
73   - - 牛肉饼(Ground Beef Patties)
74   - - 意面酱(Marinara Sauce)
75   - - 蔬菜(Pre-cut Vegetables)
76   - - 巧克力布朗尼(Chocolate Brownie)
77   - - 虾意面(Shrimp Pasta)
78   - - 冰淇淋(Ice Cream)
79   - - 三明治(Pre-made Sandwiches)
80   -
81   ----
82   -
83   -## 📱 新的标签使用流程示意图
84   -
85   -```
86   -┌─────────────────────────────────────────────────┐
87   -│ Labels(标签库) │
88   -│ │
89   -│ 🥗 Grilled Chicken Breast [LB001] ✅ │
90   -│ Nutrition Label │
91   -│ Expiry: Mar 2, 2026 │
92   -│ ┌────────────────────┐ │
93   -│ │ [食品图片] │ │
94   -│ └────────────────────┘ │
95   -│ │
96   -│ ⚠️ Caesar Salad [LB002] ✅ │
97   -│ Allergen Label │
98   -│ Expiry: Feb 28, 2026 │
99   -└─────────────────────────────────────────────────┘
100   - ↓ 点击标签
101   -┌─────────────────────────────────────────────────┐
102   -│ Label Detail(标签详情) │
103   -│ │
104   -│ ┌──────────────────────────────────────────┐ │
105   -│ │ │ │
106   -│ │ [大尺寸食品图片] │ │
107   -│ │ │ │
108   -│ └──────────────────────────────────────────┘ │
109   -│ │
110   -│ 🟢 Available for Use │
111   -│ This label is valid. Expires in 3 days. │
112   -│ │
113   -│ Label Information: │
114   -│ • Label ID: LB001 │
115   -│ • Category: Meat │
116   -│ • Printed Date: Feb 27, 2026 │
117   -│ • Expiry Date: Mar 2, 2026 │
118   -│ • Printed By: Maria Garcia │
119   -│ │
120   -│ Label Details: │
121   -│ • Serving Size: 150g │
122   -│ • Calories: 165 kcal │
123   -│ • Protein: 31g │
124   -│ • Fat: 3.6g │
125   -│ │
126   -│ Notes (Optional): │
127   -│ ┌─────────────────────────────────────┐ │
128   -│ │ Applied to container #3... │ │
129   -│ └─────────────────────────────────────┘ │
130   -│ │
131   -│ ┌──────────────────────────────────────────┐ │
132   -│ │ [Use This Label] │ │
133   -│ └──────────────────────────────────────────┘ │
134   -└─────────────────────────────────────────────────┘
135   -```
136   -
137   ----
138   -
139   -## 🌐 语言切换效果示例
140   -
141   -### English(英文)
142   -```
143   -Dashboard
144   -├── Today's Labels: 247
145   -├── Open Tasks: 8
146   -├── Alerts: 5
147   -└── Quick Actions
148   - ├── Scan & Print
149   - ├── Batch Print
150   - ├── Record Temperature
151   - └── Report Waste
152   -```
153   -
154   -### 中文(简体)
155   -```
156   -主页
157   -├── 今日标签:247
158   -├── 待办任务:8
159   -├── 提醒:5
160   -└── 快捷操作
161   - ├── 扫码打印
162   - ├── 批量打印
163   - ├── 记录温度
164   - └── 报告浪费
165   -```
166   -
167   ----
168   -
169   -## 🎨 UI 特点
170   -
171   -### 设计风格
172   -- ✅ 极简企业级 SaaS 风格
173   -- ✅ 大留白设计
174   -- ✅ 卡片式布局
175   -- ✅ 企业蓝色主色调(#2563eb)
176   -- ✅ 专业感强
177   -
178   -### 按钮规范
179   -- ✅ 按钮高度 ≥ 48px(h-12)
180   -- ✅ 重要操作使用 56px(h-14)
181   -- ✅ 文本清晰,字体大(text-base/text-lg)
182   -
183   -### 状态展示
184   -- ✅ 所有状态使用文字标签
185   -- ✅ 配合颜色区分:
186   - - 🟢 绿色 = 成功/可用/在线
187   - - 🟡 黄色 = 警告/即将过期
188   - - 🔴 红色 = 错误/过期/离线
189   - - 🔵 蓝色 = 信息/待处理
190   -
191   ----
192   -
193   -## 📂 文件结构
194   -
195   -```
196   -/src/app/
197   -├── contexts/
198   -│ └── LanguageContext.tsx # 语言管理系统(700+ 翻译)
199   -├── pages/
200   -│ ├── Dashboard.tsx # ✅ 主页(已翻译)
201   -│ ├── Labels.tsx # ✅ 标签库(已重构 + 翻译)
202   -│ ├── LabelDetail.tsx # ✅ 标签详情(新页面)
203   -│ ├── Tasks.tsx # ✅ 任务管理(已翻译)
204   -│ ├── More.tsx # ✅ 更多设置(已翻译)
205   -│ └── more/
206   -│ ├── LanguageSettings.tsx # ✅ 语��设置(新页面)
207   -│ ├── Profile.tsx # 个人资料
208   -│ ├── Printers.tsx # 打印机设置
209   -│ ├── Location.tsx # 工作地点
210   -│ ├── SyncStatus.tsx # 同步状态
211   -│ └── Support.tsx # 支持中心
212   -└── routes.tsx # ✅ 路由配置(已更新)
213   -```
214   -
215   ----
216   -
217   -## 🚀 使用说明
218   -
219   -### 查看标签
220   -1. 点击底部 **Labels**(标签)标签
221   -2. 浏览可用标签列表(带食品图片)
222   -3. 使用搜索或分类筛选
223   -4. 点击标签查看详情
224   -
225   -### 使用标签
226   -1. 在标签详情页查看所有信息
227   -2. 确认标签状态(可用/即将过期/已过期)
228   -3. 可选:添加使用备注
229   -4. 点击 **Use This Label**(使用此标签)按钮
230   -5. 确认后标签使用记录被保存
231   -
232   -### 切换语言
233   -1. 点击底部 **More**(更多)标签
234   -2. 选择 **Language / 语言**
235   -3. 点击想要的语言(🇺🇸 English 或 🇨🇳 中文)
236   -4. 语言立即生效,无需刷新
237   -
238   ----
239   -
240   -## 🎯 核心改进总结
241   -
242   -| 项目 | 改进前 | 改进后 |
243   -|-----|-------|-------|
244   -| **标签功能** | 打印新标签 | 使用已有标签 |
245   -| **语言支持** | 仅英文 | 中英文切换 |
246   -| **食品展示** | 无图片 | 高质量图片 |
247   -| **用户体验** | 复杂流程 | 简化操作 |
248   -| **翻译覆盖** | 0% | 100% |
249   -| **图片展示** | 0 张 | 10+ 张 |
250   -
251   ----
252   -
253   -## ✨ 系统特色
254   -
255   -1. **移动优先**
256   - - 专为手机端设计
257   - - 单列布局,易于浏览
258   - - 大按钮,易于点击
259   -
260   -2. **国际化**
261   - - 完整中英文支持
262   - - 即时切换
263   - - 持久化保存
264   -
265   -3. **视觉化**
266   - - 每个标签都有食品图片
267   - - 状态清晰可见
268   - - 专业的配色方案
269   -
270   -4. **简单易用**
271   - - 减少操作步骤
272   - - 清晰的信息层级
273   - - 即时反馈
274   -
275   ----
276   -
277   -## 📝 技术栈
278   -
279   -- **Frontend**: React + TypeScript
280   -- **Routing**: React Router v7
281   -- **Styling**: Tailwind CSS v4
282   -- **UI Components**: shadcn/ui
283   -- **Icons**: Lucide React
284   -- **Notifications**: Sonner
285   -- **Images**: Unsplash API
286   -- **i18n**: Custom Context-based solution
287   -
288   ----
289   -
290   -Created on: February 27, 2026
美国版/Food Labeling Management App React/TECHNICAL_DOCS.md deleted
1   -# Technical Documentation - Food Label System
2   -
3   -## 🏗️ Project Structure
4   -
5   -```
6   -src/app/
7   -├── App.tsx # Main application entry point with RouterProvider
8   -├── routes.tsx # React Router configuration
9   -├── components/
10   -│ ├── Layout.tsx # Main layout with bottom navigation
11   -│ ├── states/ # Reusable state components
12   -│ │ ├── Loading.tsx
13   -│ │ ├── EmptyState.tsx
14   -│ │ ├── ErrorState.tsx
15   -│ │ └── SuccessState.tsx
16   -│ └── ui/ # Radix UI components (shadcn/ui)
17   -├── pages/
18   -│ ├── Login.tsx # Authentication page
19   -│ ├── Dashboard.tsx # Home dashboard
20   -│ ├── Labels.tsx # Label list view
21   -│ ├── LabelPrint.tsx # Label printing configuration
22   -│ ├── LabelQueue.tsx # Print queue management
23   -│ ├── Tasks.tsx # Task list view
24   -│ ├── TaskExecute.tsx # Task execution form
25   -│ ├── TaskIssue.tsx # Issue reporting form
26   -│ ├── More.tsx # Settings menu
27   -│ ├── NotFound.tsx # 404 page
28   -│ └── more/ # Settings sub-pages
29   -│ ├── Profile.tsx
30   -│ ├── Printers.tsx
31   -│ ├── Location.tsx
32   -│ ├── SyncStatus.tsx
33   -│ └── Support.tsx
34   -└── styles/
35   - ├── fonts.css # Font imports (Inter)
36   - ├── theme.css # Design system tokens
37   - ├── tailwind.css # Tailwind directives
38   - └── index.css # Global styles
39   -```
40   -
41   -## 🔧 Technology Stack
42   -
43   -### Core Dependencies
44   -- **React**: 18.3.1
45   -- **React Router**: 7.13.0 (Data mode with createBrowserRouter)
46   -- **Tailwind CSS**: 4.1.12
47   -- **Vite**: 6.3.5
48   -
49   -### UI Libraries
50   -- **Radix UI**: Complete suite of unstyled, accessible UI components
51   -- **Lucide React**: 0.487.0 - Icon library
52   -- **Sonner**: 2.0.3 - Toast notifications
53   -- **class-variance-authority**: For component variants
54   -- **tailwind-merge**: For className merging
55   -
56   -### Styling Approach
57   -- Tailwind CSS v4 with CSS custom properties
58   -- Design tokens in `theme.css`
59   -- Mobile-first responsive design
60   -- Max-width constraint (480px) for mobile simulation
61   -
62   -## 📐 Design System
63   -
64   -### Color Palette
65   -```css
66   ---primary: #2563eb /* Enterprise Blue */
67   ---background: #ffffff /* White */
68   ---foreground: oklch(0.145 0 0) /* Near Black */
69   ---destructive: #d4183d /* Error Red */
70   -```
71   -
72   -### Typography Scale
73   -```css
74   ---font-size: 16px /* Base size */
75   -h1: 24px (text-2xl)
76   -h2: 20px (text-xl)
77   -h3: 18px (text-lg)
78   -body: 16px (text-base)
79   -```
80   -
81   -### Spacing & Layout
82   -- **Container**: max-w-[480px] mx-auto
83   -- **Padding**: p-6 (24px) for page sections
84   -- **Card spacing**: space-y-3 to space-y-6
85   -- **Button height**: h-12 (48px) minimum
86   -
87   -### Border Radius
88   -- **Cards**: rounded-lg (10px)
89   -- **Buttons**: rounded-lg (10px)
90   -- **Badges**: rounded-lg (10px)
91   -
92   -## 🔀 Routing Architecture
93   -
94   -### Route Configuration
95   -Using React Router v7 Data mode:
96   -```tsx
97   -createBrowserRouter([
98   - { path: "/login", Component: Login },
99   - {
100   - path: "/",
101   - Component: Layout, // Wrapper with bottom nav
102   - children: [...] // Nested routes
103   - }
104   -])
105   -```
106   -
107   -### Navigation Patterns
108   -1. **Bottom Tab Navigation**: 4 main sections (Dashboard, Labels, Tasks, More)
109   -2. **Nested Routes**: Sub-pages within main sections
110   -3. **Protected Routes**: Auth check in Layout component
111   -4. **Not Found**: Catch-all route (*) for 404s
112   -
113   -### State Persistence
114   -- **localStorage** for authentication state
115   -- Session data: `isLoggedIn`, `userName`, `storeName`
116   -- Auto-redirect to `/login` if not authenticated
117   -
118   -## 🎨 Component Patterns
119   -
120   -### Page Structure
121   -```tsx
122   -<div className="min-h-screen bg-gray-50">
123   - {/* Header */}
124   - <div className="bg-white border-b border-gray-200 p-6">
125   - <h1 className="text-2xl font-semibold text-gray-900">
126   - Page Title
127   - </h1>
128   - </div>
129   -
130   - {/* Content */}
131   - <div className="p-6 space-y-6">
132   - {/* Cards and content */}
133   - </div>
134   -
135   - {/* Fixed Bottom Button (if needed) */}
136   - <div className="fixed bottom-20 left-0 right-0 bg-white border-t p-6">
137   - <div className="max-w-[480px] mx-auto">
138   - <Button>Action</Button>
139   - </div>
140   - </div>
141   -</div>
142   -```
143   -
144   -### Card Component Usage
145   -```tsx
146   -<Card className="p-4">
147   - {/* Card content */}
148   -</Card>
149   -```
150   -
151   -### Status Badge Pattern
152   -```tsx
153   -<span className={`px-3 py-1 text-sm font-medium rounded-lg border ${statusClassName}`}>
154   - {statusLabel}
155   -</span>
156   -```
157   -
158   -## 🔄 Data Flow
159   -
160   -### Mock Data
161   -All data is currently mocked in component files for demonstration:
162   -- Labels: 5 sample food items
163   -- Tasks: 6 sample safety tasks
164   -- Print Jobs: 4 sample jobs
165   -- Printers: 4 sample devices
166   -
167   -### Future Integration Points
168   -Components are structured to easily integrate with:
169   -- REST APIs
170   -- GraphQL endpoints
171   -- WebSocket for real-time updates
172   -- Local database (IndexedDB) for offline support
173   -
174   -## 🎯 Key Features Implementation
175   -
176   -### 1. Authentication
177   -- Simple localStorage-based auth
178   -- Login form with email/password
179   -- Remember me functionality
180   -- Logout with confirmation dialog
181   -
182   -### 2. Label Management
183   -- List view with search and filters
184   -- Print configuration with quantity/template selection
185   -- Print queue with status tracking
186   -- Retry failed print jobs
187   -
188   -### 3. Task Execution
189   -- Multi-step forms with validation
190   -- Temperature range checking
191   -- Conditional issue reporting
192   -- File upload placeholders
193   -
194   -### 4. State Components
195   -Centralized state components for consistency:
196   -- `<Loading />`: Spinner with message
197   -- `<EmptyState />`: No data placeholder
198   -- `<ErrorState />`: Error handling (network, print, general)
199   -- `<SuccessState />`: Success confirmation
200   -
201   -## 📱 Mobile Optimization
202   -
203   -### Touch Targets
204   -- Minimum 48px for all interactive elements
205   -- Adequate spacing between touch targets
206   -- Large, obvious CTAs
207   -
208   -### Bottom Navigation
209   -- Fixed position at bottom
210   -- Safe area inset handling
211   -- Active state indication
212   -- Icon + label for clarity
213   -
214   -### Content Strategy
215   -- Main content in scrollable area
216   -- Fixed header and navigation
217   -- Bottom padding (pb-20) to prevent nav overlap
218   -
219   -## 🌐 Internationalization Ready
220   -
221   -While currently in English, the structure supports i18n:
222   -- Text strings are not hardcoded in JSX
223   -- Can easily wrap with translation functions
224   -- Date/time formatting uses `toLocaleDateString`
225   -
226   -## 🔒 Security Considerations
227   -
228   -For production deployment, implement:
229   -- Real authentication (JWT/OAuth)
230   -- API request signing
231   -- HTTPS enforcement
232   -- XSS prevention (React handles most)
233   -- CSRF tokens for mutations
234   -- Input sanitization
235   -- Rate limiting
236   -
237   -## 🧪 Testing Strategy
238   -
239   -Recommended test coverage:
240   -- **Unit Tests**: Individual components
241   -- **Integration Tests**: Page workflows
242   -- **E2E Tests**: Critical user paths
243   - - Login flow
244   - - Label print workflow
245   - - Task completion workflow
246   - - Issue reporting
247   -
248   -## 📦 Build & Deployment
249   -
250   -### Build Command
251   -```bash
252   -npm run build
253   -# or
254   -pnpm build
255   -```
256   -
257   -### Output
258   -- Static files in `dist/`
259   -- Ready for CDN deployment
260   -- No server-side rendering needed
261   -
262   -### Environment Variables
263   -For production, configure:
264   -- `VITE_API_URL`: Backend API endpoint
265   -- `VITE_APP_VERSION`: Version number
266   -- `VITE_SENTRY_DSN`: Error tracking (if used)
267   -
268   -## 🔄 Future Enhancements
269   -
270   -### Planned Features
271   -1. **Offline-First Architecture**
272   - - Service Workers
273   - - IndexedDB for local storage
274   - - Background sync
275   -
276   -2. **Real-time Updates**
277   - - WebSocket integration
278   - - Push notifications
279   - - Live printer status
280   -
281   -3. **Advanced Features**
282   - - Barcode scanning (device camera)
283   - - Voice input
284   - - Signature capture
285   - - PDF generation
286   -
287   -4. **Internationalization**
288   - - Multi-language support
289   - - RTL layout support
290   - - Currency/date localization
291   -
292   -5. **Analytics**
293   - - User behavior tracking
294   - - Performance monitoring
295   - - Error reporting
296   -
297   -## 🐛 Debugging Tips
298   -
299   -### Common Issues
300   -
301   -1. **Routes not working**
302   - - Check `routes.tsx` configuration
303   - - Verify component imports
304   - - Check browser console for errors
305   -
306   -2. **Styles not applying**
307   - - Ensure Tailwind classes are correct
308   - - Check `theme.css` for custom properties
309   - - Verify no CSS conflicts
310   -
311   -3. **State not persisting**
312   - - Check localStorage in DevTools
313   - - Verify key names match
314   - - Test in private/incognito mode
315   -
316   -## 📚 Additional Resources
317   -
318   -- [React Router v7 Docs](https://reactrouter.com)
319   -- [Tailwind CSS v4 Docs](https://tailwindcss.com)
320   -- [Radix UI Docs](https://radix-ui.com)
321   -- [Lucide Icons](https://lucide.dev)
322   -
323   ----
324   -
325   -**Maintained by**: Food Label System Team
326   -**Last Updated**: February 2026
327   -**Version**: 1.0.0
美国版/Food Labeling Management App React/USAGE_GUIDE.md deleted
1   -# Food Label System - Usage Guide
2   -
3   -## 🚀 Getting Started
4   -
5   -### Initial Login
6   -
7   -1. Open the application
8   -2. Enter your credentials:
9   - - **Email**: Any valid email format (e.g., `john@company.com`)
10   - - **Password**: Any password
11   -3. Check "Remember me" to stay logged in
12   -4. Click "Login"
13   -
14   -> **Demo Mode**: The app currently runs in demo mode with mock data. All login credentials will work for demonstration purposes.
15   -
16   -## 📱 Main Navigation
17   -
18   -The app features a **bottom tab navigation** with 4 main sections:
19   -
20   -### 🏠 Dashboard
21   -Your command center with:
22   -- **Statistics Cards**:
23   - - Today's Labels count
24   - - Open Tasks
25   - - Alerts for expiring items
26   - - Device Status (printers)
27   -- **Quick Actions**:
28   - - Scan & Print
29   - - Batch Print
30   - - Record Temperature
31   - - Report Waste
32   -
33   -**Tip**: Tap any statistic card to navigate directly to that section.
34   -
35   -### 🏷️ Labels
36   -Manage food labels and printing:
37   -
38   -#### Browse Labels
39   -- **Search**: Use the search bar to find specific items or batch numbers
40   -- **Filter Tabs**:
41   - - **All**: View all labels
42   - - **Expiring Soon**: Yellow status labels
43   - - **Expired**: Red status labels
44   -- **Actions**: Tap "Print Label" on any item
45   -
46   -#### Print a Label
47   -1. Select a label from the list
48   -2. Choose template type (Standard, Large, Small)
49   -3. Set quantity using +/- buttons
50   -4. Select printer from dropdown
51   -5. Preview the label
52   -6. Tap "Print Label"
53   -
54   -#### Print Queue
55   -View all print jobs:
56   -- **In Progress**: Currently printing
57   -- **Completed**: Successfully printed
58   -- **Failed**: Tap "Retry" to reprint
59   -
60   -### ✅ Tasks
61   -Execute safety and compliance tasks:
62   -
63   -#### Task List
64   -Tasks are organized by status:
65   -- **Overdue** (red border): Immediate attention needed
66   -- **Open** (blue badge): Pending tasks
67   -- **Completed** (green badge): Finished tasks
68   -
69   -#### Execute a Task
70   -1. Tap "Start Task" on any task
71   -2. Fill in required information:
72   - - **Temperature**: Enter reading (normal range: 35-40°F)
73   - - **Equipment Condition**: Select Good/Fair/Poor
74   - - **Safety Checks**: Check applicable items
75   - - **Photo**: Upload if needed (optional)
76   - - **Notes**: Add additional context (optional)
77   -3. Tap "Submit Task"
78   -
79   -#### Issue Reporting
80   -If temperature is **out of range**, you'll automatically be directed to report an issue:
81   -1. Review the detected issue
82   -2. Describe the problem in detail
83   -3. Document corrective actions taken
84   -4. Upload before/after photos
85   -5. Submit for supervisor review
86   -
87   -### ⚙️ More
88   -Access settings and additional features:
89   -
90   -#### Profile
91   -- View and edit your personal information
92   -- Update contact details
93   -- View employee ID
94   -
95   -#### Printers
96   -- See all connected printers
97   -- Check online/offline status
98   -- View printer locations and models
99   -
100   -#### Location Info
101   -- Store name and address
102   -- Contact information
103   -- Operating hours
104   -- Manager details
105   -
106   -#### Sync Status
107   -- View last sync time
108   -- Check sync status for:
109   - - Labels
110   - - Tasks
111   - - Photos
112   -- Manually sync data
113   -
114   -#### Support
115   -- Phone support (24/7)
116   -- Email support
117   -- Live chat
118   -- Access resources:
119   - - User Guide
120   - - Video Tutorials
121   - - FAQ
122   -- Emergency support button
123   -
124   -## 💡 Tips & Best Practices
125   -
126   -### 📋 Task Execution
127   -- ✅ Complete tasks before their due time to avoid overdue status
128   -- ✅ Always fill in temperature readings accurately
129   -- ✅ Upload photos when equipment issues are detected
130   -- ✅ Provide detailed notes for context
131   -
132   -### 🏷️ Label Printing
133   -- ✅ Check expiry dates before printing
134   -- ✅ Print labels immediately after food prep
135   -- ✅ Use batch printing for efficiency
136   -- ✅ Verify printer status before large jobs
137   -
138   -### 🔄 Data Sync
139   -- ✅ App auto-syncs every 5 minutes when online
140   -- ✅ Check sync status regularly
141   -- ✅ Manual sync available in More > Sync Status
142   -- ✅ App works offline - data syncs when connection restored
143   -
144   -### 🚨 Alerts & Issues
145   -- ✅ Red badges indicate urgent items
146   -- ✅ Yellow badges indicate items needing attention
147   -- ✅ Always report issues immediately
148   -- ✅ Include photos for equipment problems
149   -
150   -## 🎨 Visual Status Indicators
151   -
152   -### Label Status
153   -- 🟢 **Green** (Normal): Within expiry date
154   -- 🟡 **Yellow** (Expiring Soon): Approaching expiry
155   -- 🔴 **Red** (Expired): Past expiry date
156   -
157   -### Task Status
158   -- 🔵 **Blue** (Open): Ready to start
159   -- 🟢 **Green** (Completed): Finished
160   -- 🔴 **Red** (Overdue): Past due time
161   -
162   -### Printer Status
163   -- 🟢 **Online**: Ready to print
164   -- ⚫ **Offline**: Not available
165   -
166   -### Sync Status
167   -- ✅ **Synced**: All data current
168   -- 🟠 **Pending**: Items waiting to sync
169   -
170   -## 🔐 Logout
171   -
172   -To logout:
173   -1. Go to **More** tab
174   -2. Scroll to bottom
175   -3. Tap **Logout**
176   -4. Confirm logout in dialog
177   -
178   -## 📞 Getting Help
179   -
180   -If you need assistance:
181   -1. Tap **More** > **Support**
182   -2. Choose your preferred contact method:
183   - - **Phone**: 1-800-SUPPORT (24/7)
184   - - **Email**: support@foodlabel.com
185   - - **Live Chat**: Mon-Fri 8 AM - 8 PM EST
186   -3. For emergencies, use the red "Call Emergency Support" button
187   -
188   -## 🌐 Offline Mode
189   -
190   -The app works offline:
191   -- ✅ View existing labels and tasks
192   -- ✅ Execute tasks and record data
193   -- ✅ Queue print jobs
194   -- 📡 Data automatically syncs when back online
195   -- 🔄 Check sync status in More > Sync Status
196   -
197   -## 🔄 Common Workflows
198   -
199   -### Morning Opening
200   -1. Login to app
201   -2. Check Dashboard for overdue tasks
202   -3. Complete temperature checks
203   -4. Print labels for daily prep
204   -
205   -### During Service
206   -1. Scan items as needed
207   -2. Print labels for prepared foods
208   -3. Record temperatures at scheduled times
209   -
210   -### Closing
211   -1. Complete end-of-day tasks
212   -2. Report any waste
213   -3. Verify all tasks completed
214   -4. Check sync status
215   -
216   ----
217   -
218   -**Need more help?** Contact support or access the in-app help resources!
美国版/Food Labeling Management App React/VERIFICATION_CHECKLIST.md deleted
1   -# 系统验证清单 / System Verification Checklist
2   -
3   -## ✅ 设计规范 / Design Specifications
4   -
5   -### 字体系统 / Typography
6   -- [x] Inter 字体已配置 / Inter font configured
7   -- [x] 字重: 400, 500, 600, 700 / Weights: 400, 500, 600, 700
8   -- [x] 基础字号: 16px / Base font size: 16px
9   -- [x] 字体来源: Google Fonts / Font source: Google Fonts
10   -
11   -### 颜色主题 / Color Theme
12   -- [x] 主色调: #2563eb (企业蓝) / Primary: #2563eb (Corporate Blue)
13   -- [x] 按钮使用主色调 / Buttons use primary color
14   -- [x] 链接和重要元素使用主色调 / Links and key elements use primary color
15   -- [x] 配色符合欧美企业风格 / Color scheme matches EU/US enterprise style
16   -
17   -### 组件规范 / Component Specifications
18   -- [x] 按钮默认高度: h-12 (48px) / Default button height: h-12 (48px)
19   -- [x] 按钮小尺寸: h-10 (40px) / Small button: h-10 (40px)
20   -- [x] 按钮大尺寸: h-14 (56px) / Large button: h-14 (56px)
21   -- [x] 圆角半径: 0.625rem / Border radius: 0.625rem
22   -- [x] 容器最大宽度: 480px / Max container width: 480px
23   -
24   ----
25   -
26   -## ✅ 功能模块 / Feature Modules
27   -
28   -### 核心功能 / Core Features
29   -- [x] Dashboard (主页概览) / Dashboard (overview)
30   -- [x] Labels (标签管理 - 核心功能) / Labels (label management - core)
31   -- [x] Tasks (任务管理) / Tasks (task management)
32   -- [x] More (更多设置) / More (settings)
33   -
34   -### Labels 模块详细功能 / Labels Module Details
35   -- [x] 6种标签类型 / 6 label types:
36   - - [x] Nutrition (营养标签) / Nutrition Label
37   - - [x] Allergen (过敏原标签) / Allergen Label
38   - - [x] Storage (储存标签) / Storage Label
39   - - [x] Expiry (保质期标签) / Expiry Date Label
40   - - [x] Batch (批次追踪标签) / Batch Tracking Label
41   - - [x] Preparation (制备标签) / Preparation Label
42   -- [x] 标签打印流程 / Label printing workflow:
43   - - [x] 选择标签类型 / Select label type
44   - - [x] 选择食品项目 / Select food item
45   - - [x] 查看预览 / Preview label
46   - - [x] 确认打印 / Confirm print
47   -- [x] 打印历史记录 / Printing history
48   -- [x] 双Tab切换 (创建/历史) / Dual tabs (Create/History)
49   -
50   -### Dashboard 功能 / Dashboard Features
51   -- [x] 4个统计卡片 / 4 statistics cards
52   -- [x] 2个快速操作 / 2 quick actions (仅标签相关)
53   -- [x] 在线状态显示 / Online status display
54   -- [x] 店铺名称显示 / Store name display
55   -
56   -### Tasks 功能 / Tasks Features
57   -- [x] 任务列表 / Task list
58   -- [x] 任务执行 / Task execution
59   -- [x] 问题报告 / Issue reporting
60   -- [x] 照片上传功能 / Photo upload functionality
61   -
62   -### More 功能 / More Features
63   -- [x] 个人资料 / Profile
64   -- [x] 培训材料 / Training materials
65   -- [x] 打印机设置 / Printer settings
66   -- [x] 位置/店铺选择 / Location selection
67   -- [x] 同步状态 / Sync status
68   -- [x] 语言设置 / Language settings
69   -- [x] 支持帮助 / Support
70   -- [x] 退出登录 / Logout
71   -
72   ----
73   -
74   -## ✅ 已移除功能 / Removed Features
75   -
76   -- [x] 温湿度监控页面已删除 / Temperature monitoring page deleted
77   -- [x] 电子标签设备管理页面已删除 / Electronic labels page deleted
78   -- [x] 通知页面已删除 / Notifications page deleted
79   -- [x] Dashboard中的环境监测模块已移除 / Environmental monitoring section removed from Dashboard
80   -- [x] Dashboard中的电子标签模块已移除 / Electronic labels section removed from Dashboard
81   -- [x] 路由配置已清理 / Routes configuration cleaned
82   -
83   ----
84   -
85   -## ✅ 双语支持 / Bilingual Support
86   -
87   -### 语言功能 / Language Features
88   -- [x] 英文支持 (默认) / English support (default)
89   -- [x] 简体中文支持 / Simplified Chinese support
90   -- [x] 语言切换功能 / Language switching functionality
91   -- [x] 语言设置持久化 (localStorage) / Language persistence (localStorage)
92   -- [x] 1400+ 翻译键值对 / 1400+ translation keys
93   -
94   -### 翻译覆盖 / Translation Coverage
95   -- [x] 所有页面标题和描述 / All page titles and descriptions
96   -- [x] 所有按钮文本 / All button text
97   -- [x] 所有表单标签 / All form labels
98   -- [x] 所有提示消息 / All toast messages
99   -- [x] 所有标签类型名称 / All label type names
100   -- [x] 所有食品项目名称 / All food item names
101   -- [x] 所有任务名称和描述 / All task names and descriptions
102   -- [x] 所有菜单项 / All menu items
103   -
104   ----
105   -
106   -## ✅ 导航系统 / Navigation System
107   -
108   -### 底部导航栏 / Bottom Navigation
109   -- [x] 4个主导航标签 / 4 main navigation tabs:
110   - - [x] Dashboard (主页)
111   - - [x] Labels (标签)
112   - - [x] Tasks (任务)
113   - - [x] More (更多)
114   -- [x] 活跃状态高亮 / Active state highlighting
115   -- [x] 图标 + 文字标签 / Icon + text labels
116   -- [x] 固定在底部 / Fixed at bottom
117   -- [x] 高度: 80px (h-20) / Height: 80px (h-20)
118   -
119   -### 路由配置 / Route Configuration
120   -- [x] React Router v7 配置 / React Router v7 configured
121   -- [x] 嵌套路由正确 / Nested routes correct
122   -- [x] 404页面处理 / 404 page handling
123   -- [x] 受保护路由 (登录检查) / Protected routes (login check)
124   -
125   ----
126   -
127   -## ✅ 用户流程 / User Flows
128   -
129   -### 登录流程 / Login Flow
130   -- [x] 登录页面 / Login page
131   -- [x] 店铺选择页面 / Store selection page
132   -- [x] 登录状态持久化 / Login state persistence
133   -- [x] 自动导航到Dashboard / Auto-navigate to Dashboard
134   -
135   -### 标签打印流程 / Label Printing Flow
136   -```
137   -Dashboard → Labels → Select Type → Select Food → Preview → Print → History
138   -✅ 所有步骤正常工作 / All steps working correctly
139   -```
140   -
141   -### 任务执行流程 / Task Execution Flow
142   -```
143   -Dashboard/Tasks → Task List → Select Task → Execute → Submit → Return
144   -✅ 所有步骤正常工作 / All steps working correctly
145   -```
146   -
147   ----
148   -
149   -## ✅ 响应式设计 / Responsive Design
150   -
151   -### 移动端优化 / Mobile Optimization
152   -- [x] 最大宽度: 480px / Max width: 480px
153   -- [x] 触摸友好的按钮尺寸 / Touch-friendly button sizes
154   -- [x] 底部导航易于触达 / Bottom nav within thumb reach
155   -- [x] 卡片式布局便于点击 / Card-based layout for easy tapping
156   -- [x] 适当的留白和间距 / Proper spacing and padding
157   -
158   -### 桌面端支持 / Desktop Support
159   -- [x] 居中布局 (max-w-[480px] mx-auto) / Centered layout
160   -- [x] 保持移动端体验 / Maintains mobile experience
161   -- [x] 响应式图片和组件 / Responsive images and components
162   -
163   ----
164   -
165   -## ✅ UI/UX 特性 / UI/UX Features
166   -
167   -### 视觉反馈 / Visual Feedback
168   -- [x] 按钮悬停效果 / Button hover effects
169   -- [x] 卡片点击效果 / Card click effects
170   -- [x] 加载状态显示 / Loading states
171   -- [x] Toast 通知 / Toast notifications
172   -- [x] 成功/错误提示 / Success/error messages
173   -
174   -### 交互设计 / Interaction Design
175   -- [x] 清晰的导航路径 / Clear navigation paths
176   -- [x] 直观的图标使用 / Intuitive icon usage
177   -- [x] 一致的交互模式 / Consistent interaction patterns
178   -- [x] 防误操作确认 (如退出登录) / Confirmation for critical actions
179   -
180   ----
181   -
182   -## ✅ 数据管理 / Data Management
183   -
184   -### localStorage 使用 / localStorage Usage
185   -- [x] isLoggedIn (登录状态) / Login status
186   -- [x] userName (用户名) / User name
187   -- [x] storeName (店铺名) / Store name
188   -- [x] storeId (店铺ID) / Store ID
189   -- [x] language (语言设置) / Language preference
190   -
191   -### Mock 数据 / Mock Data
192   -- [x] 标签类型数据 / Label types data
193   -- [x] 食品项目数据 / Food items data
194   -- [x] 任务数据 / Tasks data
195   -- [x] 店铺数据 / Stores data
196   -- [x] 打印历史数据 / Print history data
197   -
198   ----
199   -
200   -## ✅ 性能优化 / Performance Optimization
201   -
202   -### 代码组织 / Code Organization
203   -- [x] 组件模块化 / Modular components
204   -- [x] 路由懒加载支持 / Route lazy loading support
205   -- [x] Context 使用优化 / Optimized Context usage
206   -- [x] 避免不必要的重渲染 / Avoid unnecessary re-renders
207   -
208   -### 资源加载 / Resource Loading
209   -- [x] Google Fonts 优化加载 / Optimized Google Fonts loading
210   -- [x] 图标来自 lucide-react / Icons from lucide-react
211   -- [x] CSS 变量使用 / CSS variables usage
212   -
213   ----
214   -
215   -## ✅ 可访问性 / Accessibility
216   -
217   -### 基础可访问性 / Basic Accessibility
218   -- [x] 语义化HTML / Semantic HTML
219   -- [x] 按钮和链接易于区分 / Clear buttons vs links
220   -- [x] 表单标签关联 / Form label associations
221   -- [x] 键盘导航支持 / Keyboard navigation support
222   -- [x] 颜色对比度符合标准 / Color contrast meets standards
223   -
224   ----
225   -
226   -## ✅ 错误处理 / Error Handling
227   -
228   -### 用户体验 / User Experience
229   -- [x] 404 页面 / 404 page
230   -- [x] 空状态提示 / Empty states
231   -- [x] 错误提示 Toast / Error toast messages
232   -- [x] 表单验证 / Form validation
233   -- [x] 网络错误处理 / Network error handling
234   -
235   ----
236   -
237   -## 📝 待确认项 / Items to Verify
238   -
239   -### 实际使用测试 / Real Usage Testing
240   -- [ ] 在移动设备上测试 / Test on mobile devices
241   -- [ ] 在不同浏览器测试 / Test on different browsers
242   -- [ ] 打印功能集成测试 / Print functionality integration test
243   -- [ ] 性能压力测试 / Performance stress testing
244   -
245   -### 未来集成 / Future Integration
246   -- [ ] Supabase 后端集成 / Supabase backend integration
247   -- [ ] 真实打印机连接 / Real printer connection
248   -- [ ] 条形码扫描功能 / Barcode scanning
249   -- [ ] 离线模式支持 / Offline mode support
250   -
251   ----
252   -
253   -## 🎉 验证总结 / Verification Summary
254   -
255   -### ✅ 已完成 / Completed
256   -- 核心功能完整 / Core features complete
257   -- 设计规范符合要求 / Design specs met
258   -- 双语支持完善 / Bilingual support complete
259   -- 不需要的功能已移除 / Unnecessary features removed
260   -- 代码结构清晰 / Clean code structure
261   -
262   -### 🎯 系统状态 / System Status
263   -**准备就绪!/ Ready for Use!**
264   -
265   -该系统是一个专注于核心标签打印功能的简化版本,符合所有设计规范和功能要求。
266   -This system is a simplified version focused on core label printing functionality, meeting all design specifications and functional requirements.
267   -
268   ----
269   -
270   -**验证日期 / Verification Date**: 2026年2月27日 / February 27, 2026
271   -**系统版本 / System Version**: 1.0.0
272   -**验证状态 / Verification Status**: ✅ 通过 / PASSED
美国版/Food Labeling Management App React/guidelines/Guidelines.md deleted
1   -**Add your own guidelines here**
2   -<!--
3   -
4   -System Guidelines
5   -
6   -Use this file to provide the AI with rules and guidelines you want it to follow.
7   -This template outlines a few examples of things you can add. You can add your own sections and format it to suit your needs
8   -
9   -TIP: More context isn't always better. It can confuse the LLM. Try and add the most important rules you need
10   -
11   -# General guidelines
12   -
13   -Any general rules you want the AI to follow.
14   -For example:
15   -
16   -* Only use absolute positioning when necessary. Opt for responsive and well structured layouts that use flexbox and grid by default
17   -* Refactor code as you go to keep code clean
18   -* Keep file sizes small and put helper functions and components in their own files.
19   -
20   ---------------
21   -
22   -# Design system guidelines
23   -Rules for how the AI should make generations look like your company's design system
24   -
25   -Additionally, if you select a design system to use in the prompt box, you can reference
26   -your design system's components, tokens, variables and components.
27   -For example:
28   -
29   -* Use a base font-size of 14px
30   -* Date formats should always be in the format “Jun 10”
31   -* The bottom toolbar should only ever have a maximum of 4 items
32   -* Never use the floating action button with the bottom toolbar
33   -* Chips should always come in sets of 3 or more
34   -* Don't use a dropdown if there are 2 or fewer options
35   -
36   -You can also create sub sections and add more specific details
37   -For example:
38   -
39   -
40   -## Button
41   -The Button component is a fundamental interactive element in our design system, designed to trigger actions or navigate
42   -users through the application. It provides visual feedback and clear affordances to enhance user experience.
43   -
44   -### Usage
45   -Buttons should be used for important actions that users need to take, such as form submissions, confirming choices,
46   -or initiating processes. They communicate interactivity and should have clear, action-oriented labels.
47   -
48   -### Variants
49   -* Primary Button
50   - * Purpose : Used for the main action in a section or page
51   - * Visual Style : Bold, filled with the primary brand color
52   - * Usage : One primary button per section to guide users toward the most important action
53   -* Secondary Button
54   - * Purpose : Used for alternative or supporting actions
55   - * Visual Style : Outlined with the primary color, transparent background
56   - * Usage : Can appear alongside a primary button for less important actions
57   -* Tertiary Button
58   - * Purpose : Used for the least important actions
59   - * Visual Style : Text-only with no border, using primary color
60   - * Usage : For actions that should be available but not emphasized
61   --->
美国版/Food Labeling Management App React/index.html deleted
1   -
2   - <!DOCTYPE html>
3   - <html lang="en">
4   - <head>
5   - <meta charset="UTF-8" />
6   - <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7   - <title>美国版本</title>
8   - </head>
9   -
10   - <body>
11   - <div id="root"></div>
12   - <script type="module" src="/src/main.tsx"></script>
13   - </body>
14   - </html>
15   -
16 0 \ No newline at end of file
美国版/Food Labeling Management App React/package.json deleted
1   -{
2   - "name": "@figma/my-make-file",
3   - "private": true,
4   - "version": "0.0.1",
5   - "type": "module",
6   - "scripts": {
7   - "build": "vite build",
8   - "dev": "vite"
9   - },
10   - "dependencies": {
11   - "@emotion/react": "11.14.0",
12   - "@emotion/styled": "11.14.1",
13   - "@mui/icons-material": "7.3.5",
14   - "@mui/material": "7.3.5",
15   - "@popperjs/core": "2.11.8",
16   - "@radix-ui/react-accordion": "1.2.3",
17   - "@radix-ui/react-alert-dialog": "1.1.6",
18   - "@radix-ui/react-aspect-ratio": "1.1.2",
19   - "@radix-ui/react-avatar": "1.1.3",
20   - "@radix-ui/react-checkbox": "1.1.4",
21   - "@radix-ui/react-collapsible": "1.1.3",
22   - "@radix-ui/react-context-menu": "2.2.6",
23   - "@radix-ui/react-dialog": "1.1.6",
24   - "@radix-ui/react-dropdown-menu": "2.1.6",
25   - "@radix-ui/react-hover-card": "1.1.6",
26   - "@radix-ui/react-label": "2.1.2",
27   - "@radix-ui/react-menubar": "1.1.6",
28   - "@radix-ui/react-navigation-menu": "1.2.5",
29   - "@radix-ui/react-popover": "1.1.6",
30   - "@radix-ui/react-progress": "1.1.2",
31   - "@radix-ui/react-radio-group": "1.2.3",
32   - "@radix-ui/react-scroll-area": "1.2.3",
33   - "@radix-ui/react-select": "2.1.6",
34   - "@radix-ui/react-separator": "1.1.2",
35   - "@radix-ui/react-slider": "1.2.3",
36   - "@radix-ui/react-slot": "1.1.2",
37   - "@radix-ui/react-switch": "1.1.3",
38   - "@radix-ui/react-tabs": "1.1.3",
39   - "@radix-ui/react-toggle-group": "1.1.2",
40   - "@radix-ui/react-toggle": "1.1.2",
41   - "@radix-ui/react-tooltip": "1.1.8",
42   - "class-variance-authority": "0.7.1",
43   - "clsx": "2.1.1",
44   - "cmdk": "1.1.1",
45   - "date-fns": "3.6.0",
46   - "embla-carousel-react": "8.6.0",
47   - "input-otp": "1.4.2",
48   - "lucide-react": "0.487.0",
49   - "motion": "12.23.24",
50   - "next-themes": "0.4.6",
51   - "react-day-picker": "8.10.1",
52   - "react-dnd": "16.0.1",
53   - "react-dnd-html5-backend": "16.0.1",
54   - "react-hook-form": "7.55.0",
55   - "react-popper": "2.3.0",
56   - "react-resizable-panels": "2.1.7",
57   - "react-responsive-masonry": "2.7.1",
58   - "react-router": "7.13.0",
59   - "react-slick": "0.31.0",
60   - "recharts": "2.15.2",
61   - "sonner": "2.0.3",
62   - "tailwind-merge": "3.2.0",
63   - "tw-animate-css": "1.3.8",
64   - "vaul": "1.1.2"
65   - },
66   - "devDependencies": {
67   - "@tailwindcss/vite": "4.1.12",
68   - "@vitejs/plugin-react": "4.7.0",
69   - "tailwindcss": "4.1.12",
70   - "vite": "6.3.5"
71   - },
72   - "peerDependencies": {
73   - "react": "18.3.1",
74   - "react-dom": "18.3.1"
75   - },
76   - "peerDependenciesMeta": {
77   - "react": {
78   - "optional": true
79   - },
80   - "react-dom": {
81   - "optional": true
82   - }
83   - },
84   - "pnpm": {
85   - "overrides": {
86   - "vite": "6.3.5"
87   - }
88   - }
89   -}
90 0 \ No newline at end of file
美国版/Food Labeling Management App React/postcss.config.mjs deleted
1   -/**
2   - * PostCSS Configuration
3   - *
4   - * Tailwind CSS v4 (via @tailwindcss/vite) automatically sets up all required
5   - * PostCSS plugins — you do NOT need to include `tailwindcss` or `autoprefixer` here.
6   - *
7   - * This file only exists for adding additional PostCSS plugins, if needed.
8   - * For example:
9   - *
10   - * import postcssNested from 'postcss-nested'
11   - * export default { plugins: [postcssNested()] }
12   - *
13   - * Otherwise, you can leave this file empty.
14   - */
15   -export default {}
美国版/Food Labeling Management App React/src/app/App.tsx deleted
1   -import { RouterProvider } from 'react-router';
2   -import { router } from './routes';
3   -
4   -export default function App() {
5   - return <RouterProvider router={router} />;
6   -}
7 0 \ No newline at end of file
美国版/Food Labeling Management App React/src/app/components/ExpiryAlert.tsx deleted
1   -import { useEffect, useState } from "react";
2   -import { AlertTriangle, X } from "lucide-react";
3   -import { Button } from "./ui/button";
4   -import { useLanguage } from "../contexts/LanguageContext";
5   -
6   -interface ExpiryItem {
7   - id: string;
8   - nameKey: string;
9   - expiryDate: string;
10   - location: string;
11   -}
12   -
13   -export function ExpiryAlert() {
14   - const { t } = useLanguage();
15   - const [showAlert, setShowAlert] = useState(false);
16   - const [expiryItems, setExpiryItems] = useState<ExpiryItem[]>([]);
17   -
18   - useEffect(() => {
19   - // Check for expiring items every minute
20   - const checkExpiry = () => {
21   - const now = new Date();
22   - const tomorrow = new Date(now);
23   - tomorrow.setDate(tomorrow.getDate() + 1);
24   -
25   - // Mock data - in real app, this would come from API
26   - const items: ExpiryItem[] = [
27   - {
28   - id: "1",
29   - nameKey: "food.chickenBreast",
30   - expiryDate: tomorrow.toLocaleDateString(),
31   - location: "Main Kitchen - Fridge #1",
32   - },
33   - {
34   - id: "2",
35   - nameKey: "food.caesarSalad",
36   - expiryDate: tomorrow.toLocaleDateString(),
37   - location: "Prep Station - Cooler",
38   - },
39   - ];
40   -
41   - if (items.length > 0) {
42   - setExpiryItems(items);
43   - setShowAlert(true);
44   - }
45   - };
46   -
47   - // Check on mount and every 5 minutes
48   - checkExpiry();
49   - const interval = setInterval(checkExpiry, 5 * 60 * 1000);
50   -
51   - return () => clearInterval(interval);
52   - }, []);
53   -
54   - if (!showAlert) return null;
55   -
56   - return (
57   - <div className="fixed inset-0 bg-black/80 backdrop-blur-sm z-50 flex items-center justify-center p-6">
58   - <div className="bg-white rounded-2xl max-w-md w-full shadow-2xl">
59   - {/* Header */}
60   - <div className="bg-gradient-to-r from-orange-500 to-red-500 p-6 rounded-t-2xl">
61   - <div className="flex items-center justify-between mb-4">
62   - <div className="flex items-center gap-3">
63   - <div className="p-3 bg-white rounded-full">
64   - <AlertTriangle className="w-8 h-8 text-orange-500" />
65   - </div>
66   - <div>
67   - <h2 className="text-2xl font-bold text-white">
68   - {t("expiryAlert.title")}
69   - </h2>
70   - <p className="text-orange-50">
71   - {expiryItems.length} {t("expiryAlert.itemsExpiring")}
72   - </p>
73   - </div>
74   - </div>
75   - <button
76   - onClick={() => setShowAlert(false)}
77   - className="text-white hover:bg-white/20 rounded-full p-2 transition-colors"
78   - >
79   - <X className="w-6 h-6" />
80   - </button>
81   - </div>
82   - </div>
83   -
84   - {/* Content */}
85   - <div className="p-6 space-y-4 max-h-96 overflow-y-auto">
86   - <p className="text-base text-gray-700 font-medium">
87   - {t("expiryAlert.message")}
88   - </p>
89   -
90   - <div className="space-y-3">
91   - {expiryItems.map((item) => (
92   - <div
93   - key={item.id}
94   - className="p-4 bg-orange-50 border border-orange-200 rounded-lg"
95   - >
96   - <div className="flex items-start justify-between gap-3">
97   - <div className="flex-1">
98   - <h3 className="font-semibold text-gray-900 mb-1">
99   - {t(item.nameKey)}
100   - </h3>
101   - <p className="text-sm text-gray-600 mb-1">
102   - {t("expiryAlert.location")}: {item.location}
103   - </p>
104   - <p className="text-sm text-orange-700 font-medium">
105   - {t("expiryAlert.expires")}: {item.expiryDate}
106   - </p>
107   - </div>
108   - </div>
109   - </div>
110   - ))}
111   - </div>
112   - </div>
113   -
114   - {/* Actions */}
115   - <div className="p-6 bg-gray-50 rounded-b-2xl space-y-3">
116   - <Button
117   - onClick={() => {
118   - setShowAlert(false);
119   - // Navigate to labels or inventory
120   - }}
121   - className="w-full h-12 text-base font-semibold"
122   - >
123   - {t("expiryAlert.viewAll")}
124   - </Button>
125   - <Button
126   - variant="outline"
127   - onClick={() => setShowAlert(false)}
128   - className="w-full h-12 text-base"
129   - >
130   - {t("expiryAlert.dismiss")}
131   - </Button>
132   - </div>
133   - </div>
134   - </div>
135   - );
136   -}
美国版/Food Labeling Management App React/src/app/components/Layout.tsx deleted
1   -import { Outlet, useNavigate, useLocation } from "react-router";
2   -import { Home, Tag, Menu } from "lucide-react";
3   -import { useEffect } from "react";
4   -import { useLanguage } from "../contexts/LanguageContext";
5   -
6   -export default function Layout() {
7   - const navigate = useNavigate();
8   - const location = useLocation();
9   - const { t } = useLanguage();
10   -
11   - useEffect(() => {
12   - // Check if user is logged in
13   - const isLoggedIn = localStorage.getItem("isLoggedIn");
14   - if (!isLoggedIn) {
15   - navigate("/login");
16   - }
17   - }, [navigate]);
18   -
19   - const navItems = [
20   - { path: "/", icon: Home, label: t("nav.dashboard") },
21   - { path: "/labels", icon: Tag, label: t("nav.labels") },
22   - { path: "/more", icon: Menu, label: t("nav.more") },
23   - ];
24   -
25   - const isActive = (path: string) => {
26   - if (path === "/") {
27   - return location.pathname === "/";
28   - }
29   - return location.pathname.startsWith(path);
30   - };
31   -
32   - return (
33   - <div className="min-h-screen bg-gray-50 flex flex-col">
34   - {/* Main Content */}
35   - <main className="flex-1 pb-20 overflow-y-auto">
36   - <div className="max-w-[480px] mx-auto">
37   - <Outlet />
38   - </div>
39   - </main>
40   -
41   - {/* Bottom Navigation */}
42   - <nav className="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-200 safe-area-inset-bottom">
43   - <div className="max-w-[480px] mx-auto flex justify-around items-center h-20">
44   - {navItems.map((item) => {
45   - const Icon = item.icon;
46   - const active = isActive(item.path);
47   - return (
48   - <button
49   - key={item.path}
50   - onClick={() => navigate(item.path)}
51   - className="flex flex-col items-center justify-center flex-1 h-full gap-1"
52   - >
53   - <Icon
54   - className={`w-6 h-6 ${
55   - active ? "text-blue-600" : "text-gray-400"
56   - }`}
57   - />
58   - <span
59   - className={`text-xs ${
60   - active ? "text-blue-600 font-semibold" : "text-gray-500"
61   - }`}
62   - >
63   - {item.label}
64   - </span>
65   - </button>
66   - );
67   - })}
68   - </div>
69   - </nav>
70   - </div>
71   - );
72   -}
73 0 \ No newline at end of file
美国版/Food Labeling Management App React/src/app/components/RootLayout.tsx deleted
1   -import { LanguageProvider } from "../contexts/LanguageContext";
2   -import { Toaster } from "./ui/sonner";
3   -import { ExpiryAlert } from "./ExpiryAlert";
4   -
5   -export default function RootLayout({ children }: { children: React.ReactNode }) {
6   - return (
7   - <LanguageProvider>
8   - {children}
9   - <ExpiryAlert />
10   - <Toaster />
11   - </LanguageProvider>
12   - );
13   -}
美国版/Food Labeling Management App React/src/app/components/figma/ImageWithFallback.tsx deleted
1   -import React, { useState } from 'react'
2   -
3   -const ERROR_IMG_SRC =
4   - 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODgiIGhlaWdodD0iODgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBvcGFjaXR5PSIuMyIgZmlsbD0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIzLjciPjxyZWN0IHg9IjE2IiB5PSIxNiIgd2lkdGg9IjU2IiBoZWlnaHQ9IjU2IiByeD0iNiIvPjxwYXRoIGQ9Im0xNiA1OCAxNi0xOCAzMiAzMiIvPjxjaXJjbGUgY3g9IjUzIiBjeT0iMzUiIHI9IjciLz48L3N2Zz4KCg=='
5   -
6   -export function ImageWithFallback(props: React.ImgHTMLAttributes<HTMLImageElement>) {
7   - const [didError, setDidError] = useState(false)
8   -
9   - const handleError = () => {
10   - setDidError(true)
11   - }
12   -
13   - const { src, alt, style, className, ...rest } = props
14   -
15   - return didError ? (
16   - <div
17   - className={`inline-block bg-gray-100 text-center align-middle ${className ?? ''}`}
18   - style={style}
19   - >
20   - <div className="flex items-center justify-center w-full h-full">
21   - <img src={ERROR_IMG_SRC} alt="Error loading image" {...rest} data-original-url={src} />
22   - </div>
23   - </div>
24   - ) : (
25   - <img src={src} alt={alt} className={className} style={style} {...rest} onError={handleError} />
26   - )
27   -}
美国版/Food Labeling Management App React/src/app/components/states/EmptyState.tsx deleted
1   -import { LucideIcon } from "lucide-react";
2   -import { Button } from "../ui/button";
3   -
4   -interface EmptyStateProps {
5   - icon: LucideIcon;
6   - title: string;
7   - description: string;
8   - actionLabel?: string;
9   - onAction?: () => void;
10   -}
11   -
12   -export default function EmptyState({
13   - icon: Icon,
14   - title,
15   - description,
16   - actionLabel,
17   - onAction,
18   -}: EmptyStateProps) {
19   - return (
20   - <div className="flex flex-col items-center justify-center py-16 px-6">
21   - <div className="w-24 h-24 bg-gray-100 rounded-full flex items-center justify-center mb-4">
22   - <Icon className="w-12 h-12 text-gray-400" />
23   - </div>
24   - <h3 className="text-lg font-semibold text-gray-900 mb-2">{title}</h3>
25   - <p className="text-base text-gray-500 text-center max-w-sm mb-6">
26   - {description}
27   - </p>
28   - {actionLabel && onAction && (
29   - <Button onClick={onAction} className="h-12 text-base font-semibold">
30   - {actionLabel}
31   - </Button>
32   - )}
33   - </div>
34   - );
35   -}
美国版/Food Labeling Management App React/src/app/components/states/ErrorState.tsx deleted
1   -import { WifiOff, AlertCircle } from "lucide-react";
2   -import { Button } from "../ui/button";
3   -
4   -interface ErrorStateProps {
5   - type: "network" | "error" | "print-failed";
6   - message?: string;
7   - onRetry?: () => void;
8   -}
9   -
10   -export default function ErrorState({ type, message, onRetry }: ErrorStateProps) {
11   - const configs = {
12   - network: {
13   - icon: WifiOff,
14   - title: "No Internet Connection",
15   - description:
16   - message ||
17   - "Please check your internet connection and try again. You can continue working offline.",
18   - color: "text-orange-600",
19   - bgColor: "bg-orange-100",
20   - },
21   - error: {
22   - icon: AlertCircle,
23   - title: "Something Went Wrong",
24   - description: message || "An unexpected error occurred. Please try again.",
25   - color: "text-red-600",
26   - bgColor: "bg-red-100",
27   - },
28   - "print-failed": {
29   - icon: AlertCircle,
30   - title: "Print Failed",
31   - description:
32   - message ||
33   - "Unable to print the label. Please check your printer connection and try again.",
34   - color: "text-red-600",
35   - bgColor: "bg-red-100",
36   - },
37   - };
38   -
39   - const config = configs[type];
40   - const Icon = config.icon;
41   -
42   - return (
43   - <div className="flex flex-col items-center justify-center min-h-screen bg-gray-50 p-6">
44   - <div
45   - className={`w-24 h-24 ${config.bgColor} rounded-full flex items-center justify-center mb-4`}
46   - >
47   - <Icon className={`w-12 h-12 ${config.color}`} />
48   - </div>
49   - <h3 className="text-lg font-semibold text-gray-900 mb-2">
50   - {config.title}
51   - </h3>
52   - <p className="text-base text-gray-500 text-center max-w-sm mb-6">
53   - {config.description}
54   - </p>
55   - {onRetry && (
56   - <Button onClick={onRetry} className="h-12 text-base font-semibold">
57   - Try Again
58   - </Button>
59   - )}
60   - </div>
61   - );
62   -}
美国版/Food Labeling Management App React/src/app/components/states/Loading.tsx deleted
1   -import { Loader2 } from "lucide-react";
2   -
3   -interface LoadingProps {
4   - message?: string;
5   -}
6   -
7   -export default function Loading({ message = "Loading..." }: LoadingProps) {
8   - return (
9   - <div className="flex flex-col items-center justify-center min-h-screen bg-gray-50 p-6">
10   - <Loader2 className="w-12 h-12 text-blue-600 animate-spin mb-4" />
11   - <p className="text-base text-gray-600">{message}</p>
12   - </div>
13   - );
14   -}
美国版/Food Labeling Management App React/src/app/components/states/README.md deleted
1   -# State Components
2   -
3   -This directory contains reusable state components for the application:
4   -
5   -## Components
6   -
7   -### Loading
8   -Shows a loading spinner with optional message
9   -```tsx
10   -<Loading message="Loading data..." />
11   -```
12   -
13   -### EmptyState
14   -Shows when no data is available
15   -```tsx
16   -<EmptyState
17   - icon={PackageOpen}
18   - title="No Labels Found"
19   - description="There are no labels matching your search criteria."
20   - actionLabel="Create Label"
21   - onAction={() => navigate('/labels/create')}
22   -/>
23   -```
24   -
25   -### ErrorState
26   -Shows error states (network, general errors, print failures)
27   -```tsx
28   -<ErrorState
29   - type="network"
30   - onRetry={() => fetchData()}
31   -/>
32   -```
33   -
34   -### SuccessState
35   -Shows success confirmation
36   -```tsx
37   -<SuccessState
38   - title="Success!"
39   - description="Your task has been completed."
40   - actionLabel="Continue"
41   - onAction={() => navigate('/tasks')}
42   -/>
43   -```
44   -
45   -## Usage
46   -
47   -All state components are designed to be full-screen overlays that maintain the professional European/American enterprise design style with:
48   -- Large icons in colored backgrounds
49   -- Clear, concise messaging
50   -- Prominent call-to-action buttons
51   -- Consistent spacing and typography
美国版/Food Labeling Management App React/src/app/components/states/SuccessState.tsx deleted
1   -import { CheckCircle2 } from "lucide-react";
2   -import { Button } from "../ui/button";
3   -
4   -interface SuccessStateProps {
5   - title: string;
6   - description: string;
7   - actionLabel?: string;
8   - onAction?: () => void;
9   -}
10   -
11   -export default function SuccessState({
12   - title,
13   - description,
14   - actionLabel,
15   - onAction,
16   -}: SuccessStateProps) {
17   - return (
18   - <div className="flex flex-col items-center justify-center min-h-screen bg-gray-50 p-6">
19   - <div className="w-24 h-24 bg-green-100 rounded-full flex items-center justify-center mb-4">
20   - <CheckCircle2 className="w-12 h-12 text-green-600" />
21   - </div>
22   - <h3 className="text-lg font-semibold text-gray-900 mb-2">{title}</h3>
23   - <p className="text-base text-gray-500 text-center max-w-sm mb-6">
24   - {description}
25   - </p>
26   - {actionLabel && onAction && (
27   - <Button onClick={onAction} className="h-12 text-base font-semibold">
28   - {actionLabel}
29   - </Button>
30   - )}
31   - </div>
32   - );
33   -}
美国版/Food Labeling Management App React/src/app/components/ui/accordion.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import * as AccordionPrimitive from "@radix-ui/react-accordion";
5   -import { ChevronDownIcon } from "lucide-react";
6   -
7   -import { cn } from "./utils";
8   -
9   -function Accordion({
10   - ...props
11   -}: React.ComponentProps<typeof AccordionPrimitive.Root>) {
12   - return <AccordionPrimitive.Root data-slot="accordion" {...props} />;
13   -}
14   -
15   -function AccordionItem({
16   - className,
17   - ...props
18   -}: React.ComponentProps<typeof AccordionPrimitive.Item>) {
19   - return (
20   - <AccordionPrimitive.Item
21   - data-slot="accordion-item"
22   - className={cn("border-b last:border-b-0", className)}
23   - {...props}
24   - />
25   - );
26   -}
27   -
28   -function AccordionTrigger({
29   - className,
30   - children,
31   - ...props
32   -}: React.ComponentProps<typeof AccordionPrimitive.Trigger>) {
33   - return (
34   - <AccordionPrimitive.Header className="flex">
35   - <AccordionPrimitive.Trigger
36   - data-slot="accordion-trigger"
37   - className={cn(
38   - "focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180",
39   - className,
40   - )}
41   - {...props}
42   - >
43   - {children}
44   - <ChevronDownIcon className="text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200" />
45   - </AccordionPrimitive.Trigger>
46   - </AccordionPrimitive.Header>
47   - );
48   -}
49   -
50   -function AccordionContent({
51   - className,
52   - children,
53   - ...props
54   -}: React.ComponentProps<typeof AccordionPrimitive.Content>) {
55   - return (
56   - <AccordionPrimitive.Content
57   - data-slot="accordion-content"
58   - className="data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm"
59   - {...props}
60   - >
61   - <div className={cn("pt-0 pb-4", className)}>{children}</div>
62   - </AccordionPrimitive.Content>
63   - );
64   -}
65   -
66   -export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
美国版/Food Labeling Management App React/src/app/components/ui/alert-dialog.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
5   -
6   -import { cn } from "./utils";
7   -import { buttonVariants } from "./button";
8   -
9   -function AlertDialog({
10   - ...props
11   -}: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
12   - return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />;
13   -}
14   -
15   -function AlertDialogTrigger({
16   - ...props
17   -}: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {
18   - return (
19   - <AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
20   - );
21   -}
22   -
23   -function AlertDialogPortal({
24   - ...props
25   -}: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {
26   - return (
27   - <AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
28   - );
29   -}
30   -
31   -function AlertDialogOverlay({
32   - className,
33   - ...props
34   -}: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {
35   - return (
36   - <AlertDialogPrimitive.Overlay
37   - data-slot="alert-dialog-overlay"
38   - className={cn(
39   - "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
40   - className,
41   - )}
42   - {...props}
43   - />
44   - );
45   -}
46   -
47   -function AlertDialogContent({
48   - className,
49   - ...props
50   -}: React.ComponentProps<typeof AlertDialogPrimitive.Content>) {
51   - return (
52   - <AlertDialogPortal>
53   - <AlertDialogOverlay />
54   - <AlertDialogPrimitive.Content
55   - data-slot="alert-dialog-content"
56   - className={cn(
57   - "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
58   - className,
59   - )}
60   - {...props}
61   - />
62   - </AlertDialogPortal>
63   - );
64   -}
65   -
66   -function AlertDialogHeader({
67   - className,
68   - ...props
69   -}: React.ComponentProps<"div">) {
70   - return (
71   - <div
72   - data-slot="alert-dialog-header"
73   - className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
74   - {...props}
75   - />
76   - );
77   -}
78   -
79   -function AlertDialogFooter({
80   - className,
81   - ...props
82   -}: React.ComponentProps<"div">) {
83   - return (
84   - <div
85   - data-slot="alert-dialog-footer"
86   - className={cn(
87   - "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
88   - className,
89   - )}
90   - {...props}
91   - />
92   - );
93   -}
94   -
95   -function AlertDialogTitle({
96   - className,
97   - ...props
98   -}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
99   - return (
100   - <AlertDialogPrimitive.Title
101   - data-slot="alert-dialog-title"
102   - className={cn("text-lg font-semibold", className)}
103   - {...props}
104   - />
105   - );
106   -}
107   -
108   -function AlertDialogDescription({
109   - className,
110   - ...props
111   -}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
112   - return (
113   - <AlertDialogPrimitive.Description
114   - data-slot="alert-dialog-description"
115   - className={cn("text-muted-foreground text-sm", className)}
116   - {...props}
117   - />
118   - );
119   -}
120   -
121   -function AlertDialogAction({
122   - className,
123   - ...props
124   -}: React.ComponentProps<typeof AlertDialogPrimitive.Action>) {
125   - return (
126   - <AlertDialogPrimitive.Action
127   - className={cn(buttonVariants(), className)}
128   - {...props}
129   - />
130   - );
131   -}
132   -
133   -function AlertDialogCancel({
134   - className,
135   - ...props
136   -}: React.ComponentProps<typeof AlertDialogPrimitive.Cancel>) {
137   - return (
138   - <AlertDialogPrimitive.Cancel
139   - className={cn(buttonVariants({ variant: "outline" }), className)}
140   - {...props}
141   - />
142   - );
143   -}
144   -
145   -export {
146   - AlertDialog,
147   - AlertDialogPortal,
148   - AlertDialogOverlay,
149   - AlertDialogTrigger,
150   - AlertDialogContent,
151   - AlertDialogHeader,
152   - AlertDialogFooter,
153   - AlertDialogTitle,
154   - AlertDialogDescription,
155   - AlertDialogAction,
156   - AlertDialogCancel,
157   -};
美国版/Food Labeling Management App React/src/app/components/ui/alert.tsx deleted
1   -import * as React from "react";
2   -import { cva, type VariantProps } from "class-variance-authority";
3   -
4   -import { cn } from "./utils";
5   -
6   -const alertVariants = cva(
7   - "relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
8   - {
9   - variants: {
10   - variant: {
11   - default: "bg-card text-card-foreground",
12   - destructive:
13   - "text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90",
14   - },
15   - },
16   - defaultVariants: {
17   - variant: "default",
18   - },
19   - },
20   -);
21   -
22   -function Alert({
23   - className,
24   - variant,
25   - ...props
26   -}: React.ComponentProps<"div"> & VariantProps<typeof alertVariants>) {
27   - return (
28   - <div
29   - data-slot="alert"
30   - role="alert"
31   - className={cn(alertVariants({ variant }), className)}
32   - {...props}
33   - />
34   - );
35   -}
36   -
37   -function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
38   - return (
39   - <div
40   - data-slot="alert-title"
41   - className={cn(
42   - "col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight",
43   - className,
44   - )}
45   - {...props}
46   - />
47   - );
48   -}
49   -
50   -function AlertDescription({
51   - className,
52   - ...props
53   -}: React.ComponentProps<"div">) {
54   - return (
55   - <div
56   - data-slot="alert-description"
57   - className={cn(
58   - "text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed",
59   - className,
60   - )}
61   - {...props}
62   - />
63   - );
64   -}
65   -
66   -export { Alert, AlertTitle, AlertDescription };
美国版/Food Labeling Management App React/src/app/components/ui/aspect-ratio.tsx deleted
1   -"use client";
2   -
3   -import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio";
4   -
5   -function AspectRatio({
6   - ...props
7   -}: React.ComponentProps<typeof AspectRatioPrimitive.Root>) {
8   - return <AspectRatioPrimitive.Root data-slot="aspect-ratio" {...props} />;
9   -}
10   -
11   -export { AspectRatio };
美国版/Food Labeling Management App React/src/app/components/ui/avatar.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import * as AvatarPrimitive from "@radix-ui/react-avatar";
5   -
6   -import { cn } from "./utils";
7   -
8   -function Avatar({
9   - className,
10   - ...props
11   -}: React.ComponentProps<typeof AvatarPrimitive.Root>) {
12   - return (
13   - <AvatarPrimitive.Root
14   - data-slot="avatar"
15   - className={cn(
16   - "relative flex size-10 shrink-0 overflow-hidden rounded-full",
17   - className,
18   - )}
19   - {...props}
20   - />
21   - );
22   -}
23   -
24   -function AvatarImage({
25   - className,
26   - ...props
27   -}: React.ComponentProps<typeof AvatarPrimitive.Image>) {
28   - return (
29   - <AvatarPrimitive.Image
30   - data-slot="avatar-image"
31   - className={cn("aspect-square size-full", className)}
32   - {...props}
33   - />
34   - );
35   -}
36   -
37   -function AvatarFallback({
38   - className,
39   - ...props
40   -}: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
41   - return (
42   - <AvatarPrimitive.Fallback
43   - data-slot="avatar-fallback"
44   - className={cn(
45   - "bg-muted flex size-full items-center justify-center rounded-full",
46   - className,
47   - )}
48   - {...props}
49   - />
50   - );
51   -}
52   -
53   -export { Avatar, AvatarImage, AvatarFallback };
美国版/Food Labeling Management App React/src/app/components/ui/badge.tsx deleted
1   -import * as React from "react";
2   -import { Slot } from "@radix-ui/react-slot";
3   -import { cva, type VariantProps } from "class-variance-authority";
4   -
5   -import { cn } from "./utils";
6   -
7   -const badgeVariants = cva(
8   - "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
9   - {
10   - variants: {
11   - variant: {
12   - default:
13   - "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
14   - secondary:
15   - "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
16   - destructive:
17   - "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
18   - outline:
19   - "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
20   - },
21   - },
22   - defaultVariants: {
23   - variant: "default",
24   - },
25   - },
26   -);
27   -
28   -function Badge({
29   - className,
30   - variant,
31   - asChild = false,
32   - ...props
33   -}: React.ComponentProps<"span"> &
34   - VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
35   - const Comp = asChild ? Slot : "span";
36   -
37   - return (
38   - <Comp
39   - data-slot="badge"
40   - className={cn(badgeVariants({ variant }), className)}
41   - {...props}
42   - />
43   - );
44   -}
45   -
46   -export { Badge, badgeVariants };
美国版/Food Labeling Management App React/src/app/components/ui/breadcrumb.tsx deleted
1   -import * as React from "react";
2   -import { Slot } from "@radix-ui/react-slot";
3   -import { ChevronRight, MoreHorizontal } from "lucide-react";
4   -
5   -import { cn } from "./utils";
6   -
7   -function Breadcrumb({ ...props }: React.ComponentProps<"nav">) {
8   - return <nav aria-label="breadcrumb" data-slot="breadcrumb" {...props} />;
9   -}
10   -
11   -function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
12   - return (
13   - <ol
14   - data-slot="breadcrumb-list"
15   - className={cn(
16   - "text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5",
17   - className,
18   - )}
19   - {...props}
20   - />
21   - );
22   -}
23   -
24   -function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
25   - return (
26   - <li
27   - data-slot="breadcrumb-item"
28   - className={cn("inline-flex items-center gap-1.5", className)}
29   - {...props}
30   - />
31   - );
32   -}
33   -
34   -function BreadcrumbLink({
35   - asChild,
36   - className,
37   - ...props
38   -}: React.ComponentProps<"a"> & {
39   - asChild?: boolean;
40   -}) {
41   - const Comp = asChild ? Slot : "a";
42   -
43   - return (
44   - <Comp
45   - data-slot="breadcrumb-link"
46   - className={cn("hover:text-foreground transition-colors", className)}
47   - {...props}
48   - />
49   - );
50   -}
51   -
52   -function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
53   - return (
54   - <span
55   - data-slot="breadcrumb-page"
56   - role="link"
57   - aria-disabled="true"
58   - aria-current="page"
59   - className={cn("text-foreground font-normal", className)}
60   - {...props}
61   - />
62   - );
63   -}
64   -
65   -function BreadcrumbSeparator({
66   - children,
67   - className,
68   - ...props
69   -}: React.ComponentProps<"li">) {
70   - return (
71   - <li
72   - data-slot="breadcrumb-separator"
73   - role="presentation"
74   - aria-hidden="true"
75   - className={cn("[&>svg]:size-3.5", className)}
76   - {...props}
77   - >
78   - {children ?? <ChevronRight />}
79   - </li>
80   - );
81   -}
82   -
83   -function BreadcrumbEllipsis({
84   - className,
85   - ...props
86   -}: React.ComponentProps<"span">) {
87   - return (
88   - <span
89   - data-slot="breadcrumb-ellipsis"
90   - role="presentation"
91   - aria-hidden="true"
92   - className={cn("flex size-9 items-center justify-center", className)}
93   - {...props}
94   - >
95   - <MoreHorizontal className="size-4" />
96   - <span className="sr-only">More</span>
97   - </span>
98   - );
99   -}
100   -
101   -export {
102   - Breadcrumb,
103   - BreadcrumbList,
104   - BreadcrumbItem,
105   - BreadcrumbLink,
106   - BreadcrumbPage,
107   - BreadcrumbSeparator,
108   - BreadcrumbEllipsis,
109   -};
美国版/Food Labeling Management App React/src/app/components/ui/button.tsx deleted
1   -import * as React from "react";
2   -import { Slot } from "@radix-ui/react-slot";
3   -import { cva, type VariantProps } from "class-variance-authority";
4   -
5   -import { cn } from "./utils";
6   -
7   -const buttonVariants = cva(
8   - "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
9   - {
10   - variants: {
11   - variant: {
12   - default: "bg-primary text-primary-foreground hover:bg-primary/90",
13   - destructive:
14   - "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
15   - outline:
16   - "border bg-background text-foreground hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
17   - secondary:
18   - "bg-secondary text-secondary-foreground hover:bg-secondary/80",
19   - ghost:
20   - "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
21   - link: "text-primary underline-offset-4 hover:underline",
22   - },
23   - size: {
24   - default: "h-12 px-4 py-2 has-[>svg]:px-3",
25   - sm: "h-10 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
26   - lg: "h-14 rounded-md px-6 has-[>svg]:px-4",
27   - icon: "size-12 rounded-md",
28   - },
29   - },
30   - defaultVariants: {
31   - variant: "default",
32   - size: "default",
33   - },
34   - },
35   -);
36   -
37   -function Button({
38   - className,
39   - variant,
40   - size,
41   - asChild = false,
42   - ...props
43   -}: React.ComponentProps<"button"> &
44   - VariantProps<typeof buttonVariants> & {
45   - asChild?: boolean;
46   - }) {
47   - const Comp = asChild ? Slot : "button";
48   -
49   - return (
50   - <Comp
51   - data-slot="button"
52   - className={cn(buttonVariants({ variant, size, className }))}
53   - {...props}
54   - />
55   - );
56   -}
57   -
58   -export { Button, buttonVariants };
59 0 \ No newline at end of file
美国版/Food Labeling Management App React/src/app/components/ui/calendar.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import { ChevronLeft, ChevronRight } from "lucide-react";
5   -import { DayPicker } from "react-day-picker";
6   -
7   -import { cn } from "./utils";
8   -import { buttonVariants } from "./button";
9   -
10   -function Calendar({
11   - className,
12   - classNames,
13   - showOutsideDays = true,
14   - ...props
15   -}: React.ComponentProps<typeof DayPicker>) {
16   - return (
17   - <DayPicker
18   - showOutsideDays={showOutsideDays}
19   - className={cn("p-3", className)}
20   - classNames={{
21   - months: "flex flex-col sm:flex-row gap-2",
22   - month: "flex flex-col gap-4",
23   - caption: "flex justify-center pt-1 relative items-center w-full",
24   - caption_label: "text-sm font-medium",
25   - nav: "flex items-center gap-1",
26   - nav_button: cn(
27   - buttonVariants({ variant: "outline" }),
28   - "size-7 bg-transparent p-0 opacity-50 hover:opacity-100",
29   - ),
30   - nav_button_previous: "absolute left-1",
31   - nav_button_next: "absolute right-1",
32   - table: "w-full border-collapse space-x-1",
33   - head_row: "flex",
34   - head_cell:
35   - "text-muted-foreground rounded-md w-8 font-normal text-[0.8rem]",
36   - row: "flex w-full mt-2",
37   - cell: cn(
38   - "relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-accent [&:has([aria-selected].day-range-end)]:rounded-r-md",
39   - props.mode === "range"
40   - ? "[&:has(>.day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md"
41   - : "[&:has([aria-selected])]:rounded-md",
42   - ),
43   - day: cn(
44   - buttonVariants({ variant: "ghost" }),
45   - "size-8 p-0 font-normal aria-selected:opacity-100",
46   - ),
47   - day_range_start:
48   - "day-range-start aria-selected:bg-primary aria-selected:text-primary-foreground",
49   - day_range_end:
50   - "day-range-end aria-selected:bg-primary aria-selected:text-primary-foreground",
51   - day_selected:
52   - "bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
53   - day_today: "bg-accent text-accent-foreground",
54   - day_outside:
55   - "day-outside text-muted-foreground aria-selected:text-muted-foreground",
56   - day_disabled: "text-muted-foreground opacity-50",
57   - day_range_middle:
58   - "aria-selected:bg-accent aria-selected:text-accent-foreground",
59   - day_hidden: "invisible",
60   - ...classNames,
61   - }}
62   - components={{
63   - IconLeft: ({ className, ...props }) => (
64   - <ChevronLeft className={cn("size-4", className)} {...props} />
65   - ),
66   - IconRight: ({ className, ...props }) => (
67   - <ChevronRight className={cn("size-4", className)} {...props} />
68   - ),
69   - }}
70   - {...props}
71   - />
72   - );
73   -}
74   -
75   -export { Calendar };
美国版/Food Labeling Management App React/src/app/components/ui/card.tsx deleted
1   -import * as React from "react";
2   -
3   -import { cn } from "./utils";
4   -
5   -function Card({ className, ...props }: React.ComponentProps<"div">) {
6   - return (
7   - <div
8   - data-slot="card"
9   - className={cn(
10   - "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border",
11   - className,
12   - )}
13   - {...props}
14   - />
15   - );
16   -}
17   -
18   -function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
19   - return (
20   - <div
21   - data-slot="card-header"
22   - className={cn(
23   - "@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 pt-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
24   - className,
25   - )}
26   - {...props}
27   - />
28   - );
29   -}
30   -
31   -function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
32   - return (
33   - <h4
34   - data-slot="card-title"
35   - className={cn("leading-none", className)}
36   - {...props}
37   - />
38   - );
39   -}
40   -
41   -function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
42   - return (
43   - <p
44   - data-slot="card-description"
45   - className={cn("text-muted-foreground", className)}
46   - {...props}
47   - />
48   - );
49   -}
50   -
51   -function CardAction({ className, ...props }: React.ComponentProps<"div">) {
52   - return (
53   - <div
54   - data-slot="card-action"
55   - className={cn(
56   - "col-start-2 row-span-2 row-start-1 self-start justify-self-end",
57   - className,
58   - )}
59   - {...props}
60   - />
61   - );
62   -}
63   -
64   -function CardContent({ className, ...props }: React.ComponentProps<"div">) {
65   - return (
66   - <div
67   - data-slot="card-content"
68   - className={cn("px-6 [&:last-child]:pb-6", className)}
69   - {...props}
70   - />
71   - );
72   -}
73   -
74   -function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
75   - return (
76   - <div
77   - data-slot="card-footer"
78   - className={cn("flex items-center px-6 pb-6 [.border-t]:pt-6", className)}
79   - {...props}
80   - />
81   - );
82   -}
83   -
84   -export {
85   - Card,
86   - CardHeader,
87   - CardFooter,
88   - CardTitle,
89   - CardAction,
90   - CardDescription,
91   - CardContent,
92   -};
美国版/Food Labeling Management App React/src/app/components/ui/carousel.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import useEmblaCarousel, {
5   - type UseEmblaCarouselType,
6   -} from "embla-carousel-react";
7   -import { ArrowLeft, ArrowRight } from "lucide-react";
8   -
9   -import { cn } from "./utils";
10   -import { Button } from "./button";
11   -
12   -type CarouselApi = UseEmblaCarouselType[1];
13   -type UseCarouselParameters = Parameters<typeof useEmblaCarousel>;
14   -type CarouselOptions = UseCarouselParameters[0];
15   -type CarouselPlugin = UseCarouselParameters[1];
16   -
17   -type CarouselProps = {
18   - opts?: CarouselOptions;
19   - plugins?: CarouselPlugin;
20   - orientation?: "horizontal" | "vertical";
21   - setApi?: (api: CarouselApi) => void;
22   -};
23   -
24   -type CarouselContextProps = {
25   - carouselRef: ReturnType<typeof useEmblaCarousel>[0];
26   - api: ReturnType<typeof useEmblaCarousel>[1];
27   - scrollPrev: () => void;
28   - scrollNext: () => void;
29   - canScrollPrev: boolean;
30   - canScrollNext: boolean;
31   -} & CarouselProps;
32   -
33   -const CarouselContext = React.createContext<CarouselContextProps | null>(null);
34   -
35   -function useCarousel() {
36   - const context = React.useContext(CarouselContext);
37   -
38   - if (!context) {
39   - throw new Error("useCarousel must be used within a <Carousel />");
40   - }
41   -
42   - return context;
43   -}
44   -
45   -function Carousel({
46   - orientation = "horizontal",
47   - opts,
48   - setApi,
49   - plugins,
50   - className,
51   - children,
52   - ...props
53   -}: React.ComponentProps<"div"> & CarouselProps) {
54   - const [carouselRef, api] = useEmblaCarousel(
55   - {
56   - ...opts,
57   - axis: orientation === "horizontal" ? "x" : "y",
58   - },
59   - plugins,
60   - );
61   - const [canScrollPrev, setCanScrollPrev] = React.useState(false);
62   - const [canScrollNext, setCanScrollNext] = React.useState(false);
63   -
64   - const onSelect = React.useCallback((api: CarouselApi) => {
65   - if (!api) return;
66   - setCanScrollPrev(api.canScrollPrev());
67   - setCanScrollNext(api.canScrollNext());
68   - }, []);
69   -
70   - const scrollPrev = React.useCallback(() => {
71   - api?.scrollPrev();
72   - }, [api]);
73   -
74   - const scrollNext = React.useCallback(() => {
75   - api?.scrollNext();
76   - }, [api]);
77   -
78   - const handleKeyDown = React.useCallback(
79   - (event: React.KeyboardEvent<HTMLDivElement>) => {
80   - if (event.key === "ArrowLeft") {
81   - event.preventDefault();
82   - scrollPrev();
83   - } else if (event.key === "ArrowRight") {
84   - event.preventDefault();
85   - scrollNext();
86   - }
87   - },
88   - [scrollPrev, scrollNext],
89   - );
90   -
91   - React.useEffect(() => {
92   - if (!api || !setApi) return;
93   - setApi(api);
94   - }, [api, setApi]);
95   -
96   - React.useEffect(() => {
97   - if (!api) return;
98   - onSelect(api);
99   - api.on("reInit", onSelect);
100   - api.on("select", onSelect);
101   -
102   - return () => {
103   - api?.off("select", onSelect);
104   - };
105   - }, [api, onSelect]);
106   -
107   - return (
108   - <CarouselContext.Provider
109   - value={{
110   - carouselRef,
111   - api: api,
112   - opts,
113   - orientation:
114   - orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
115   - scrollPrev,
116   - scrollNext,
117   - canScrollPrev,
118   - canScrollNext,
119   - }}
120   - >
121   - <div
122   - onKeyDownCapture={handleKeyDown}
123   - className={cn("relative", className)}
124   - role="region"
125   - aria-roledescription="carousel"
126   - data-slot="carousel"
127   - {...props}
128   - >
129   - {children}
130   - </div>
131   - </CarouselContext.Provider>
132   - );
133   -}
134   -
135   -function CarouselContent({ className, ...props }: React.ComponentProps<"div">) {
136   - const { carouselRef, orientation } = useCarousel();
137   -
138   - return (
139   - <div
140   - ref={carouselRef}
141   - className="overflow-hidden"
142   - data-slot="carousel-content"
143   - >
144   - <div
145   - className={cn(
146   - "flex",
147   - orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col",
148   - className,
149   - )}
150   - {...props}
151   - />
152   - </div>
153   - );
154   -}
155   -
156   -function CarouselItem({ className, ...props }: React.ComponentProps<"div">) {
157   - const { orientation } = useCarousel();
158   -
159   - return (
160   - <div
161   - role="group"
162   - aria-roledescription="slide"
163   - data-slot="carousel-item"
164   - className={cn(
165   - "min-w-0 shrink-0 grow-0 basis-full",
166   - orientation === "horizontal" ? "pl-4" : "pt-4",
167   - className,
168   - )}
169   - {...props}
170   - />
171   - );
172   -}
173   -
174   -function CarouselPrevious({
175   - className,
176   - variant = "outline",
177   - size = "icon",
178   - ...props
179   -}: React.ComponentProps<typeof Button>) {
180   - const { orientation, scrollPrev, canScrollPrev } = useCarousel();
181   -
182   - return (
183   - <Button
184   - data-slot="carousel-previous"
185   - variant={variant}
186   - size={size}
187   - className={cn(
188   - "absolute size-8 rounded-full",
189   - orientation === "horizontal"
190   - ? "top-1/2 -left-12 -translate-y-1/2"
191   - : "-top-12 left-1/2 -translate-x-1/2 rotate-90",
192   - className,
193   - )}
194   - disabled={!canScrollPrev}
195   - onClick={scrollPrev}
196   - {...props}
197   - >
198   - <ArrowLeft />
199   - <span className="sr-only">Previous slide</span>
200   - </Button>
201   - );
202   -}
203   -
204   -function CarouselNext({
205   - className,
206   - variant = "outline",
207   - size = "icon",
208   - ...props
209   -}: React.ComponentProps<typeof Button>) {
210   - const { orientation, scrollNext, canScrollNext } = useCarousel();
211   -
212   - return (
213   - <Button
214   - data-slot="carousel-next"
215   - variant={variant}
216   - size={size}
217   - className={cn(
218   - "absolute size-8 rounded-full",
219   - orientation === "horizontal"
220   - ? "top-1/2 -right-12 -translate-y-1/2"
221   - : "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
222   - className,
223   - )}
224   - disabled={!canScrollNext}
225   - onClick={scrollNext}
226   - {...props}
227   - >
228   - <ArrowRight />
229   - <span className="sr-only">Next slide</span>
230   - </Button>
231   - );
232   -}
233   -
234   -export {
235   - type CarouselApi,
236   - Carousel,
237   - CarouselContent,
238   - CarouselItem,
239   - CarouselPrevious,
240   - CarouselNext,
241   -};
美国版/Food Labeling Management App React/src/app/components/ui/chart.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import * as RechartsPrimitive from "recharts";
5   -
6   -import { cn } from "./utils";
7   -
8   -// Format: { THEME_NAME: CSS_SELECTOR }
9   -const THEMES = { light: "", dark: ".dark" } as const;
10   -
11   -export type ChartConfig = {
12   - [k in string]: {
13   - label?: React.ReactNode;
14   - icon?: React.ComponentType;
15   - } & (
16   - | { color?: string; theme?: never }
17   - | { color?: never; theme: Record<keyof typeof THEMES, string> }
18   - );
19   -};
20   -
21   -type ChartContextProps = {
22   - config: ChartConfig;
23   -};
24   -
25   -const ChartContext = React.createContext<ChartContextProps | null>(null);
26   -
27   -function useChart() {
28   - const context = React.useContext(ChartContext);
29   -
30   - if (!context) {
31   - throw new Error("useChart must be used within a <ChartContainer />");
32   - }
33   -
34   - return context;
35   -}
36   -
37   -function ChartContainer({
38   - id,
39   - className,
40   - children,
41   - config,
42   - ...props
43   -}: React.ComponentProps<"div"> & {
44   - config: ChartConfig;
45   - children: React.ComponentProps<
46   - typeof RechartsPrimitive.ResponsiveContainer
47   - >["children"];
48   -}) {
49   - const uniqueId = React.useId();
50   - const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`;
51   -
52   - return (
53   - <ChartContext.Provider value={{ config }}>
54   - <div
55   - data-slot="chart"
56   - data-chart={chartId}
57   - className={cn(
58   - "[&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border flex aspect-video justify-center text-xs [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-hidden [&_.recharts-sector]:outline-hidden [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-surface]:outline-hidden",
59   - className,
60   - )}
61   - {...props}
62   - >
63   - <ChartStyle id={chartId} config={config} />
64   - <RechartsPrimitive.ResponsiveContainer>
65   - {children}
66   - </RechartsPrimitive.ResponsiveContainer>
67   - </div>
68   - </ChartContext.Provider>
69   - );
70   -}
71   -
72   -const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
73   - const colorConfig = Object.entries(config).filter(
74   - ([, config]) => config.theme || config.color,
75   - );
76   -
77   - if (!colorConfig.length) {
78   - return null;
79   - }
80   -
81   - return (
82   - <style
83   - dangerouslySetInnerHTML={{
84   - __html: Object.entries(THEMES)
85   - .map(
86   - ([theme, prefix]) => `
87   -${prefix} [data-chart=${id}] {
88   -${colorConfig
89   - .map(([key, itemConfig]) => {
90   - const color =
91   - itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||
92   - itemConfig.color;
93   - return color ? ` --color-${key}: ${color};` : null;
94   - })
95   - .join("\n")}
96   -}
97   -`,
98   - )
99   - .join("\n"),
100   - }}
101   - />
102   - );
103   -};
104   -
105   -const ChartTooltip = RechartsPrimitive.Tooltip;
106   -
107   -function ChartTooltipContent({
108   - active,
109   - payload,
110   - className,
111   - indicator = "dot",
112   - hideLabel = false,
113   - hideIndicator = false,
114   - label,
115   - labelFormatter,
116   - labelClassName,
117   - formatter,
118   - color,
119   - nameKey,
120   - labelKey,
121   -}: React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
122   - React.ComponentProps<"div"> & {
123   - hideLabel?: boolean;
124   - hideIndicator?: boolean;
125   - indicator?: "line" | "dot" | "dashed";
126   - nameKey?: string;
127   - labelKey?: string;
128   - }) {
129   - const { config } = useChart();
130   -
131   - const tooltipLabel = React.useMemo(() => {
132   - if (hideLabel || !payload?.length) {
133   - return null;
134   - }
135   -
136   - const [item] = payload;
137   - const key = `${labelKey || item?.dataKey || item?.name || "value"}`;
138   - const itemConfig = getPayloadConfigFromPayload(config, item, key);
139   - const value =
140   - !labelKey && typeof label === "string"
141   - ? config[label as keyof typeof config]?.label || label
142   - : itemConfig?.label;
143   -
144   - if (labelFormatter) {
145   - return (
146   - <div className={cn("font-medium", labelClassName)}>
147   - {labelFormatter(value, payload)}
148   - </div>
149   - );
150   - }
151   -
152   - if (!value) {
153   - return null;
154   - }
155   -
156   - return <div className={cn("font-medium", labelClassName)}>{value}</div>;
157   - }, [
158   - label,
159   - labelFormatter,
160   - payload,
161   - hideLabel,
162   - labelClassName,
163   - config,
164   - labelKey,
165   - ]);
166   -
167   - if (!active || !payload?.length) {
168   - return null;
169   - }
170   -
171   - const nestLabel = payload.length === 1 && indicator !== "dot";
172   -
173   - return (
174   - <div
175   - className={cn(
176   - "border-border/50 bg-background grid min-w-[8rem] items-start gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs shadow-xl",
177   - className,
178   - )}
179   - >
180   - {!nestLabel ? tooltipLabel : null}
181   - <div className="grid gap-1.5">
182   - {payload.map((item, index) => {
183   - const key = `${nameKey || item.name || item.dataKey || "value"}`;
184   - const itemConfig = getPayloadConfigFromPayload(config, item, key);
185   - const indicatorColor = color || item.payload.fill || item.color;
186   -
187   - return (
188   - <div
189   - key={item.dataKey}
190   - className={cn(
191   - "[&>svg]:text-muted-foreground flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5",
192   - indicator === "dot" && "items-center",
193   - )}
194   - >
195   - {formatter && item?.value !== undefined && item.name ? (
196   - formatter(item.value, item.name, item, index, item.payload)
197   - ) : (
198   - <>
199   - {itemConfig?.icon ? (
200   - <itemConfig.icon />
201   - ) : (
202   - !hideIndicator && (
203   - <div
204   - className={cn(
205   - "shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)",
206   - {
207   - "h-2.5 w-2.5": indicator === "dot",
208   - "w-1": indicator === "line",
209   - "w-0 border-[1.5px] border-dashed bg-transparent":
210   - indicator === "dashed",
211   - "my-0.5": nestLabel && indicator === "dashed",
212   - },
213   - )}
214   - style={
215   - {
216   - "--color-bg": indicatorColor,
217   - "--color-border": indicatorColor,
218   - } as React.CSSProperties
219   - }
220   - />
221   - )
222   - )}
223   - <div
224   - className={cn(
225   - "flex flex-1 justify-between leading-none",
226   - nestLabel ? "items-end" : "items-center",
227   - )}
228   - >
229   - <div className="grid gap-1.5">
230   - {nestLabel ? tooltipLabel : null}
231   - <span className="text-muted-foreground">
232   - {itemConfig?.label || item.name}
233   - </span>
234   - </div>
235   - {item.value && (
236   - <span className="text-foreground font-mono font-medium tabular-nums">
237   - {item.value.toLocaleString()}
238   - </span>
239   - )}
240   - </div>
241   - </>
242   - )}
243   - </div>
244   - );
245   - })}
246   - </div>
247   - </div>
248   - );
249   -}
250   -
251   -const ChartLegend = RechartsPrimitive.Legend;
252   -
253   -function ChartLegendContent({
254   - className,
255   - hideIcon = false,
256   - payload,
257   - verticalAlign = "bottom",
258   - nameKey,
259   -}: React.ComponentProps<"div"> &
260   - Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
261   - hideIcon?: boolean;
262   - nameKey?: string;
263   - }) {
264   - const { config } = useChart();
265   -
266   - if (!payload?.length) {
267   - return null;
268   - }
269   -
270   - return (
271   - <div
272   - className={cn(
273   - "flex items-center justify-center gap-4",
274   - verticalAlign === "top" ? "pb-3" : "pt-3",
275   - className,
276   - )}
277   - >
278   - {payload.map((item) => {
279   - const key = `${nameKey || item.dataKey || "value"}`;
280   - const itemConfig = getPayloadConfigFromPayload(config, item, key);
281   -
282   - return (
283   - <div
284   - key={item.value}
285   - className={cn(
286   - "[&>svg]:text-muted-foreground flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3",
287   - )}
288   - >
289   - {itemConfig?.icon && !hideIcon ? (
290   - <itemConfig.icon />
291   - ) : (
292   - <div
293   - className="h-2 w-2 shrink-0 rounded-[2px]"
294   - style={{
295   - backgroundColor: item.color,
296   - }}
297   - />
298   - )}
299   - {itemConfig?.label}
300   - </div>
301   - );
302   - })}
303   - </div>
304   - );
305   -}
306   -
307   -// Helper to extract item config from a payload.
308   -function getPayloadConfigFromPayload(
309   - config: ChartConfig,
310   - payload: unknown,
311   - key: string,
312   -) {
313   - if (typeof payload !== "object" || payload === null) {
314   - return undefined;
315   - }
316   -
317   - const payloadPayload =
318   - "payload" in payload &&
319   - typeof payload.payload === "object" &&
320   - payload.payload !== null
321   - ? payload.payload
322   - : undefined;
323   -
324   - let configLabelKey: string = key;
325   -
326   - if (
327   - key in payload &&
328   - typeof payload[key as keyof typeof payload] === "string"
329   - ) {
330   - configLabelKey = payload[key as keyof typeof payload] as string;
331   - } else if (
332   - payloadPayload &&
333   - key in payloadPayload &&
334   - typeof payloadPayload[key as keyof typeof payloadPayload] === "string"
335   - ) {
336   - configLabelKey = payloadPayload[
337   - key as keyof typeof payloadPayload
338   - ] as string;
339   - }
340   -
341   - return configLabelKey in config
342   - ? config[configLabelKey]
343   - : config[key as keyof typeof config];
344   -}
345   -
346   -export {
347   - ChartContainer,
348   - ChartTooltip,
349   - ChartTooltipContent,
350   - ChartLegend,
351   - ChartLegendContent,
352   - ChartStyle,
353   -};
美国版/Food Labeling Management App React/src/app/components/ui/checkbox.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
5   -import { CheckIcon } from "lucide-react";
6   -
7   -import { cn } from "./utils";
8   -
9   -function Checkbox({
10   - className,
11   - ...props
12   -}: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
13   - return (
14   - <CheckboxPrimitive.Root
15   - data-slot="checkbox"
16   - className={cn(
17   - "peer border bg-input-background dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
18   - className,
19   - )}
20   - {...props}
21   - >
22   - <CheckboxPrimitive.Indicator
23   - data-slot="checkbox-indicator"
24   - className="flex items-center justify-center text-current transition-none"
25   - >
26   - <CheckIcon className="size-3.5" />
27   - </CheckboxPrimitive.Indicator>
28   - </CheckboxPrimitive.Root>
29   - );
30   -}
31   -
32   -export { Checkbox };
美国版/Food Labeling Management App React/src/app/components/ui/collapsible.tsx deleted
1   -"use client";
2   -
3   -import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
4   -
5   -function Collapsible({
6   - ...props
7   -}: React.ComponentProps<typeof CollapsiblePrimitive.Root>) {
8   - return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} />;
9   -}
10   -
11   -function CollapsibleTrigger({
12   - ...props
13   -}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>) {
14   - return (
15   - <CollapsiblePrimitive.CollapsibleTrigger
16   - data-slot="collapsible-trigger"
17   - {...props}
18   - />
19   - );
20   -}
21   -
22   -function CollapsibleContent({
23   - ...props
24   -}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>) {
25   - return (
26   - <CollapsiblePrimitive.CollapsibleContent
27   - data-slot="collapsible-content"
28   - {...props}
29   - />
30   - );
31   -}
32   -
33   -export { Collapsible, CollapsibleTrigger, CollapsibleContent };
美国版/Food Labeling Management App React/src/app/components/ui/command.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import { Command as CommandPrimitive } from "cmdk";
5   -import { SearchIcon } from "lucide-react";
6   -
7   -import { cn } from "./utils";
8   -import {
9   - Dialog,
10   - DialogContent,
11   - DialogDescription,
12   - DialogHeader,
13   - DialogTitle,
14   -} from "./dialog";
15   -
16   -function Command({
17   - className,
18   - ...props
19   -}: React.ComponentProps<typeof CommandPrimitive>) {
20   - return (
21   - <CommandPrimitive
22   - data-slot="command"
23   - className={cn(
24   - "bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md",
25   - className,
26   - )}
27   - {...props}
28   - />
29   - );
30   -}
31   -
32   -function CommandDialog({
33   - title = "Command Palette",
34   - description = "Search for a command to run...",
35   - children,
36   - ...props
37   -}: React.ComponentProps<typeof Dialog> & {
38   - title?: string;
39   - description?: string;
40   -}) {
41   - return (
42   - <Dialog {...props}>
43   - <DialogHeader className="sr-only">
44   - <DialogTitle>{title}</DialogTitle>
45   - <DialogDescription>{description}</DialogDescription>
46   - </DialogHeader>
47   - <DialogContent className="overflow-hidden p-0">
48   - <Command className="[&_[cmdk-group-heading]]:text-muted-foreground **:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
49   - {children}
50   - </Command>
51   - </DialogContent>
52   - </Dialog>
53   - );
54   -}
55   -
56   -function CommandInput({
57   - className,
58   - ...props
59   -}: React.ComponentProps<typeof CommandPrimitive.Input>) {
60   - return (
61   - <div
62   - data-slot="command-input-wrapper"
63   - className="flex h-9 items-center gap-2 border-b px-3"
64   - >
65   - <SearchIcon className="size-4 shrink-0 opacity-50" />
66   - <CommandPrimitive.Input
67   - data-slot="command-input"
68   - className={cn(
69   - "placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50",
70   - className,
71   - )}
72   - {...props}
73   - />
74   - </div>
75   - );
76   -}
77   -
78   -function CommandList({
79   - className,
80   - ...props
81   -}: React.ComponentProps<typeof CommandPrimitive.List>) {
82   - return (
83   - <CommandPrimitive.List
84   - data-slot="command-list"
85   - className={cn(
86   - "max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto",
87   - className,
88   - )}
89   - {...props}
90   - />
91   - );
92   -}
93   -
94   -function CommandEmpty({
95   - ...props
96   -}: React.ComponentProps<typeof CommandPrimitive.Empty>) {
97   - return (
98   - <CommandPrimitive.Empty
99   - data-slot="command-empty"
100   - className="py-6 text-center text-sm"
101   - {...props}
102   - />
103   - );
104   -}
105   -
106   -function CommandGroup({
107   - className,
108   - ...props
109   -}: React.ComponentProps<typeof CommandPrimitive.Group>) {
110   - return (
111   - <CommandPrimitive.Group
112   - data-slot="command-group"
113   - className={cn(
114   - "text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium",
115   - className,
116   - )}
117   - {...props}
118   - />
119   - );
120   -}
121   -
122   -function CommandSeparator({
123   - className,
124   - ...props
125   -}: React.ComponentProps<typeof CommandPrimitive.Separator>) {
126   - return (
127   - <CommandPrimitive.Separator
128   - data-slot="command-separator"
129   - className={cn("bg-border -mx-1 h-px", className)}
130   - {...props}
131   - />
132   - );
133   -}
134   -
135   -function CommandItem({
136   - className,
137   - ...props
138   -}: React.ComponentProps<typeof CommandPrimitive.Item>) {
139   - return (
140   - <CommandPrimitive.Item
141   - data-slot="command-item"
142   - className={cn(
143   - "data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
144   - className,
145   - )}
146   - {...props}
147   - />
148   - );
149   -}
150   -
151   -function CommandShortcut({
152   - className,
153   - ...props
154   -}: React.ComponentProps<"span">) {
155   - return (
156   - <span
157   - data-slot="command-shortcut"
158   - className={cn(
159   - "text-muted-foreground ml-auto text-xs tracking-widest",
160   - className,
161   - )}
162   - {...props}
163   - />
164   - );
165   -}
166   -
167   -export {
168   - Command,
169   - CommandDialog,
170   - CommandInput,
171   - CommandList,
172   - CommandEmpty,
173   - CommandGroup,
174   - CommandItem,
175   - CommandShortcut,
176   - CommandSeparator,
177   -};
美国版/Food Labeling Management App React/src/app/components/ui/context-menu.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import * as ContextMenuPrimitive from "@radix-ui/react-context-menu";
5   -import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
6   -
7   -import { cn } from "./utils";
8   -
9   -function ContextMenu({
10   - ...props
11   -}: React.ComponentProps<typeof ContextMenuPrimitive.Root>) {
12   - return <ContextMenuPrimitive.Root data-slot="context-menu" {...props} />;
13   -}
14   -
15   -function ContextMenuTrigger({
16   - ...props
17   -}: React.ComponentProps<typeof ContextMenuPrimitive.Trigger>) {
18   - return (
19   - <ContextMenuPrimitive.Trigger data-slot="context-menu-trigger" {...props} />
20   - );
21   -}
22   -
23   -function ContextMenuGroup({
24   - ...props
25   -}: React.ComponentProps<typeof ContextMenuPrimitive.Group>) {
26   - return (
27   - <ContextMenuPrimitive.Group data-slot="context-menu-group" {...props} />
28   - );
29   -}
30   -
31   -function ContextMenuPortal({
32   - ...props
33   -}: React.ComponentProps<typeof ContextMenuPrimitive.Portal>) {
34   - return (
35   - <ContextMenuPrimitive.Portal data-slot="context-menu-portal" {...props} />
36   - );
37   -}
38   -
39   -function ContextMenuSub({
40   - ...props
41   -}: React.ComponentProps<typeof ContextMenuPrimitive.Sub>) {
42   - return <ContextMenuPrimitive.Sub data-slot="context-menu-sub" {...props} />;
43   -}
44   -
45   -function ContextMenuRadioGroup({
46   - ...props
47   -}: React.ComponentProps<typeof ContextMenuPrimitive.RadioGroup>) {
48   - return (
49   - <ContextMenuPrimitive.RadioGroup
50   - data-slot="context-menu-radio-group"
51   - {...props}
52   - />
53   - );
54   -}
55   -
56   -function ContextMenuSubTrigger({
57   - className,
58   - inset,
59   - children,
60   - ...props
61   -}: React.ComponentProps<typeof ContextMenuPrimitive.SubTrigger> & {
62   - inset?: boolean;
63   -}) {
64   - return (
65   - <ContextMenuPrimitive.SubTrigger
66   - data-slot="context-menu-sub-trigger"
67   - data-inset={inset}
68   - className={cn(
69   - "focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
70   - className,
71   - )}
72   - {...props}
73   - >
74   - {children}
75   - <ChevronRightIcon className="ml-auto" />
76   - </ContextMenuPrimitive.SubTrigger>
77   - );
78   -}
79   -
80   -function ContextMenuSubContent({
81   - className,
82   - ...props
83   -}: React.ComponentProps<typeof ContextMenuPrimitive.SubContent>) {
84   - return (
85   - <ContextMenuPrimitive.SubContent
86   - data-slot="context-menu-sub-content"
87   - className={cn(
88   - "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-context-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg",
89   - className,
90   - )}
91   - {...props}
92   - />
93   - );
94   -}
95   -
96   -function ContextMenuContent({
97   - className,
98   - ...props
99   -}: React.ComponentProps<typeof ContextMenuPrimitive.Content>) {
100   - return (
101   - <ContextMenuPrimitive.Portal>
102   - <ContextMenuPrimitive.Content
103   - data-slot="context-menu-content"
104   - className={cn(
105   - "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-context-menu-content-available-height) min-w-[8rem] origin-(--radix-context-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",
106   - className,
107   - )}
108   - {...props}
109   - />
110   - </ContextMenuPrimitive.Portal>
111   - );
112   -}
113   -
114   -function ContextMenuItem({
115   - className,
116   - inset,
117   - variant = "default",
118   - ...props
119   -}: React.ComponentProps<typeof ContextMenuPrimitive.Item> & {
120   - inset?: boolean;
121   - variant?: "default" | "destructive";
122   -}) {
123   - return (
124   - <ContextMenuPrimitive.Item
125   - data-slot="context-menu-item"
126   - data-inset={inset}
127   - data-variant={variant}
128   - className={cn(
129   - "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
130   - className,
131   - )}
132   - {...props}
133   - />
134   - );
135   -}
136   -
137   -function ContextMenuCheckboxItem({
138   - className,
139   - children,
140   - checked,
141   - ...props
142   -}: React.ComponentProps<typeof ContextMenuPrimitive.CheckboxItem>) {
143   - return (
144   - <ContextMenuPrimitive.CheckboxItem
145   - data-slot="context-menu-checkbox-item"
146   - className={cn(
147   - "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
148   - className,
149   - )}
150   - checked={checked}
151   - {...props}
152   - >
153   - <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
154   - <ContextMenuPrimitive.ItemIndicator>
155   - <CheckIcon className="size-4" />
156   - </ContextMenuPrimitive.ItemIndicator>
157   - </span>
158   - {children}
159   - </ContextMenuPrimitive.CheckboxItem>
160   - );
161   -}
162   -
163   -function ContextMenuRadioItem({
164   - className,
165   - children,
166   - ...props
167   -}: React.ComponentProps<typeof ContextMenuPrimitive.RadioItem>) {
168   - return (
169   - <ContextMenuPrimitive.RadioItem
170   - data-slot="context-menu-radio-item"
171   - className={cn(
172   - "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
173   - className,
174   - )}
175   - {...props}
176   - >
177   - <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
178   - <ContextMenuPrimitive.ItemIndicator>
179   - <CircleIcon className="size-2 fill-current" />
180   - </ContextMenuPrimitive.ItemIndicator>
181   - </span>
182   - {children}
183   - </ContextMenuPrimitive.RadioItem>
184   - );
185   -}
186   -
187   -function ContextMenuLabel({
188   - className,
189   - inset,
190   - ...props
191   -}: React.ComponentProps<typeof ContextMenuPrimitive.Label> & {
192   - inset?: boolean;
193   -}) {
194   - return (
195   - <ContextMenuPrimitive.Label
196   - data-slot="context-menu-label"
197   - data-inset={inset}
198   - className={cn(
199   - "text-foreground px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
200   - className,
201   - )}
202   - {...props}
203   - />
204   - );
205   -}
206   -
207   -function ContextMenuSeparator({
208   - className,
209   - ...props
210   -}: React.ComponentProps<typeof ContextMenuPrimitive.Separator>) {
211   - return (
212   - <ContextMenuPrimitive.Separator
213   - data-slot="context-menu-separator"
214   - className={cn("bg-border -mx-1 my-1 h-px", className)}
215   - {...props}
216   - />
217   - );
218   -}
219   -
220   -function ContextMenuShortcut({
221   - className,
222   - ...props
223   -}: React.ComponentProps<"span">) {
224   - return (
225   - <span
226   - data-slot="context-menu-shortcut"
227   - className={cn(
228   - "text-muted-foreground ml-auto text-xs tracking-widest",
229   - className,
230   - )}
231   - {...props}
232   - />
233   - );
234   -}
235   -
236   -export {
237   - ContextMenu,
238   - ContextMenuTrigger,
239   - ContextMenuContent,
240   - ContextMenuItem,
241   - ContextMenuCheckboxItem,
242   - ContextMenuRadioItem,
243   - ContextMenuLabel,
244   - ContextMenuSeparator,
245   - ContextMenuShortcut,
246   - ContextMenuGroup,
247   - ContextMenuPortal,
248   - ContextMenuSub,
249   - ContextMenuSubContent,
250   - ContextMenuSubTrigger,
251   - ContextMenuRadioGroup,
252   -};
美国版/Food Labeling Management App React/src/app/components/ui/dialog.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import * as DialogPrimitive from "@radix-ui/react-dialog";
5   -import { XIcon } from "lucide-react";
6   -
7   -import { cn } from "./utils";
8   -
9   -function Dialog({
10   - ...props
11   -}: React.ComponentProps<typeof DialogPrimitive.Root>) {
12   - return <DialogPrimitive.Root data-slot="dialog" {...props} />;
13   -}
14   -
15   -function DialogTrigger({
16   - ...props
17   -}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
18   - return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
19   -}
20   -
21   -function DialogPortal({
22   - ...props
23   -}: React.ComponentProps<typeof DialogPrimitive.Portal>) {
24   - return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
25   -}
26   -
27   -function DialogClose({
28   - ...props
29   -}: React.ComponentProps<typeof DialogPrimitive.Close>) {
30   - return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
31   -}
32   -
33   -function DialogOverlay({
34   - className,
35   - ...props
36   -}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
37   - return (
38   - <DialogPrimitive.Overlay
39   - data-slot="dialog-overlay"
40   - className={cn(
41   - "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
42   - className,
43   - )}
44   - {...props}
45   - />
46   - );
47   -}
48   -
49   -function DialogContent({
50   - className,
51   - children,
52   - ...props
53   -}: React.ComponentProps<typeof DialogPrimitive.Content>) {
54   - return (
55   - <DialogPortal data-slot="dialog-portal">
56   - <DialogOverlay />
57   - <DialogPrimitive.Content
58   - data-slot="dialog-content"
59   - className={cn(
60   - "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
61   - className,
62   - )}
63   - {...props}
64   - >
65   - {children}
66   - <DialogPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4">
67   - <XIcon />
68   - <span className="sr-only">Close</span>
69   - </DialogPrimitive.Close>
70   - </DialogPrimitive.Content>
71   - </DialogPortal>
72   - );
73   -}
74   -
75   -function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
76   - return (
77   - <div
78   - data-slot="dialog-header"
79   - className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
80   - {...props}
81   - />
82   - );
83   -}
84   -
85   -function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
86   - return (
87   - <div
88   - data-slot="dialog-footer"
89   - className={cn(
90   - "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
91   - className,
92   - )}
93   - {...props}
94   - />
95   - );
96   -}
97   -
98   -function DialogTitle({
99   - className,
100   - ...props
101   -}: React.ComponentProps<typeof DialogPrimitive.Title>) {
102   - return (
103   - <DialogPrimitive.Title
104   - data-slot="dialog-title"
105   - className={cn("text-lg leading-none font-semibold", className)}
106   - {...props}
107   - />
108   - );
109   -}
110   -
111   -function DialogDescription({
112   - className,
113   - ...props
114   -}: React.ComponentProps<typeof DialogPrimitive.Description>) {
115   - return (
116   - <DialogPrimitive.Description
117   - data-slot="dialog-description"
118   - className={cn("text-muted-foreground text-sm", className)}
119   - {...props}
120   - />
121   - );
122   -}
123   -
124   -export {
125   - Dialog,
126   - DialogClose,
127   - DialogContent,
128   - DialogDescription,
129   - DialogFooter,
130   - DialogHeader,
131   - DialogOverlay,
132   - DialogPortal,
133   - DialogTitle,
134   - DialogTrigger,
135   -};
美国版/Food Labeling Management App React/src/app/components/ui/drawer.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import { Drawer as DrawerPrimitive } from "vaul";
5   -
6   -import { cn } from "./utils";
7   -
8   -function Drawer({
9   - ...props
10   -}: React.ComponentProps<typeof DrawerPrimitive.Root>) {
11   - return <DrawerPrimitive.Root data-slot="drawer" {...props} />;
12   -}
13   -
14   -function DrawerTrigger({
15   - ...props
16   -}: React.ComponentProps<typeof DrawerPrimitive.Trigger>) {
17   - return <DrawerPrimitive.Trigger data-slot="drawer-trigger" {...props} />;
18   -}
19   -
20   -function DrawerPortal({
21   - ...props
22   -}: React.ComponentProps<typeof DrawerPrimitive.Portal>) {
23   - return <DrawerPrimitive.Portal data-slot="drawer-portal" {...props} />;
24   -}
25   -
26   -function DrawerClose({
27   - ...props
28   -}: React.ComponentProps<typeof DrawerPrimitive.Close>) {
29   - return <DrawerPrimitive.Close data-slot="drawer-close" {...props} />;
30   -}
31   -
32   -function DrawerOverlay({
33   - className,
34   - ...props
35   -}: React.ComponentProps<typeof DrawerPrimitive.Overlay>) {
36   - return (
37   - <DrawerPrimitive.Overlay
38   - data-slot="drawer-overlay"
39   - className={cn(
40   - "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
41   - className,
42   - )}
43   - {...props}
44   - />
45   - );
46   -}
47   -
48   -function DrawerContent({
49   - className,
50   - children,
51   - ...props
52   -}: React.ComponentProps<typeof DrawerPrimitive.Content>) {
53   - return (
54   - <DrawerPortal data-slot="drawer-portal">
55   - <DrawerOverlay />
56   - <DrawerPrimitive.Content
57   - data-slot="drawer-content"
58   - className={cn(
59   - "group/drawer-content bg-background fixed z-50 flex h-auto flex-col",
60   - "data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=top]:rounded-b-lg data-[vaul-drawer-direction=top]:border-b",
61   - "data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=bottom]:rounded-t-lg data-[vaul-drawer-direction=bottom]:border-t",
62   - "data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=right]:border-l data-[vaul-drawer-direction=right]:sm:max-w-sm",
63   - "data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=left]:border-r data-[vaul-drawer-direction=left]:sm:max-w-sm",
64   - className,
65   - )}
66   - {...props}
67   - >
68   - <div className="bg-muted mx-auto mt-4 hidden h-2 w-[100px] shrink-0 rounded-full group-data-[vaul-drawer-direction=bottom]/drawer-content:block" />
69   - {children}
70   - </DrawerPrimitive.Content>
71   - </DrawerPortal>
72   - );
73   -}
74   -
75   -function DrawerHeader({ className, ...props }: React.ComponentProps<"div">) {
76   - return (
77   - <div
78   - data-slot="drawer-header"
79   - className={cn("flex flex-col gap-1.5 p-4", className)}
80   - {...props}
81   - />
82   - );
83   -}
84   -
85   -function DrawerFooter({ className, ...props }: React.ComponentProps<"div">) {
86   - return (
87   - <div
88   - data-slot="drawer-footer"
89   - className={cn("mt-auto flex flex-col gap-2 p-4", className)}
90   - {...props}
91   - />
92   - );
93   -}
94   -
95   -function DrawerTitle({
96   - className,
97   - ...props
98   -}: React.ComponentProps<typeof DrawerPrimitive.Title>) {
99   - return (
100   - <DrawerPrimitive.Title
101   - data-slot="drawer-title"
102   - className={cn("text-foreground font-semibold", className)}
103   - {...props}
104   - />
105   - );
106   -}
107   -
108   -function DrawerDescription({
109   - className,
110   - ...props
111   -}: React.ComponentProps<typeof DrawerPrimitive.Description>) {
112   - return (
113   - <DrawerPrimitive.Description
114   - data-slot="drawer-description"
115   - className={cn("text-muted-foreground text-sm", className)}
116   - {...props}
117   - />
118   - );
119   -}
120   -
121   -export {
122   - Drawer,
123   - DrawerPortal,
124   - DrawerOverlay,
125   - DrawerTrigger,
126   - DrawerClose,
127   - DrawerContent,
128   - DrawerHeader,
129   - DrawerFooter,
130   - DrawerTitle,
131   - DrawerDescription,
132   -};
美国版/Food Labeling Management App React/src/app/components/ui/dropdown-menu.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
5   -import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
6   -
7   -import { cn } from "./utils";
8   -
9   -function DropdownMenu({
10   - ...props
11   -}: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
12   - return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />;
13   -}
14   -
15   -function DropdownMenuPortal({
16   - ...props
17   -}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
18   - return (
19   - <DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
20   - );
21   -}
22   -
23   -function DropdownMenuTrigger({
24   - ...props
25   -}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
26   - return (
27   - <DropdownMenuPrimitive.Trigger
28   - data-slot="dropdown-menu-trigger"
29   - {...props}
30   - />
31   - );
32   -}
33   -
34   -function DropdownMenuContent({
35   - className,
36   - sideOffset = 4,
37   - ...props
38   -}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
39   - return (
40   - <DropdownMenuPrimitive.Portal>
41   - <DropdownMenuPrimitive.Content
42   - data-slot="dropdown-menu-content"
43   - sideOffset={sideOffset}
44   - className={cn(
45   - "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",
46   - className,
47   - )}
48   - {...props}
49   - />
50   - </DropdownMenuPrimitive.Portal>
51   - );
52   -}
53   -
54   -function DropdownMenuGroup({
55   - ...props
56   -}: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
57   - return (
58   - <DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
59   - );
60   -}
61   -
62   -function DropdownMenuItem({
63   - className,
64   - inset,
65   - variant = "default",
66   - ...props
67   -}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
68   - inset?: boolean;
69   - variant?: "default" | "destructive";
70   -}) {
71   - return (
72   - <DropdownMenuPrimitive.Item
73   - data-slot="dropdown-menu-item"
74   - data-inset={inset}
75   - data-variant={variant}
76   - className={cn(
77   - "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
78   - className,
79   - )}
80   - {...props}
81   - />
82   - );
83   -}
84   -
85   -function DropdownMenuCheckboxItem({
86   - className,
87   - children,
88   - checked,
89   - ...props
90   -}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {
91   - return (
92   - <DropdownMenuPrimitive.CheckboxItem
93   - data-slot="dropdown-menu-checkbox-item"
94   - className={cn(
95   - "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
96   - className,
97   - )}
98   - checked={checked}
99   - {...props}
100   - >
101   - <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
102   - <DropdownMenuPrimitive.ItemIndicator>
103   - <CheckIcon className="size-4" />
104   - </DropdownMenuPrimitive.ItemIndicator>
105   - </span>
106   - {children}
107   - </DropdownMenuPrimitive.CheckboxItem>
108   - );
109   -}
110   -
111   -function DropdownMenuRadioGroup({
112   - ...props
113   -}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
114   - return (
115   - <DropdownMenuPrimitive.RadioGroup
116   - data-slot="dropdown-menu-radio-group"
117   - {...props}
118   - />
119   - );
120   -}
121   -
122   -function DropdownMenuRadioItem({
123   - className,
124   - children,
125   - ...props
126   -}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
127   - return (
128   - <DropdownMenuPrimitive.RadioItem
129   - data-slot="dropdown-menu-radio-item"
130   - className={cn(
131   - "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
132   - className,
133   - )}
134   - {...props}
135   - >
136   - <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
137   - <DropdownMenuPrimitive.ItemIndicator>
138   - <CircleIcon className="size-2 fill-current" />
139   - </DropdownMenuPrimitive.ItemIndicator>
140   - </span>
141   - {children}
142   - </DropdownMenuPrimitive.RadioItem>
143   - );
144   -}
145   -
146   -function DropdownMenuLabel({
147   - className,
148   - inset,
149   - ...props
150   -}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
151   - inset?: boolean;
152   -}) {
153   - return (
154   - <DropdownMenuPrimitive.Label
155   - data-slot="dropdown-menu-label"
156   - data-inset={inset}
157   - className={cn(
158   - "px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
159   - className,
160   - )}
161   - {...props}
162   - />
163   - );
164   -}
165   -
166   -function DropdownMenuSeparator({
167   - className,
168   - ...props
169   -}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
170   - return (
171   - <DropdownMenuPrimitive.Separator
172   - data-slot="dropdown-menu-separator"
173   - className={cn("bg-border -mx-1 my-1 h-px", className)}
174   - {...props}
175   - />
176   - );
177   -}
178   -
179   -function DropdownMenuShortcut({
180   - className,
181   - ...props
182   -}: React.ComponentProps<"span">) {
183   - return (
184   - <span
185   - data-slot="dropdown-menu-shortcut"
186   - className={cn(
187   - "text-muted-foreground ml-auto text-xs tracking-widest",
188   - className,
189   - )}
190   - {...props}
191   - />
192   - );
193   -}
194   -
195   -function DropdownMenuSub({
196   - ...props
197   -}: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
198   - return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />;
199   -}
200   -
201   -function DropdownMenuSubTrigger({
202   - className,
203   - inset,
204   - children,
205   - ...props
206   -}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
207   - inset?: boolean;
208   -}) {
209   - return (
210   - <DropdownMenuPrimitive.SubTrigger
211   - data-slot="dropdown-menu-sub-trigger"
212   - data-inset={inset}
213   - className={cn(
214   - "focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8",
215   - className,
216   - )}
217   - {...props}
218   - >
219   - {children}
220   - <ChevronRightIcon className="ml-auto size-4" />
221   - </DropdownMenuPrimitive.SubTrigger>
222   - );
223   -}
224   -
225   -function DropdownMenuSubContent({
226   - className,
227   - ...props
228   -}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
229   - return (
230   - <DropdownMenuPrimitive.SubContent
231   - data-slot="dropdown-menu-sub-content"
232   - className={cn(
233   - "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg",
234   - className,
235   - )}
236   - {...props}
237   - />
238   - );
239   -}
240   -
241   -export {
242   - DropdownMenu,
243   - DropdownMenuPortal,
244   - DropdownMenuTrigger,
245   - DropdownMenuContent,
246   - DropdownMenuGroup,
247   - DropdownMenuLabel,
248   - DropdownMenuItem,
249   - DropdownMenuCheckboxItem,
250   - DropdownMenuRadioGroup,
251   - DropdownMenuRadioItem,
252   - DropdownMenuSeparator,
253   - DropdownMenuShortcut,
254   - DropdownMenuSub,
255   - DropdownMenuSubTrigger,
256   - DropdownMenuSubContent,
257   -};
美国版/Food Labeling Management App React/src/app/components/ui/form.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import * as LabelPrimitive from "@radix-ui/react-label";
5   -import { Slot } from "@radix-ui/react-slot";
6   -import {
7   - Controller,
8   - FormProvider,
9   - useFormContext,
10   - useFormState,
11   - type ControllerProps,
12   - type FieldPath,
13   - type FieldValues,
14   -} from "react-hook-form";
15   -
16   -import { cn } from "./utils";
17   -import { Label } from "./label";
18   -
19   -const Form = FormProvider;
20   -
21   -type FormFieldContextValue<
22   - TFieldValues extends FieldValues = FieldValues,
23   - TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
24   -> = {
25   - name: TName;
26   -};
27   -
28   -const FormFieldContext = React.createContext<FormFieldContextValue>(
29   - {} as FormFieldContextValue,
30   -);
31   -
32   -const FormField = <
33   - TFieldValues extends FieldValues = FieldValues,
34   - TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
35   ->({
36   - ...props
37   -}: ControllerProps<TFieldValues, TName>) => {
38   - return (
39   - <FormFieldContext.Provider value={{ name: props.name }}>
40   - <Controller {...props} />
41   - </FormFieldContext.Provider>
42   - );
43   -};
44   -
45   -const useFormField = () => {
46   - const fieldContext = React.useContext(FormFieldContext);
47   - const itemContext = React.useContext(FormItemContext);
48   - const { getFieldState } = useFormContext();
49   - const formState = useFormState({ name: fieldContext.name });
50   - const fieldState = getFieldState(fieldContext.name, formState);
51   -
52   - if (!fieldContext) {
53   - throw new Error("useFormField should be used within <FormField>");
54   - }
55   -
56   - const { id } = itemContext;
57   -
58   - return {
59   - id,
60   - name: fieldContext.name,
61   - formItemId: `${id}-form-item`,
62   - formDescriptionId: `${id}-form-item-description`,
63   - formMessageId: `${id}-form-item-message`,
64   - ...fieldState,
65   - };
66   -};
67   -
68   -type FormItemContextValue = {
69   - id: string;
70   -};
71   -
72   -const FormItemContext = React.createContext<FormItemContextValue>(
73   - {} as FormItemContextValue,
74   -);
75   -
76   -function FormItem({ className, ...props }: React.ComponentProps<"div">) {
77   - const id = React.useId();
78   -
79   - return (
80   - <FormItemContext.Provider value={{ id }}>
81   - <div
82   - data-slot="form-item"
83   - className={cn("grid gap-2", className)}
84   - {...props}
85   - />
86   - </FormItemContext.Provider>
87   - );
88   -}
89   -
90   -function FormLabel({
91   - className,
92   - ...props
93   -}: React.ComponentProps<typeof LabelPrimitive.Root>) {
94   - const { error, formItemId } = useFormField();
95   -
96   - return (
97   - <Label
98   - data-slot="form-label"
99   - data-error={!!error}
100   - className={cn("data-[error=true]:text-destructive", className)}
101   - htmlFor={formItemId}
102   - {...props}
103   - />
104   - );
105   -}
106   -
107   -function FormControl({ ...props }: React.ComponentProps<typeof Slot>) {
108   - const { error, formItemId, formDescriptionId, formMessageId } =
109   - useFormField();
110   -
111   - return (
112   - <Slot
113   - data-slot="form-control"
114   - id={formItemId}
115   - aria-describedby={
116   - !error
117   - ? `${formDescriptionId}`
118   - : `${formDescriptionId} ${formMessageId}`
119   - }
120   - aria-invalid={!!error}
121   - {...props}
122   - />
123   - );
124   -}
125   -
126   -function FormDescription({ className, ...props }: React.ComponentProps<"p">) {
127   - const { formDescriptionId } = useFormField();
128   -
129   - return (
130   - <p
131   - data-slot="form-description"
132   - id={formDescriptionId}
133   - className={cn("text-muted-foreground text-sm", className)}
134   - {...props}
135   - />
136   - );
137   -}
138   -
139   -function FormMessage({ className, ...props }: React.ComponentProps<"p">) {
140   - const { error, formMessageId } = useFormField();
141   - const body = error ? String(error?.message ?? "") : props.children;
142   -
143   - if (!body) {
144   - return null;
145   - }
146   -
147   - return (
148   - <p
149   - data-slot="form-message"
150   - id={formMessageId}
151   - className={cn("text-destructive text-sm", className)}
152   - {...props}
153   - >
154   - {body}
155   - </p>
156   - );
157   -}
158   -
159   -export {
160   - useFormField,
161   - Form,
162   - FormItem,
163   - FormLabel,
164   - FormControl,
165   - FormDescription,
166   - FormMessage,
167   - FormField,
168   -};
美国版/Food Labeling Management App React/src/app/components/ui/hover-card.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import * as HoverCardPrimitive from "@radix-ui/react-hover-card";
5   -
6   -import { cn } from "./utils";
7   -
8   -function HoverCard({
9   - ...props
10   -}: React.ComponentProps<typeof HoverCardPrimitive.Root>) {
11   - return <HoverCardPrimitive.Root data-slot="hover-card" {...props} />;
12   -}
13   -
14   -function HoverCardTrigger({
15   - ...props
16   -}: React.ComponentProps<typeof HoverCardPrimitive.Trigger>) {
17   - return (
18   - <HoverCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} />
19   - );
20   -}
21   -
22   -function HoverCardContent({
23   - className,
24   - align = "center",
25   - sideOffset = 4,
26   - ...props
27   -}: React.ComponentProps<typeof HoverCardPrimitive.Content>) {
28   - return (
29   - <HoverCardPrimitive.Portal data-slot="hover-card-portal">
30   - <HoverCardPrimitive.Content
31   - data-slot="hover-card-content"
32   - align={align}
33   - sideOffset={sideOffset}
34   - className={cn(
35   - "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-64 origin-(--radix-hover-card-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
36   - className,
37   - )}
38   - {...props}
39   - />
40   - </HoverCardPrimitive.Portal>
41   - );
42   -}
43   -
44   -export { HoverCard, HoverCardTrigger, HoverCardContent };
美国版/Food Labeling Management App React/src/app/components/ui/input-otp.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import { OTPInput, OTPInputContext } from "input-otp";
5   -import { MinusIcon } from "lucide-react";
6   -
7   -import { cn } from "./utils";
8   -
9   -function InputOTP({
10   - className,
11   - containerClassName,
12   - ...props
13   -}: React.ComponentProps<typeof OTPInput> & {
14   - containerClassName?: string;
15   -}) {
16   - return (
17   - <OTPInput
18   - data-slot="input-otp"
19   - containerClassName={cn(
20   - "flex items-center gap-2 has-disabled:opacity-50",
21   - containerClassName,
22   - )}
23   - className={cn("disabled:cursor-not-allowed", className)}
24   - {...props}
25   - />
26   - );
27   -}
28   -
29   -function InputOTPGroup({ className, ...props }: React.ComponentProps<"div">) {
30   - return (
31   - <div
32   - data-slot="input-otp-group"
33   - className={cn("flex items-center gap-1", className)}
34   - {...props}
35   - />
36   - );
37   -}
38   -
39   -function InputOTPSlot({
40   - index,
41   - className,
42   - ...props
43   -}: React.ComponentProps<"div"> & {
44   - index: number;
45   -}) {
46   - const inputOTPContext = React.useContext(OTPInputContext);
47   - const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {};
48   -
49   - return (
50   - <div
51   - data-slot="input-otp-slot"
52   - data-active={isActive}
53   - className={cn(
54   - "data-[active=true]:border-ring data-[active=true]:ring-ring/50 data-[active=true]:aria-invalid:ring-destructive/20 dark:data-[active=true]:aria-invalid:ring-destructive/40 aria-invalid:border-destructive data-[active=true]:aria-invalid:border-destructive dark:bg-input/30 border-input relative flex h-9 w-9 items-center justify-center border-y border-r text-sm bg-input-background transition-all outline-none first:rounded-l-md first:border-l last:rounded-r-md data-[active=true]:z-10 data-[active=true]:ring-[3px]",
55   - className,
56   - )}
57   - {...props}
58   - >
59   - {char}
60   - {hasFakeCaret && (
61   - <div className="pointer-events-none absolute inset-0 flex items-center justify-center">
62   - <div className="animate-caret-blink bg-foreground h-4 w-px duration-1000" />
63   - </div>
64   - )}
65   - </div>
66   - );
67   -}
68   -
69   -function InputOTPSeparator({ ...props }: React.ComponentProps<"div">) {
70   - return (
71   - <div data-slot="input-otp-separator" role="separator" {...props}>
72   - <MinusIcon />
73   - </div>
74   - );
75   -}
76   -
77   -export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator };
美国版/Food Labeling Management App React/src/app/components/ui/input.tsx deleted
1   -import * as React from "react";
2   -
3   -import { cn } from "./utils";
4   -
5   -function Input({ className, type, ...props }: React.ComponentProps<"input">) {
6   - return (
7   - <input
8   - type={type}
9   - data-slot="input"
10   - className={cn(
11   - "file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border px-3 py-1 text-base bg-input-background transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
12   - "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
13   - "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
14   - className,
15   - )}
16   - {...props}
17   - />
18   - );
19   -}
20   -
21   -export { Input };
美国版/Food Labeling Management App React/src/app/components/ui/label.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import * as LabelPrimitive from "@radix-ui/react-label";
5   -
6   -import { cn } from "./utils";
7   -
8   -function Label({
9   - className,
10   - ...props
11   -}: React.ComponentProps<typeof LabelPrimitive.Root>) {
12   - return (
13   - <LabelPrimitive.Root
14   - data-slot="label"
15   - className={cn(
16   - "flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
17   - className,
18   - )}
19   - {...props}
20   - />
21   - );
22   -}
23   -
24   -export { Label };
美国版/Food Labeling Management App React/src/app/components/ui/menubar.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import * as MenubarPrimitive from "@radix-ui/react-menubar";
5   -import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
6   -
7   -import { cn } from "./utils";
8   -
9   -function Menubar({
10   - className,
11   - ...props
12   -}: React.ComponentProps<typeof MenubarPrimitive.Root>) {
13   - return (
14   - <MenubarPrimitive.Root
15   - data-slot="menubar"
16   - className={cn(
17   - "bg-background flex h-9 items-center gap-1 rounded-md border p-1 shadow-xs",
18   - className,
19   - )}
20   - {...props}
21   - />
22   - );
23   -}
24   -
25   -function MenubarMenu({
26   - ...props
27   -}: React.ComponentProps<typeof MenubarPrimitive.Menu>) {
28   - return <MenubarPrimitive.Menu data-slot="menubar-menu" {...props} />;
29   -}
30   -
31   -function MenubarGroup({
32   - ...props
33   -}: React.ComponentProps<typeof MenubarPrimitive.Group>) {
34   - return <MenubarPrimitive.Group data-slot="menubar-group" {...props} />;
35   -}
36   -
37   -function MenubarPortal({
38   - ...props
39   -}: React.ComponentProps<typeof MenubarPrimitive.Portal>) {
40   - return <MenubarPrimitive.Portal data-slot="menubar-portal" {...props} />;
41   -}
42   -
43   -function MenubarRadioGroup({
44   - ...props
45   -}: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) {
46   - return (
47   - <MenubarPrimitive.RadioGroup data-slot="menubar-radio-group" {...props} />
48   - );
49   -}
50   -
51   -function MenubarTrigger({
52   - className,
53   - ...props
54   -}: React.ComponentProps<typeof MenubarPrimitive.Trigger>) {
55   - return (
56   - <MenubarPrimitive.Trigger
57   - data-slot="menubar-trigger"
58   - className={cn(
59   - "focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex items-center rounded-sm px-2 py-1 text-sm font-medium outline-hidden select-none",
60   - className,
61   - )}
62   - {...props}
63   - />
64   - );
65   -}
66   -
67   -function MenubarContent({
68   - className,
69   - align = "start",
70   - alignOffset = -4,
71   - sideOffset = 8,
72   - ...props
73   -}: React.ComponentProps<typeof MenubarPrimitive.Content>) {
74   - return (
75   - <MenubarPortal>
76   - <MenubarPrimitive.Content
77   - data-slot="menubar-content"
78   - align={align}
79   - alignOffset={alignOffset}
80   - sideOffset={sideOffset}
81   - className={cn(
82   - "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[12rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-md",
83   - className,
84   - )}
85   - {...props}
86   - />
87   - </MenubarPortal>
88   - );
89   -}
90   -
91   -function MenubarItem({
92   - className,
93   - inset,
94   - variant = "default",
95   - ...props
96   -}: React.ComponentProps<typeof MenubarPrimitive.Item> & {
97   - inset?: boolean;
98   - variant?: "default" | "destructive";
99   -}) {
100   - return (
101   - <MenubarPrimitive.Item
102   - data-slot="menubar-item"
103   - data-inset={inset}
104   - data-variant={variant}
105   - className={cn(
106   - "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
107   - className,
108   - )}
109   - {...props}
110   - />
111   - );
112   -}
113   -
114   -function MenubarCheckboxItem({
115   - className,
116   - children,
117   - checked,
118   - ...props
119   -}: React.ComponentProps<typeof MenubarPrimitive.CheckboxItem>) {
120   - return (
121   - <MenubarPrimitive.CheckboxItem
122   - data-slot="menubar-checkbox-item"
123   - className={cn(
124   - "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
125   - className,
126   - )}
127   - checked={checked}
128   - {...props}
129   - >
130   - <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
131   - <MenubarPrimitive.ItemIndicator>
132   - <CheckIcon className="size-4" />
133   - </MenubarPrimitive.ItemIndicator>
134   - </span>
135   - {children}
136   - </MenubarPrimitive.CheckboxItem>
137   - );
138   -}
139   -
140   -function MenubarRadioItem({
141   - className,
142   - children,
143   - ...props
144   -}: React.ComponentProps<typeof MenubarPrimitive.RadioItem>) {
145   - return (
146   - <MenubarPrimitive.RadioItem
147   - data-slot="menubar-radio-item"
148   - className={cn(
149   - "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
150   - className,
151   - )}
152   - {...props}
153   - >
154   - <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
155   - <MenubarPrimitive.ItemIndicator>
156   - <CircleIcon className="size-2 fill-current" />
157   - </MenubarPrimitive.ItemIndicator>
158   - </span>
159   - {children}
160   - </MenubarPrimitive.RadioItem>
161   - );
162   -}
163   -
164   -function MenubarLabel({
165   - className,
166   - inset,
167   - ...props
168   -}: React.ComponentProps<typeof MenubarPrimitive.Label> & {
169   - inset?: boolean;
170   -}) {
171   - return (
172   - <MenubarPrimitive.Label
173   - data-slot="menubar-label"
174   - data-inset={inset}
175   - className={cn(
176   - "px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
177   - className,
178   - )}
179   - {...props}
180   - />
181   - );
182   -}
183   -
184   -function MenubarSeparator({
185   - className,
186   - ...props
187   -}: React.ComponentProps<typeof MenubarPrimitive.Separator>) {
188   - return (
189   - <MenubarPrimitive.Separator
190   - data-slot="menubar-separator"
191   - className={cn("bg-border -mx-1 my-1 h-px", className)}
192   - {...props}
193   - />
194   - );
195   -}
196   -
197   -function MenubarShortcut({
198   - className,
199   - ...props
200   -}: React.ComponentProps<"span">) {
201   - return (
202   - <span
203   - data-slot="menubar-shortcut"
204   - className={cn(
205   - "text-muted-foreground ml-auto text-xs tracking-widest",
206   - className,
207   - )}
208   - {...props}
209   - />
210   - );
211   -}
212   -
213   -function MenubarSub({
214   - ...props
215   -}: React.ComponentProps<typeof MenubarPrimitive.Sub>) {
216   - return <MenubarPrimitive.Sub data-slot="menubar-sub" {...props} />;
217   -}
218   -
219   -function MenubarSubTrigger({
220   - className,
221   - inset,
222   - children,
223   - ...props
224   -}: React.ComponentProps<typeof MenubarPrimitive.SubTrigger> & {
225   - inset?: boolean;
226   -}) {
227   - return (
228   - <MenubarPrimitive.SubTrigger
229   - data-slot="menubar-sub-trigger"
230   - data-inset={inset}
231   - className={cn(
232   - "focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[inset]:pl-8",
233   - className,
234   - )}
235   - {...props}
236   - >
237   - {children}
238   - <ChevronRightIcon className="ml-auto h-4 w-4" />
239   - </MenubarPrimitive.SubTrigger>
240   - );
241   -}
242   -
243   -function MenubarSubContent({
244   - className,
245   - ...props
246   -}: React.ComponentProps<typeof MenubarPrimitive.SubContent>) {
247   - return (
248   - <MenubarPrimitive.SubContent
249   - data-slot="menubar-sub-content"
250   - className={cn(
251   - "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg",
252   - className,
253   - )}
254   - {...props}
255   - />
256   - );
257   -}
258   -
259   -export {
260   - Menubar,
261   - MenubarPortal,
262   - MenubarMenu,
263   - MenubarTrigger,
264   - MenubarContent,
265   - MenubarGroup,
266   - MenubarSeparator,
267   - MenubarLabel,
268   - MenubarItem,
269   - MenubarShortcut,
270   - MenubarCheckboxItem,
271   - MenubarRadioGroup,
272   - MenubarRadioItem,
273   - MenubarSub,
274   - MenubarSubTrigger,
275   - MenubarSubContent,
276   -};
美国版/Food Labeling Management App React/src/app/components/ui/navigation-menu.tsx deleted
1   -import * as React from "react";
2   -import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu";
3   -import { cva } from "class-variance-authority";
4   -import { ChevronDownIcon } from "lucide-react";
5   -
6   -import { cn } from "./utils";
7   -
8   -function NavigationMenu({
9   - className,
10   - children,
11   - viewport = true,
12   - ...props
13   -}: React.ComponentProps<typeof NavigationMenuPrimitive.Root> & {
14   - viewport?: boolean;
15   -}) {
16   - return (
17   - <NavigationMenuPrimitive.Root
18   - data-slot="navigation-menu"
19   - data-viewport={viewport}
20   - className={cn(
21   - "group/navigation-menu relative flex max-w-max flex-1 items-center justify-center",
22   - className,
23   - )}
24   - {...props}
25   - >
26   - {children}
27   - {viewport && <NavigationMenuViewport />}
28   - </NavigationMenuPrimitive.Root>
29   - );
30   -}
31   -
32   -function NavigationMenuList({
33   - className,
34   - ...props
35   -}: React.ComponentProps<typeof NavigationMenuPrimitive.List>) {
36   - return (
37   - <NavigationMenuPrimitive.List
38   - data-slot="navigation-menu-list"
39   - className={cn(
40   - "group flex flex-1 list-none items-center justify-center gap-1",
41   - className,
42   - )}
43   - {...props}
44   - />
45   - );
46   -}
47   -
48   -function NavigationMenuItem({
49   - className,
50   - ...props
51   -}: React.ComponentProps<typeof NavigationMenuPrimitive.Item>) {
52   - return (
53   - <NavigationMenuPrimitive.Item
54   - data-slot="navigation-menu-item"
55   - className={cn("relative", className)}
56   - {...props}
57   - />
58   - );
59   -}
60   -
61   -const navigationMenuTriggerStyle = cva(
62   - "group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:hover:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent data-[state=open]:bg-accent/50 focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1",
63   -);
64   -
65   -function NavigationMenuTrigger({
66   - className,
67   - children,
68   - ...props
69   -}: React.ComponentProps<typeof NavigationMenuPrimitive.Trigger>) {
70   - return (
71   - <NavigationMenuPrimitive.Trigger
72   - data-slot="navigation-menu-trigger"
73   - className={cn(navigationMenuTriggerStyle(), "group", className)}
74   - {...props}
75   - >
76   - {children}{" "}
77   - <ChevronDownIcon
78   - className="relative top-[1px] ml-1 size-3 transition duration-300 group-data-[state=open]:rotate-180"
79   - aria-hidden="true"
80   - />
81   - </NavigationMenuPrimitive.Trigger>
82   - );
83   -}
84   -
85   -function NavigationMenuContent({
86   - className,
87   - ...props
88   -}: React.ComponentProps<typeof NavigationMenuPrimitive.Content>) {
89   - return (
90   - <NavigationMenuPrimitive.Content
91   - data-slot="navigation-menu-content"
92   - className={cn(
93   - "data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 top-0 left-0 w-full p-2 pr-2.5 md:absolute md:w-auto",
94   - "group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:data-[state=open]:animate-in group-data-[viewport=false]/navigation-menu:data-[state=closed]:animate-out group-data-[viewport=false]/navigation-menu:data-[state=closed]:zoom-out-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:fade-in-0 group-data-[viewport=false]/navigation-menu:data-[state=closed]:fade-out-0 group-data-[viewport=false]/navigation-menu:top-full group-data-[viewport=false]/navigation-menu:mt-1.5 group-data-[viewport=false]/navigation-menu:overflow-hidden group-data-[viewport=false]/navigation-menu:rounded-md group-data-[viewport=false]/navigation-menu:border group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:duration-200 **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none",
95   - className,
96   - )}
97   - {...props}
98   - />
99   - );
100   -}
101   -
102   -function NavigationMenuViewport({
103   - className,
104   - ...props
105   -}: React.ComponentProps<typeof NavigationMenuPrimitive.Viewport>) {
106   - return (
107   - <div
108   - className={cn(
109   - "absolute top-full left-0 isolate z-50 flex justify-center",
110   - )}
111   - >
112   - <NavigationMenuPrimitive.Viewport
113   - data-slot="navigation-menu-viewport"
114   - className={cn(
115   - "origin-top-center bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border shadow md:w-[var(--radix-navigation-menu-viewport-width)]",
116   - className,
117   - )}
118   - {...props}
119   - />
120   - </div>
121   - );
122   -}
123   -
124   -function NavigationMenuLink({
125   - className,
126   - ...props
127   -}: React.ComponentProps<typeof NavigationMenuPrimitive.Link>) {
128   - return (
129   - <NavigationMenuPrimitive.Link
130   - data-slot="navigation-menu-link"
131   - className={cn(
132   - "data-[active=true]:focus:bg-accent data-[active=true]:hover:bg-accent data-[active=true]:bg-accent/50 data-[active=true]:text-accent-foreground hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus-visible:ring-ring/50 [&_svg:not([class*='text-'])]:text-muted-foreground flex flex-col gap-1 rounded-sm p-2 text-sm transition-all outline-none focus-visible:ring-[3px] focus-visible:outline-1 [&_svg:not([class*='size-'])]:size-4",
133   - className,
134   - )}
135   - {...props}
136   - />
137   - );
138   -}
139   -
140   -function NavigationMenuIndicator({
141   - className,
142   - ...props
143   -}: React.ComponentProps<typeof NavigationMenuPrimitive.Indicator>) {
144   - return (
145   - <NavigationMenuPrimitive.Indicator
146   - data-slot="navigation-menu-indicator"
147   - className={cn(
148   - "data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden",
149   - className,
150   - )}
151   - {...props}
152   - >
153   - <div className="bg-border relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm shadow-md" />
154   - </NavigationMenuPrimitive.Indicator>
155   - );
156   -}
157   -
158   -export {
159   - NavigationMenu,
160   - NavigationMenuList,
161   - NavigationMenuItem,
162   - NavigationMenuContent,
163   - NavigationMenuTrigger,
164   - NavigationMenuLink,
165   - NavigationMenuIndicator,
166   - NavigationMenuViewport,
167   - navigationMenuTriggerStyle,
168   -};
美国版/Food Labeling Management App React/src/app/components/ui/pagination.tsx deleted
1   -import * as React from "react";
2   -import {
3   - ChevronLeftIcon,
4   - ChevronRightIcon,
5   - MoreHorizontalIcon,
6   -} from "lucide-react";
7   -
8   -import { cn } from "./utils";
9   -import { Button, buttonVariants } from "./button";
10   -
11   -function Pagination({ className, ...props }: React.ComponentProps<"nav">) {
12   - return (
13   - <nav
14   - role="navigation"
15   - aria-label="pagination"
16   - data-slot="pagination"
17   - className={cn("mx-auto flex w-full justify-center", className)}
18   - {...props}
19   - />
20   - );
21   -}
22   -
23   -function PaginationContent({
24   - className,
25   - ...props
26   -}: React.ComponentProps<"ul">) {
27   - return (
28   - <ul
29   - data-slot="pagination-content"
30   - className={cn("flex flex-row items-center gap-1", className)}
31   - {...props}
32   - />
33   - );
34   -}
35   -
36   -function PaginationItem({ ...props }: React.ComponentProps<"li">) {
37   - return <li data-slot="pagination-item" {...props} />;
38   -}
39   -
40   -type PaginationLinkProps = {
41   - isActive?: boolean;
42   -} & Pick<React.ComponentProps<typeof Button>, "size"> &
43   - React.ComponentProps<"a">;
44   -
45   -function PaginationLink({
46   - className,
47   - isActive,
48   - size = "icon",
49   - ...props
50   -}: PaginationLinkProps) {
51   - return (
52   - <a
53   - aria-current={isActive ? "page" : undefined}
54   - data-slot="pagination-link"
55   - data-active={isActive}
56   - className={cn(
57   - buttonVariants({
58   - variant: isActive ? "outline" : "ghost",
59   - size,
60   - }),
61   - className,
62   - )}
63   - {...props}
64   - />
65   - );
66   -}
67   -
68   -function PaginationPrevious({
69   - className,
70   - ...props
71   -}: React.ComponentProps<typeof PaginationLink>) {
72   - return (
73   - <PaginationLink
74   - aria-label="Go to previous page"
75   - size="default"
76   - className={cn("gap-1 px-2.5 sm:pl-2.5", className)}
77   - {...props}
78   - >
79   - <ChevronLeftIcon />
80   - <span className="hidden sm:block">Previous</span>
81   - </PaginationLink>
82   - );
83   -}
84   -
85   -function PaginationNext({
86   - className,
87   - ...props
88   -}: React.ComponentProps<typeof PaginationLink>) {
89   - return (
90   - <PaginationLink
91   - aria-label="Go to next page"
92   - size="default"
93   - className={cn("gap-1 px-2.5 sm:pr-2.5", className)}
94   - {...props}
95   - >
96   - <span className="hidden sm:block">Next</span>
97   - <ChevronRightIcon />
98   - </PaginationLink>
99   - );
100   -}
101   -
102   -function PaginationEllipsis({
103   - className,
104   - ...props
105   -}: React.ComponentProps<"span">) {
106   - return (
107   - <span
108   - aria-hidden
109   - data-slot="pagination-ellipsis"
110   - className={cn("flex size-9 items-center justify-center", className)}
111   - {...props}
112   - >
113   - <MoreHorizontalIcon className="size-4" />
114   - <span className="sr-only">More pages</span>
115   - </span>
116   - );
117   -}
118   -
119   -export {
120   - Pagination,
121   - PaginationContent,
122   - PaginationLink,
123   - PaginationItem,
124   - PaginationPrevious,
125   - PaginationNext,
126   - PaginationEllipsis,
127   -};
美国版/Food Labeling Management App React/src/app/components/ui/popover.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import * as PopoverPrimitive from "@radix-ui/react-popover";
5   -
6   -import { cn } from "./utils";
7   -
8   -function Popover({
9   - ...props
10   -}: React.ComponentProps<typeof PopoverPrimitive.Root>) {
11   - return <PopoverPrimitive.Root data-slot="popover" {...props} />;
12   -}
13   -
14   -function PopoverTrigger({
15   - ...props
16   -}: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
17   - return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />;
18   -}
19   -
20   -function PopoverContent({
21   - className,
22   - align = "center",
23   - sideOffset = 4,
24   - ...props
25   -}: React.ComponentProps<typeof PopoverPrimitive.Content>) {
26   - return (
27   - <PopoverPrimitive.Portal>
28   - <PopoverPrimitive.Content
29   - data-slot="popover-content"
30   - align={align}
31   - sideOffset={sideOffset}
32   - className={cn(
33   - "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
34   - className,
35   - )}
36   - {...props}
37   - />
38   - </PopoverPrimitive.Portal>
39   - );
40   -}
41   -
42   -function PopoverAnchor({
43   - ...props
44   -}: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
45   - return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />;
46   -}
47   -
48   -export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };
美国版/Food Labeling Management App React/src/app/components/ui/progress.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import * as ProgressPrimitive from "@radix-ui/react-progress";
5   -
6   -import { cn } from "./utils";
7   -
8   -function Progress({
9   - className,
10   - value,
11   - ...props
12   -}: React.ComponentProps<typeof ProgressPrimitive.Root>) {
13   - return (
14   - <ProgressPrimitive.Root
15   - data-slot="progress"
16   - className={cn(
17   - "bg-primary/20 relative h-2 w-full overflow-hidden rounded-full",
18   - className,
19   - )}
20   - {...props}
21   - >
22   - <ProgressPrimitive.Indicator
23   - data-slot="progress-indicator"
24   - className="bg-primary h-full w-full flex-1 transition-all"
25   - style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
26   - />
27   - </ProgressPrimitive.Root>
28   - );
29   -}
30   -
31   -export { Progress };
美国版/Food Labeling Management App React/src/app/components/ui/radio-group.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
5   -import { CircleIcon } from "lucide-react";
6   -
7   -import { cn } from "./utils";
8   -
9   -function RadioGroup({
10   - className,
11   - ...props
12   -}: React.ComponentProps<typeof RadioGroupPrimitive.Root>) {
13   - return (
14   - <RadioGroupPrimitive.Root
15   - data-slot="radio-group"
16   - className={cn("grid gap-3", className)}
17   - {...props}
18   - />
19   - );
20   -}
21   -
22   -function RadioGroupItem({
23   - className,
24   - ...props
25   -}: React.ComponentProps<typeof RadioGroupPrimitive.Item>) {
26   - return (
27   - <RadioGroupPrimitive.Item
28   - data-slot="radio-group-item"
29   - className={cn(
30   - "border-input text-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 aspect-square size-4 shrink-0 rounded-full border shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
31   - className,
32   - )}
33   - {...props}
34   - >
35   - <RadioGroupPrimitive.Indicator
36   - data-slot="radio-group-indicator"
37   - className="relative flex items-center justify-center"
38   - >
39   - <CircleIcon className="fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2" />
40   - </RadioGroupPrimitive.Indicator>
41   - </RadioGroupPrimitive.Item>
42   - );
43   -}
44   -
45   -export { RadioGroup, RadioGroupItem };
美国版/Food Labeling Management App React/src/app/components/ui/resizable.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import { GripVerticalIcon } from "lucide-react";
5   -import * as ResizablePrimitive from "react-resizable-panels";
6   -
7   -import { cn } from "./utils";
8   -
9   -function ResizablePanelGroup({
10   - className,
11   - ...props
12   -}: React.ComponentProps<typeof ResizablePrimitive.PanelGroup>) {
13   - return (
14   - <ResizablePrimitive.PanelGroup
15   - data-slot="resizable-panel-group"
16   - className={cn(
17   - "flex h-full w-full data-[panel-group-direction=vertical]:flex-col",
18   - className,
19   - )}
20   - {...props}
21   - />
22   - );
23   -}
24   -
25   -function ResizablePanel({
26   - ...props
27   -}: React.ComponentProps<typeof ResizablePrimitive.Panel>) {
28   - return <ResizablePrimitive.Panel data-slot="resizable-panel" {...props} />;
29   -}
30   -
31   -function ResizableHandle({
32   - withHandle,
33   - className,
34   - ...props
35   -}: React.ComponentProps<typeof ResizablePrimitive.PanelResizeHandle> & {
36   - withHandle?: boolean;
37   -}) {
38   - return (
39   - <ResizablePrimitive.PanelResizeHandle
40   - data-slot="resizable-handle"
41   - className={cn(
42   - "bg-border focus-visible:ring-ring relative flex w-px items-center justify-center after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:ring-1 focus-visible:ring-offset-1 focus-visible:outline-hidden data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90",
43   - className,
44   - )}
45   - {...props}
46   - >
47   - {withHandle && (
48   - <div className="bg-border z-10 flex h-4 w-3 items-center justify-center rounded-xs border">
49   - <GripVerticalIcon className="size-2.5" />
50   - </div>
51   - )}
52   - </ResizablePrimitive.PanelResizeHandle>
53   - );
54   -}
55   -
56   -export { ResizablePanelGroup, ResizablePanel, ResizableHandle };
美国版/Food Labeling Management App React/src/app/components/ui/scroll-area.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
5   -
6   -import { cn } from "./utils";
7   -
8   -function ScrollArea({
9   - className,
10   - children,
11   - ...props
12   -}: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {
13   - return (
14   - <ScrollAreaPrimitive.Root
15   - data-slot="scroll-area"
16   - className={cn("relative", className)}
17   - {...props}
18   - >
19   - <ScrollAreaPrimitive.Viewport
20   - data-slot="scroll-area-viewport"
21   - className="focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1"
22   - >
23   - {children}
24   - </ScrollAreaPrimitive.Viewport>
25   - <ScrollBar />
26   - <ScrollAreaPrimitive.Corner />
27   - </ScrollAreaPrimitive.Root>
28   - );
29   -}
30   -
31   -function ScrollBar({
32   - className,
33   - orientation = "vertical",
34   - ...props
35   -}: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) {
36   - return (
37   - <ScrollAreaPrimitive.ScrollAreaScrollbar
38   - data-slot="scroll-area-scrollbar"
39   - orientation={orientation}
40   - className={cn(
41   - "flex touch-none p-px transition-colors select-none",
42   - orientation === "vertical" &&
43   - "h-full w-2.5 border-l border-l-transparent",
44   - orientation === "horizontal" &&
45   - "h-2.5 flex-col border-t border-t-transparent",
46   - className,
47   - )}
48   - {...props}
49   - >
50   - <ScrollAreaPrimitive.ScrollAreaThumb
51   - data-slot="scroll-area-thumb"
52   - className="bg-border relative flex-1 rounded-full"
53   - />
54   - </ScrollAreaPrimitive.ScrollAreaScrollbar>
55   - );
56   -}
57   -
58   -export { ScrollArea, ScrollBar };
美国版/Food Labeling Management App React/src/app/components/ui/select.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import * as SelectPrimitive from "@radix-ui/react-select";
5   -import {
6   - CheckIcon,
7   - ChevronDownIcon,
8   - ChevronUpIcon,
9   -} from "lucide-react";
10   -
11   -import { cn } from "./utils";
12   -
13   -function Select({
14   - ...props
15   -}: React.ComponentProps<typeof SelectPrimitive.Root>) {
16   - return <SelectPrimitive.Root data-slot="select" {...props} />;
17   -}
18   -
19   -function SelectGroup({
20   - ...props
21   -}: React.ComponentProps<typeof SelectPrimitive.Group>) {
22   - return <SelectPrimitive.Group data-slot="select-group" {...props} />;
23   -}
24   -
25   -function SelectValue({
26   - ...props
27   -}: React.ComponentProps<typeof SelectPrimitive.Value>) {
28   - return <SelectPrimitive.Value data-slot="select-value" {...props} />;
29   -}
30   -
31   -function SelectTrigger({
32   - className,
33   - size = "default",
34   - children,
35   - ...props
36   -}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
37   - size?: "sm" | "default";
38   -}) {
39   - return (
40   - <SelectPrimitive.Trigger
41   - data-slot="select-trigger"
42   - data-size={size}
43   - className={cn(
44   - "border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-full items-center justify-between gap-2 rounded-md border bg-input-background px-3 py-2 text-sm whitespace-nowrap transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
45   - className,
46   - )}
47   - {...props}
48   - >
49   - {children}
50   - <SelectPrimitive.Icon asChild>
51   - <ChevronDownIcon className="size-4 opacity-50" />
52   - </SelectPrimitive.Icon>
53   - </SelectPrimitive.Trigger>
54   - );
55   -}
56   -
57   -function SelectContent({
58   - className,
59   - children,
60   - position = "popper",
61   - ...props
62   -}: React.ComponentProps<typeof SelectPrimitive.Content>) {
63   - return (
64   - <SelectPrimitive.Portal>
65   - <SelectPrimitive.Content
66   - data-slot="select-content"
67   - className={cn(
68   - "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
69   - position === "popper" &&
70   - "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
71   - className,
72   - )}
73   - position={position}
74   - {...props}
75   - >
76   - <SelectScrollUpButton />
77   - <SelectPrimitive.Viewport
78   - className={cn(
79   - "p-1",
80   - position === "popper" &&
81   - "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1",
82   - )}
83   - >
84   - {children}
85   - </SelectPrimitive.Viewport>
86   - <SelectScrollDownButton />
87   - </SelectPrimitive.Content>
88   - </SelectPrimitive.Portal>
89   - );
90   -}
91   -
92   -function SelectLabel({
93   - className,
94   - ...props
95   -}: React.ComponentProps<typeof SelectPrimitive.Label>) {
96   - return (
97   - <SelectPrimitive.Label
98   - data-slot="select-label"
99   - className={cn("text-muted-foreground px-2 py-1.5 text-xs", className)}
100   - {...props}
101   - />
102   - );
103   -}
104   -
105   -function SelectItem({
106   - className,
107   - children,
108   - ...props
109   -}: React.ComponentProps<typeof SelectPrimitive.Item>) {
110   - return (
111   - <SelectPrimitive.Item
112   - data-slot="select-item"
113   - className={cn(
114   - "focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
115   - className,
116   - )}
117   - {...props}
118   - >
119   - <span className="absolute right-2 flex size-3.5 items-center justify-center">
120   - <SelectPrimitive.ItemIndicator>
121   - <CheckIcon className="size-4" />
122   - </SelectPrimitive.ItemIndicator>
123   - </span>
124   - <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
125   - </SelectPrimitive.Item>
126   - );
127   -}
128   -
129   -function SelectSeparator({
130   - className,
131   - ...props
132   -}: React.ComponentProps<typeof SelectPrimitive.Separator>) {
133   - return (
134   - <SelectPrimitive.Separator
135   - data-slot="select-separator"
136   - className={cn("bg-border pointer-events-none -mx-1 my-1 h-px", className)}
137   - {...props}
138   - />
139   - );
140   -}
141   -
142   -function SelectScrollUpButton({
143   - className,
144   - ...props
145   -}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
146   - return (
147   - <SelectPrimitive.ScrollUpButton
148   - data-slot="select-scroll-up-button"
149   - className={cn(
150   - "flex cursor-default items-center justify-center py-1",
151   - className,
152   - )}
153   - {...props}
154   - >
155   - <ChevronUpIcon className="size-4" />
156   - </SelectPrimitive.ScrollUpButton>
157   - );
158   -}
159   -
160   -function SelectScrollDownButton({
161   - className,
162   - ...props
163   -}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
164   - return (
165   - <SelectPrimitive.ScrollDownButton
166   - data-slot="select-scroll-down-button"
167   - className={cn(
168   - "flex cursor-default items-center justify-center py-1",
169   - className,
170   - )}
171   - {...props}
172   - >
173   - <ChevronDownIcon className="size-4" />
174   - </SelectPrimitive.ScrollDownButton>
175   - );
176   -}
177   -
178   -export {
179   - Select,
180   - SelectContent,
181   - SelectGroup,
182   - SelectItem,
183   - SelectLabel,
184   - SelectScrollDownButton,
185   - SelectScrollUpButton,
186   - SelectSeparator,
187   - SelectTrigger,
188   - SelectValue,
189   -};
美国版/Food Labeling Management App React/src/app/components/ui/separator.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import * as SeparatorPrimitive from "@radix-ui/react-separator";
5   -
6   -import { cn } from "./utils";
7   -
8   -function Separator({
9   - className,
10   - orientation = "horizontal",
11   - decorative = true,
12   - ...props
13   -}: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
14   - return (
15   - <SeparatorPrimitive.Root
16   - data-slot="separator-root"
17   - decorative={decorative}
18   - orientation={orientation}
19   - className={cn(
20   - "bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
21   - className,
22   - )}
23   - {...props}
24   - />
25   - );
26   -}
27   -
28   -export { Separator };
美国版/Food Labeling Management App React/src/app/components/ui/sheet.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import * as SheetPrimitive from "@radix-ui/react-dialog";
5   -import { XIcon } from "lucide-react";
6   -
7   -import { cn } from "./utils";
8   -
9   -function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {
10   - return <SheetPrimitive.Root data-slot="sheet" {...props} />;
11   -}
12   -
13   -function SheetTrigger({
14   - ...props
15   -}: React.ComponentProps<typeof SheetPrimitive.Trigger>) {
16   - return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />;
17   -}
18   -
19   -function SheetClose({
20   - ...props
21   -}: React.ComponentProps<typeof SheetPrimitive.Close>) {
22   - return <SheetPrimitive.Close data-slot="sheet-close" {...props} />;
23   -}
24   -
25   -function SheetPortal({
26   - ...props
27   -}: React.ComponentProps<typeof SheetPrimitive.Portal>) {
28   - return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />;
29   -}
30   -
31   -function SheetOverlay({
32   - className,
33   - ...props
34   -}: React.ComponentProps<typeof SheetPrimitive.Overlay>) {
35   - return (
36   - <SheetPrimitive.Overlay
37   - data-slot="sheet-overlay"
38   - className={cn(
39   - "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
40   - className,
41   - )}
42   - {...props}
43   - />
44   - );
45   -}
46   -
47   -function SheetContent({
48   - className,
49   - children,
50   - side = "right",
51   - ...props
52   -}: React.ComponentProps<typeof SheetPrimitive.Content> & {
53   - side?: "top" | "right" | "bottom" | "left";
54   -}) {
55   - return (
56   - <SheetPortal>
57   - <SheetOverlay />
58   - <SheetPrimitive.Content
59   - data-slot="sheet-content"
60   - className={cn(
61   - "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
62   - side === "right" &&
63   - "data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm",
64   - side === "left" &&
65   - "data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm",
66   - side === "top" &&
67   - "data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b",
68   - side === "bottom" &&
69   - "data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t",
70   - className,
71   - )}
72   - {...props}
73   - >
74   - {children}
75   - <SheetPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none">
76   - <XIcon className="size-4" />
77   - <span className="sr-only">Close</span>
78   - </SheetPrimitive.Close>
79   - </SheetPrimitive.Content>
80   - </SheetPortal>
81   - );
82   -}
83   -
84   -function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
85   - return (
86   - <div
87   - data-slot="sheet-header"
88   - className={cn("flex flex-col gap-1.5 p-4", className)}
89   - {...props}
90   - />
91   - );
92   -}
93   -
94   -function SheetFooter({ className, ...props }: React.ComponentProps<"div">) {
95   - return (
96   - <div
97   - data-slot="sheet-footer"
98   - className={cn("mt-auto flex flex-col gap-2 p-4", className)}
99   - {...props}
100   - />
101   - );
102   -}
103   -
104   -function SheetTitle({
105   - className,
106   - ...props
107   -}: React.ComponentProps<typeof SheetPrimitive.Title>) {
108   - return (
109   - <SheetPrimitive.Title
110   - data-slot="sheet-title"
111   - className={cn("text-foreground font-semibold", className)}
112   - {...props}
113   - />
114   - );
115   -}
116   -
117   -function SheetDescription({
118   - className,
119   - ...props
120   -}: React.ComponentProps<typeof SheetPrimitive.Description>) {
121   - return (
122   - <SheetPrimitive.Description
123   - data-slot="sheet-description"
124   - className={cn("text-muted-foreground text-sm", className)}
125   - {...props}
126   - />
127   - );
128   -}
129   -
130   -export {
131   - Sheet,
132   - SheetTrigger,
133   - SheetClose,
134   - SheetContent,
135   - SheetHeader,
136   - SheetFooter,
137   - SheetTitle,
138   - SheetDescription,
139   -};
美国版/Food Labeling Management App React/src/app/components/ui/sidebar.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import { Slot } from "@radix-ui/react-slot";
5   -import { VariantProps, cva } from "class-variance-authority";
6   -import { PanelLeftIcon } from "lucide-react";
7   -
8   -import { useIsMobile } from "./use-mobile";
9   -import { cn } from "./utils";
10   -import { Button } from "./button";
11   -import { Input } from "./input";
12   -import { Separator } from "./separator";
13   -import {
14   - Sheet,
15   - SheetContent,
16   - SheetDescription,
17   - SheetHeader,
18   - SheetTitle,
19   -} from "./sheet";
20   -import { Skeleton } from "./skeleton";
21   -import {
22   - Tooltip,
23   - TooltipContent,
24   - TooltipProvider,
25   - TooltipTrigger,
26   -} from "./tooltip";
27   -
28   -const SIDEBAR_COOKIE_NAME = "sidebar_state";
29   -const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
30   -const SIDEBAR_WIDTH = "16rem";
31   -const SIDEBAR_WIDTH_MOBILE = "18rem";
32   -const SIDEBAR_WIDTH_ICON = "3rem";
33   -const SIDEBAR_KEYBOARD_SHORTCUT = "b";
34   -
35   -type SidebarContextProps = {
36   - state: "expanded" | "collapsed";
37   - open: boolean;
38   - setOpen: (open: boolean) => void;
39   - openMobile: boolean;
40   - setOpenMobile: (open: boolean) => void;
41   - isMobile: boolean;
42   - toggleSidebar: () => void;
43   -};
44   -
45   -const SidebarContext = React.createContext<SidebarContextProps | null>(null);
46   -
47   -function useSidebar() {
48   - const context = React.useContext(SidebarContext);
49   - if (!context) {
50   - throw new Error("useSidebar must be used within a SidebarProvider.");
51   - }
52   -
53   - return context;
54   -}
55   -
56   -function SidebarProvider({
57   - defaultOpen = true,
58   - open: openProp,
59   - onOpenChange: setOpenProp,
60   - className,
61   - style,
62   - children,
63   - ...props
64   -}: React.ComponentProps<"div"> & {
65   - defaultOpen?: boolean;
66   - open?: boolean;
67   - onOpenChange?: (open: boolean) => void;
68   -}) {
69   - const isMobile = useIsMobile();
70   - const [openMobile, setOpenMobile] = React.useState(false);
71   -
72   - // This is the internal state of the sidebar.
73   - // We use openProp and setOpenProp for control from outside the component.
74   - const [_open, _setOpen] = React.useState(defaultOpen);
75   - const open = openProp ?? _open;
76   - const setOpen = React.useCallback(
77   - (value: boolean | ((value: boolean) => boolean)) => {
78   - const openState = typeof value === "function" ? value(open) : value;
79   - if (setOpenProp) {
80   - setOpenProp(openState);
81   - } else {
82   - _setOpen(openState);
83   - }
84   -
85   - // This sets the cookie to keep the sidebar state.
86   - document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
87   - },
88   - [setOpenProp, open],
89   - );
90   -
91   - // Helper to toggle the sidebar.
92   - const toggleSidebar = React.useCallback(() => {
93   - return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open);
94   - }, [isMobile, setOpen, setOpenMobile]);
95   -
96   - // Adds a keyboard shortcut to toggle the sidebar.
97   - React.useEffect(() => {
98   - const handleKeyDown = (event: KeyboardEvent) => {
99   - if (
100   - event.key === SIDEBAR_KEYBOARD_SHORTCUT &&
101   - (event.metaKey || event.ctrlKey)
102   - ) {
103   - event.preventDefault();
104   - toggleSidebar();
105   - }
106   - };
107   -
108   - window.addEventListener("keydown", handleKeyDown);
109   - return () => window.removeEventListener("keydown", handleKeyDown);
110   - }, [toggleSidebar]);
111   -
112   - // We add a state so that we can do data-state="expanded" or "collapsed".
113   - // This makes it easier to style the sidebar with Tailwind classes.
114   - const state = open ? "expanded" : "collapsed";
115   -
116   - const contextValue = React.useMemo<SidebarContextProps>(
117   - () => ({
118   - state,
119   - open,
120   - setOpen,
121   - isMobile,
122   - openMobile,
123   - setOpenMobile,
124   - toggleSidebar,
125   - }),
126   - [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar],
127   - );
128   -
129   - return (
130   - <SidebarContext.Provider value={contextValue}>
131   - <TooltipProvider delayDuration={0}>
132   - <div
133   - data-slot="sidebar-wrapper"
134   - style={
135   - {
136   - "--sidebar-width": SIDEBAR_WIDTH,
137   - "--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
138   - ...style,
139   - } as React.CSSProperties
140   - }
141   - className={cn(
142   - "group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full",
143   - className,
144   - )}
145   - {...props}
146   - >
147   - {children}
148   - </div>
149   - </TooltipProvider>
150   - </SidebarContext.Provider>
151   - );
152   -}
153   -
154   -function Sidebar({
155   - side = "left",
156   - variant = "sidebar",
157   - collapsible = "offcanvas",
158   - className,
159   - children,
160   - ...props
161   -}: React.ComponentProps<"div"> & {
162   - side?: "left" | "right";
163   - variant?: "sidebar" | "floating" | "inset";
164   - collapsible?: "offcanvas" | "icon" | "none";
165   -}) {
166   - const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
167   -
168   - if (collapsible === "none") {
169   - return (
170   - <div
171   - data-slot="sidebar"
172   - className={cn(
173   - "bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col",
174   - className,
175   - )}
176   - {...props}
177   - >
178   - {children}
179   - </div>
180   - );
181   - }
182   -
183   - if (isMobile) {
184   - return (
185   - <Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}>
186   - <SheetContent
187   - data-sidebar="sidebar"
188   - data-slot="sidebar"
189   - data-mobile="true"
190   - className="bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden"
191   - style={
192   - {
193   - "--sidebar-width": SIDEBAR_WIDTH_MOBILE,
194   - } as React.CSSProperties
195   - }
196   - side={side}
197   - >
198   - <SheetHeader className="sr-only">
199   - <SheetTitle>Sidebar</SheetTitle>
200   - <SheetDescription>Displays the mobile sidebar.</SheetDescription>
201   - </SheetHeader>
202   - <div className="flex h-full w-full flex-col">{children}</div>
203   - </SheetContent>
204   - </Sheet>
205   - );
206   - }
207   -
208   - return (
209   - <div
210   - className="group peer text-sidebar-foreground hidden md:block"
211   - data-state={state}
212   - data-collapsible={state === "collapsed" ? collapsible : ""}
213   - data-variant={variant}
214   - data-side={side}
215   - data-slot="sidebar"
216   - >
217   - {/* This is what handles the sidebar gap on desktop */}
218   - <div
219   - data-slot="sidebar-gap"
220   - className={cn(
221   - "relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear",
222   - "group-data-[collapsible=offcanvas]:w-0",
223   - "group-data-[side=right]:rotate-180",
224   - variant === "floating" || variant === "inset"
225   - ? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]"
226   - : "group-data-[collapsible=icon]:w-(--sidebar-width-icon)",
227   - )}
228   - />
229   - <div
230   - data-slot="sidebar-container"
231   - className={cn(
232   - "fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex",
233   - side === "left"
234   - ? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]"
235   - : "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
236   - // Adjust the padding for floating and inset variants.
237   - variant === "floating" || variant === "inset"
238   - ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]"
239   - : "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l",
240   - className,
241   - )}
242   - {...props}
243   - >
244   - <div
245   - data-sidebar="sidebar"
246   - data-slot="sidebar-inner"
247   - className="bg-sidebar group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm"
248   - >
249   - {children}
250   - </div>
251   - </div>
252   - </div>
253   - );
254   -}
255   -
256   -function SidebarTrigger({
257   - className,
258   - onClick,
259   - ...props
260   -}: React.ComponentProps<typeof Button>) {
261   - const { toggleSidebar } = useSidebar();
262   -
263   - return (
264   - <Button
265   - data-sidebar="trigger"
266   - data-slot="sidebar-trigger"
267   - variant="ghost"
268   - size="icon"
269   - className={cn("size-7", className)}
270   - onClick={(event) => {
271   - onClick?.(event);
272   - toggleSidebar();
273   - }}
274   - {...props}
275   - >
276   - <PanelLeftIcon />
277   - <span className="sr-only">Toggle Sidebar</span>
278   - </Button>
279   - );
280   -}
281   -
282   -function SidebarRail({ className, ...props }: React.ComponentProps<"button">) {
283   - const { toggleSidebar } = useSidebar();
284   -
285   - return (
286   - <button
287   - data-sidebar="rail"
288   - data-slot="sidebar-rail"
289   - aria-label="Toggle Sidebar"
290   - tabIndex={-1}
291   - onClick={toggleSidebar}
292   - title="Toggle Sidebar"
293   - className={cn(
294   - "hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] sm:flex",
295   - "in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize",
296   - "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize",
297   - "hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full",
298   - "[[data-side=left][data-collapsible=offcanvas]_&]:-right-2",
299   - "[[data-side=right][data-collapsible=offcanvas]_&]:-left-2",
300   - className,
301   - )}
302   - {...props}
303   - />
304   - );
305   -}
306   -
307   -function SidebarInset({ className, ...props }: React.ComponentProps<"main">) {
308   - return (
309   - <main
310   - data-slot="sidebar-inset"
311   - className={cn(
312   - "bg-background relative flex w-full flex-1 flex-col",
313   - "md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2",
314   - className,
315   - )}
316   - {...props}
317   - />
318   - );
319   -}
320   -
321   -function SidebarInput({
322   - className,
323   - ...props
324   -}: React.ComponentProps<typeof Input>) {
325   - return (
326   - <Input
327   - data-slot="sidebar-input"
328   - data-sidebar="input"
329   - className={cn("bg-background h-8 w-full shadow-none", className)}
330   - {...props}
331   - />
332   - );
333   -}
334   -
335   -function SidebarHeader({ className, ...props }: React.ComponentProps<"div">) {
336   - return (
337   - <div
338   - data-slot="sidebar-header"
339   - data-sidebar="header"
340   - className={cn("flex flex-col gap-2 p-2", className)}
341   - {...props}
342   - />
343   - );
344   -}
345   -
346   -function SidebarFooter({ className, ...props }: React.ComponentProps<"div">) {
347   - return (
348   - <div
349   - data-slot="sidebar-footer"
350   - data-sidebar="footer"
351   - className={cn("flex flex-col gap-2 p-2", className)}
352   - {...props}
353   - />
354   - );
355   -}
356   -
357   -function SidebarSeparator({
358   - className,
359   - ...props
360   -}: React.ComponentProps<typeof Separator>) {
361   - return (
362   - <Separator
363   - data-slot="sidebar-separator"
364   - data-sidebar="separator"
365   - className={cn("bg-sidebar-border mx-2 w-auto", className)}
366   - {...props}
367   - />
368   - );
369   -}
370   -
371   -function SidebarContent({ className, ...props }: React.ComponentProps<"div">) {
372   - return (
373   - <div
374   - data-slot="sidebar-content"
375   - data-sidebar="content"
376   - className={cn(
377   - "flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",
378   - className,
379   - )}
380   - {...props}
381   - />
382   - );
383   -}
384   -
385   -function SidebarGroup({ className, ...props }: React.ComponentProps<"div">) {
386   - return (
387   - <div
388   - data-slot="sidebar-group"
389   - data-sidebar="group"
390   - className={cn("relative flex w-full min-w-0 flex-col p-2", className)}
391   - {...props}
392   - />
393   - );
394   -}
395   -
396   -function SidebarGroupLabel({
397   - className,
398   - asChild = false,
399   - ...props
400   -}: React.ComponentProps<"div"> & { asChild?: boolean }) {
401   - const Comp = asChild ? Slot : "div";
402   -
403   - return (
404   - <Comp
405   - data-slot="sidebar-group-label"
406   - data-sidebar="group-label"
407   - className={cn(
408   - "text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
409   - "group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
410   - className,
411   - )}
412   - {...props}
413   - />
414   - );
415   -}
416   -
417   -function SidebarGroupAction({
418   - className,
419   - asChild = false,
420   - ...props
421   -}: React.ComponentProps<"button"> & { asChild?: boolean }) {
422   - const Comp = asChild ? Slot : "button";
423   -
424   - return (
425   - <Comp
426   - data-slot="sidebar-group-action"
427   - data-sidebar="group-action"
428   - className={cn(
429   - "text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
430   - // Increases the hit area of the button on mobile.
431   - "after:absolute after:-inset-2 md:after:hidden",
432   - "group-data-[collapsible=icon]:hidden",
433   - className,
434   - )}
435   - {...props}
436   - />
437   - );
438   -}
439   -
440   -function SidebarGroupContent({
441   - className,
442   - ...props
443   -}: React.ComponentProps<"div">) {
444   - return (
445   - <div
446   - data-slot="sidebar-group-content"
447   - data-sidebar="group-content"
448   - className={cn("w-full text-sm", className)}
449   - {...props}
450   - />
451   - );
452   -}
453   -
454   -function SidebarMenu({ className, ...props }: React.ComponentProps<"ul">) {
455   - return (
456   - <ul
457   - data-slot="sidebar-menu"
458   - data-sidebar="menu"
459   - className={cn("flex w-full min-w-0 flex-col gap-1", className)}
460   - {...props}
461   - />
462   - );
463   -}
464   -
465   -function SidebarMenuItem({ className, ...props }: React.ComponentProps<"li">) {
466   - return (
467   - <li
468   - data-slot="sidebar-menu-item"
469   - data-sidebar="menu-item"
470   - className={cn("group/menu-item relative", className)}
471   - {...props}
472   - />
473   - );
474   -}
475   -
476   -const sidebarMenuButtonVariants = cva(
477   - "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
478   - {
479   - variants: {
480   - variant: {
481   - default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
482   - outline:
483   - "bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]",
484   - },
485   - size: {
486   - default: "h-8 text-sm",
487   - sm: "h-7 text-xs",
488   - lg: "h-12 text-sm group-data-[collapsible=icon]:p-0!",
489   - },
490   - },
491   - defaultVariants: {
492   - variant: "default",
493   - size: "default",
494   - },
495   - },
496   -);
497   -
498   -function SidebarMenuButton({
499   - asChild = false,
500   - isActive = false,
501   - variant = "default",
502   - size = "default",
503   - tooltip,
504   - className,
505   - ...props
506   -}: React.ComponentProps<"button"> & {
507   - asChild?: boolean;
508   - isActive?: boolean;
509   - tooltip?: string | React.ComponentProps<typeof TooltipContent>;
510   -} & VariantProps<typeof sidebarMenuButtonVariants>) {
511   - const Comp = asChild ? Slot : "button";
512   - const { isMobile, state } = useSidebar();
513   -
514   - const button = (
515   - <Comp
516   - data-slot="sidebar-menu-button"
517   - data-sidebar="menu-button"
518   - data-size={size}
519   - data-active={isActive}
520   - className={cn(sidebarMenuButtonVariants({ variant, size }), className)}
521   - {...props}
522   - />
523   - );
524   -
525   - if (!tooltip) {
526   - return button;
527   - }
528   -
529   - if (typeof tooltip === "string") {
530   - tooltip = {
531   - children: tooltip,
532   - };
533   - }
534   -
535   - return (
536   - <Tooltip>
537   - <TooltipTrigger asChild>{button}</TooltipTrigger>
538   - <TooltipContent
539   - side="right"
540   - align="center"
541   - hidden={state !== "collapsed" || isMobile}
542   - {...tooltip}
543   - />
544   - </Tooltip>
545   - );
546   -}
547   -
548   -function SidebarMenuAction({
549   - className,
550   - asChild = false,
551   - showOnHover = false,
552   - ...props
553   -}: React.ComponentProps<"button"> & {
554   - asChild?: boolean;
555   - showOnHover?: boolean;
556   -}) {
557   - const Comp = asChild ? Slot : "button";
558   -
559   - return (
560   - <Comp
561   - data-slot="sidebar-menu-action"
562   - data-sidebar="menu-action"
563   - className={cn(
564   - "text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground peer-hover/menu-button:text-sidebar-accent-foreground absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
565   - // Increases the hit area of the button on mobile.
566   - "after:absolute after:-inset-2 md:after:hidden",
567   - "peer-data-[size=sm]/menu-button:top-1",
568   - "peer-data-[size=default]/menu-button:top-1.5",
569   - "peer-data-[size=lg]/menu-button:top-2.5",
570   - "group-data-[collapsible=icon]:hidden",
571   - showOnHover &&
572   - "peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 md:opacity-0",
573   - className,
574   - )}
575   - {...props}
576   - />
577   - );
578   -}
579   -
580   -function SidebarMenuBadge({
581   - className,
582   - ...props
583   -}: React.ComponentProps<"div">) {
584   - return (
585   - <div
586   - data-slot="sidebar-menu-badge"
587   - data-sidebar="menu-badge"
588   - className={cn(
589   - "text-sidebar-foreground pointer-events-none absolute right-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums select-none",
590   - "peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground",
591   - "peer-data-[size=sm]/menu-button:top-1",
592   - "peer-data-[size=default]/menu-button:top-1.5",
593   - "peer-data-[size=lg]/menu-button:top-2.5",
594   - "group-data-[collapsible=icon]:hidden",
595   - className,
596   - )}
597   - {...props}
598   - />
599   - );
600   -}
601   -
602   -function SidebarMenuSkeleton({
603   - className,
604   - showIcon = false,
605   - ...props
606   -}: React.ComponentProps<"div"> & {
607   - showIcon?: boolean;
608   -}) {
609   - // Random width between 50 to 90%.
610   - const width = React.useMemo(() => {
611   - return `${Math.floor(Math.random() * 40) + 50}%`;
612   - }, []);
613   -
614   - return (
615   - <div
616   - data-slot="sidebar-menu-skeleton"
617   - data-sidebar="menu-skeleton"
618   - className={cn("flex h-8 items-center gap-2 rounded-md px-2", className)}
619   - {...props}
620   - >
621   - {showIcon && (
622   - <Skeleton
623   - className="size-4 rounded-md"
624   - data-sidebar="menu-skeleton-icon"
625   - />
626   - )}
627   - <Skeleton
628   - className="h-4 max-w-(--skeleton-width) flex-1"
629   - data-sidebar="menu-skeleton-text"
630   - style={
631   - {
632   - "--skeleton-width": width,
633   - } as React.CSSProperties
634   - }
635   - />
636   - </div>
637   - );
638   -}
639   -
640   -function SidebarMenuSub({ className, ...props }: React.ComponentProps<"ul">) {
641   - return (
642   - <ul
643   - data-slot="sidebar-menu-sub"
644   - data-sidebar="menu-sub"
645   - className={cn(
646   - "border-sidebar-border mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l px-2.5 py-0.5",
647   - "group-data-[collapsible=icon]:hidden",
648   - className,
649   - )}
650   - {...props}
651   - />
652   - );
653   -}
654   -
655   -function SidebarMenuSubItem({
656   - className,
657   - ...props
658   -}: React.ComponentProps<"li">) {
659   - return (
660   - <li
661   - data-slot="sidebar-menu-sub-item"
662   - data-sidebar="menu-sub-item"
663   - className={cn("group/menu-sub-item relative", className)}
664   - {...props}
665   - />
666   - );
667   -}
668   -
669   -function SidebarMenuSubButton({
670   - asChild = false,
671   - size = "md",
672   - isActive = false,
673   - className,
674   - ...props
675   -}: React.ComponentProps<"a"> & {
676   - asChild?: boolean;
677   - size?: "sm" | "md";
678   - isActive?: boolean;
679   -}) {
680   - const Comp = asChild ? Slot : "a";
681   -
682   - return (
683   - <Comp
684   - data-slot="sidebar-menu-sub-button"
685   - data-sidebar="menu-sub-button"
686   - data-size={size}
687   - data-active={isActive}
688   - className={cn(
689   - "text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 outline-hidden focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
690   - "data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground",
691   - size === "sm" && "text-xs",
692   - size === "md" && "text-sm",
693   - "group-data-[collapsible=icon]:hidden",
694   - className,
695   - )}
696   - {...props}
697   - />
698   - );
699   -}
700   -
701   -export {
702   - Sidebar,
703   - SidebarContent,
704   - SidebarFooter,
705   - SidebarGroup,
706   - SidebarGroupAction,
707   - SidebarGroupContent,
708   - SidebarGroupLabel,
709   - SidebarHeader,
710   - SidebarInput,
711   - SidebarInset,
712   - SidebarMenu,
713   - SidebarMenuAction,
714   - SidebarMenuBadge,
715   - SidebarMenuButton,
716   - SidebarMenuItem,
717   - SidebarMenuSkeleton,
718   - SidebarMenuSub,
719   - SidebarMenuSubButton,
720   - SidebarMenuSubItem,
721   - SidebarProvider,
722   - SidebarRail,
723   - SidebarSeparator,
724   - SidebarTrigger,
725   - useSidebar,
726   -};
美国版/Food Labeling Management App React/src/app/components/ui/skeleton.tsx deleted
1   -import { cn } from "./utils";
2   -
3   -function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
4   - return (
5   - <div
6   - data-slot="skeleton"
7   - className={cn("bg-accent animate-pulse rounded-md", className)}
8   - {...props}
9   - />
10   - );
11   -}
12   -
13   -export { Skeleton };
美国版/Food Labeling Management App React/src/app/components/ui/slider.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import * as SliderPrimitive from "@radix-ui/react-slider";
5   -
6   -import { cn } from "./utils";
7   -
8   -function Slider({
9   - className,
10   - defaultValue,
11   - value,
12   - min = 0,
13   - max = 100,
14   - ...props
15   -}: React.ComponentProps<typeof SliderPrimitive.Root>) {
16   - const _values = React.useMemo(
17   - () =>
18   - Array.isArray(value)
19   - ? value
20   - : Array.isArray(defaultValue)
21   - ? defaultValue
22   - : [min, max],
23   - [value, defaultValue, min, max],
24   - );
25   -
26   - return (
27   - <SliderPrimitive.Root
28   - data-slot="slider"
29   - defaultValue={defaultValue}
30   - value={value}
31   - min={min}
32   - max={max}
33   - className={cn(
34   - "relative flex w-full touch-none items-center select-none data-[disabled]:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col",
35   - className,
36   - )}
37   - {...props}
38   - >
39   - <SliderPrimitive.Track
40   - data-slot="slider-track"
41   - className={cn(
42   - "bg-muted relative grow overflow-hidden rounded-full data-[orientation=horizontal]:h-4 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5",
43   - )}
44   - >
45   - <SliderPrimitive.Range
46   - data-slot="slider-range"
47   - className={cn(
48   - "bg-primary absolute data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full",
49   - )}
50   - />
51   - </SliderPrimitive.Track>
52   - {Array.from({ length: _values.length }, (_, index) => (
53   - <SliderPrimitive.Thumb
54   - data-slot="slider-thumb"
55   - key={index}
56   - className="border-primary bg-background ring-ring/50 block size-4 shrink-0 rounded-full border shadow-sm transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50"
57   - />
58   - ))}
59   - </SliderPrimitive.Root>
60   - );
61   -}
62   -
63   -export { Slider };
美国版/Food Labeling Management App React/src/app/components/ui/sonner.tsx deleted
1   -"use client";
2   -
3   -import { useTheme } from "next-themes";
4   -import { Toaster as Sonner, ToasterProps } from "sonner";
5   -
6   -const Toaster = ({ ...props }: ToasterProps) => {
7   - const { theme = "system" } = useTheme();
8   -
9   - return (
10   - <Sonner
11   - theme={theme as ToasterProps["theme"]}
12   - className="toaster group"
13   - style={
14   - {
15   - "--normal-bg": "var(--popover)",
16   - "--normal-text": "var(--popover-foreground)",
17   - "--normal-border": "var(--border)",
18   - } as React.CSSProperties
19   - }
20   - {...props}
21   - />
22   - );
23   -};
24   -
25   -export { Toaster };
美国版/Food Labeling Management App React/src/app/components/ui/switch.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import * as SwitchPrimitive from "@radix-ui/react-switch";
5   -
6   -import { cn } from "./utils";
7   -
8   -function Switch({
9   - className,
10   - ...props
11   -}: React.ComponentProps<typeof SwitchPrimitive.Root>) {
12   - return (
13   - <SwitchPrimitive.Root
14   - data-slot="switch"
15   - className={cn(
16   - "peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-switch-background focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
17   - className,
18   - )}
19   - {...props}
20   - >
21   - <SwitchPrimitive.Thumb
22   - data-slot="switch-thumb"
23   - className={cn(
24   - "bg-card dark:data-[state=unchecked]:bg-card-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0",
25   - )}
26   - />
27   - </SwitchPrimitive.Root>
28   - );
29   -}
30   -
31   -export { Switch };
美国版/Food Labeling Management App React/src/app/components/ui/table.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -
5   -import { cn } from "./utils";
6   -
7   -function Table({ className, ...props }: React.ComponentProps<"table">) {
8   - return (
9   - <div
10   - data-slot="table-container"
11   - className="relative w-full overflow-x-auto"
12   - >
13   - <table
14   - data-slot="table"
15   - className={cn("w-full caption-bottom text-sm", className)}
16   - {...props}
17   - />
18   - </div>
19   - );
20   -}
21   -
22   -function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
23   - return (
24   - <thead
25   - data-slot="table-header"
26   - className={cn("[&_tr]:border-b", className)}
27   - {...props}
28   - />
29   - );
30   -}
31   -
32   -function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
33   - return (
34   - <tbody
35   - data-slot="table-body"
36   - className={cn("[&_tr:last-child]:border-0", className)}
37   - {...props}
38   - />
39   - );
40   -}
41   -
42   -function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
43   - return (
44   - <tfoot
45   - data-slot="table-footer"
46   - className={cn(
47   - "bg-muted/50 border-t font-medium [&>tr]:last:border-b-0",
48   - className,
49   - )}
50   - {...props}
51   - />
52   - );
53   -}
54   -
55   -function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
56   - return (
57   - <tr
58   - data-slot="table-row"
59   - className={cn(
60   - "hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",
61   - className,
62   - )}
63   - {...props}
64   - />
65   - );
66   -}
67   -
68   -function TableHead({ className, ...props }: React.ComponentProps<"th">) {
69   - return (
70   - <th
71   - data-slot="table-head"
72   - className={cn(
73   - "text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
74   - className,
75   - )}
76   - {...props}
77   - />
78   - );
79   -}
80   -
81   -function TableCell({ className, ...props }: React.ComponentProps<"td">) {
82   - return (
83   - <td
84   - data-slot="table-cell"
85   - className={cn(
86   - "p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
87   - className,
88   - )}
89   - {...props}
90   - />
91   - );
92   -}
93   -
94   -function TableCaption({
95   - className,
96   - ...props
97   -}: React.ComponentProps<"caption">) {
98   - return (
99   - <caption
100   - data-slot="table-caption"
101   - className={cn("text-muted-foreground mt-4 text-sm", className)}
102   - {...props}
103   - />
104   - );
105   -}
106   -
107   -export {
108   - Table,
109   - TableHeader,
110   - TableBody,
111   - TableFooter,
112   - TableHead,
113   - TableRow,
114   - TableCell,
115   - TableCaption,
116   -};
美国版/Food Labeling Management App React/src/app/components/ui/tabs.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import * as TabsPrimitive from "@radix-ui/react-tabs";
5   -
6   -import { cn } from "./utils";
7   -
8   -function Tabs({
9   - className,
10   - ...props
11   -}: React.ComponentProps<typeof TabsPrimitive.Root>) {
12   - return (
13   - <TabsPrimitive.Root
14   - data-slot="tabs"
15   - className={cn("flex flex-col gap-2", className)}
16   - {...props}
17   - />
18   - );
19   -}
20   -
21   -function TabsList({
22   - className,
23   - ...props
24   -}: React.ComponentProps<typeof TabsPrimitive.List>) {
25   - return (
26   - <TabsPrimitive.List
27   - data-slot="tabs-list"
28   - className={cn(
29   - "bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-xl p-[3px] flex",
30   - className,
31   - )}
32   - {...props}
33   - />
34   - );
35   -}
36   -
37   -function TabsTrigger({
38   - className,
39   - ...props
40   -}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
41   - return (
42   - <TabsPrimitive.Trigger
43   - data-slot="tabs-trigger"
44   - className={cn(
45   - "data-[state=active]:bg-card dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-xl border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
46   - className,
47   - )}
48   - {...props}
49   - />
50   - );
51   -}
52   -
53   -function TabsContent({
54   - className,
55   - ...props
56   -}: React.ComponentProps<typeof TabsPrimitive.Content>) {
57   - return (
58   - <TabsPrimitive.Content
59   - data-slot="tabs-content"
60   - className={cn("flex-1 outline-none", className)}
61   - {...props}
62   - />
63   - );
64   -}
65   -
66   -export { Tabs, TabsList, TabsTrigger, TabsContent };
美国版/Food Labeling Management App React/src/app/components/ui/textarea.tsx deleted
1   -import * as React from "react";
2   -
3   -import { cn } from "./utils";
4   -
5   -function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
6   - return (
7   - <textarea
8   - data-slot="textarea"
9   - className={cn(
10   - "resize-none border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-input-background px-3 py-2 text-base transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
11   - className,
12   - )}
13   - {...props}
14   - />
15   - );
16   -}
17   -
18   -export { Textarea };
美国版/Food Labeling Management App React/src/app/components/ui/toggle-group.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
5   -import { type VariantProps } from "class-variance-authority";
6   -
7   -import { cn } from "./utils";
8   -import { toggleVariants } from "./toggle";
9   -
10   -const ToggleGroupContext = React.createContext<
11   - VariantProps<typeof toggleVariants>
12   ->({
13   - size: "default",
14   - variant: "default",
15   -});
16   -
17   -function ToggleGroup({
18   - className,
19   - variant,
20   - size,
21   - children,
22   - ...props
23   -}: React.ComponentProps<typeof ToggleGroupPrimitive.Root> &
24   - VariantProps<typeof toggleVariants>) {
25   - return (
26   - <ToggleGroupPrimitive.Root
27   - data-slot="toggle-group"
28   - data-variant={variant}
29   - data-size={size}
30   - className={cn(
31   - "group/toggle-group flex w-fit items-center rounded-md data-[variant=outline]:shadow-xs",
32   - className,
33   - )}
34   - {...props}
35   - >
36   - <ToggleGroupContext.Provider value={{ variant, size }}>
37   - {children}
38   - </ToggleGroupContext.Provider>
39   - </ToggleGroupPrimitive.Root>
40   - );
41   -}
42   -
43   -function ToggleGroupItem({
44   - className,
45   - children,
46   - variant,
47   - size,
48   - ...props
49   -}: React.ComponentProps<typeof ToggleGroupPrimitive.Item> &
50   - VariantProps<typeof toggleVariants>) {
51   - const context = React.useContext(ToggleGroupContext);
52   -
53   - return (
54   - <ToggleGroupPrimitive.Item
55   - data-slot="toggle-group-item"
56   - data-variant={context.variant || variant}
57   - data-size={context.size || size}
58   - className={cn(
59   - toggleVariants({
60   - variant: context.variant || variant,
61   - size: context.size || size,
62   - }),
63   - "min-w-0 flex-1 shrink-0 rounded-none shadow-none first:rounded-l-md last:rounded-r-md focus:z-10 focus-visible:z-10 data-[variant=outline]:border-l-0 data-[variant=outline]:first:border-l",
64   - className,
65   - )}
66   - {...props}
67   - >
68   - {children}
69   - </ToggleGroupPrimitive.Item>
70   - );
71   -}
72   -
73   -export { ToggleGroup, ToggleGroupItem };
美国版/Food Labeling Management App React/src/app/components/ui/toggle.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import * as TogglePrimitive from "@radix-ui/react-toggle";
5   -import { cva, type VariantProps } from "class-variance-authority";
6   -
7   -import { cn } from "./utils";
8   -
9   -const toggleVariants = cva(
10   - "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium hover:bg-muted hover:text-muted-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] outline-none transition-[color,box-shadow] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive whitespace-nowrap",
11   - {
12   - variants: {
13   - variant: {
14   - default: "bg-transparent",
15   - outline:
16   - "border border-input bg-transparent hover:bg-accent hover:text-accent-foreground",
17   - },
18   - size: {
19   - default: "h-9 px-2 min-w-9",
20   - sm: "h-8 px-1.5 min-w-8",
21   - lg: "h-10 px-2.5 min-w-10",
22   - },
23   - },
24   - defaultVariants: {
25   - variant: "default",
26   - size: "default",
27   - },
28   - },
29   -);
30   -
31   -function Toggle({
32   - className,
33   - variant,
34   - size,
35   - ...props
36   -}: React.ComponentProps<typeof TogglePrimitive.Root> &
37   - VariantProps<typeof toggleVariants>) {
38   - return (
39   - <TogglePrimitive.Root
40   - data-slot="toggle"
41   - className={cn(toggleVariants({ variant, size, className }))}
42   - {...props}
43   - />
44   - );
45   -}
46   -
47   -export { Toggle, toggleVariants };
美国版/Food Labeling Management App React/src/app/components/ui/tooltip.tsx deleted
1   -"use client";
2   -
3   -import * as React from "react";
4   -import * as TooltipPrimitive from "@radix-ui/react-tooltip";
5   -
6   -import { cn } from "./utils";
7   -
8   -function TooltipProvider({
9   - delayDuration = 0,
10   - ...props
11   -}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
12   - return (
13   - <TooltipPrimitive.Provider
14   - data-slot="tooltip-provider"
15   - delayDuration={delayDuration}
16   - {...props}
17   - />
18   - );
19   -}
20   -
21   -function Tooltip({
22   - ...props
23   -}: React.ComponentProps<typeof TooltipPrimitive.Root>) {
24   - return (
25   - <TooltipProvider>
26   - <TooltipPrimitive.Root data-slot="tooltip" {...props} />
27   - </TooltipProvider>
28   - );
29   -}
30   -
31   -function TooltipTrigger({
32   - ...props
33   -}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
34   - return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
35   -}
36   -
37   -function TooltipContent({
38   - className,
39   - sideOffset = 0,
40   - children,
41   - ...props
42   -}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
43   - return (
44   - <TooltipPrimitive.Portal>
45   - <TooltipPrimitive.Content
46   - data-slot="tooltip-content"
47   - sideOffset={sideOffset}
48   - className={cn(
49   - "bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
50   - className,
51   - )}
52   - {...props}
53   - >
54   - {children}
55   - <TooltipPrimitive.Arrow className="bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" />
56   - </TooltipPrimitive.Content>
57   - </TooltipPrimitive.Portal>
58   - );
59   -}
60   -
61   -export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
美国版/Food Labeling Management App React/src/app/components/ui/use-mobile.ts deleted
1   -import * as React from "react";
2   -
3   -const MOBILE_BREAKPOINT = 768;
4   -
5   -export function useIsMobile() {
6   - const [isMobile, setIsMobile] = React.useState<boolean | undefined>(
7   - undefined,
8   - );
9   -
10   - React.useEffect(() => {
11   - const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
12   - const onChange = () => {
13   - setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
14   - };
15   - mql.addEventListener("change", onChange);
16   - setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
17   - return () => mql.removeEventListener("change", onChange);
18   - }, []);
19   -
20   - return !!isMobile;
21   -}
美国版/Food Labeling Management App React/src/app/components/ui/utils.ts deleted
1   -import { clsx, type ClassValue } from "clsx";
2   -import { twMerge } from "tailwind-merge";
3   -
4   -export function cn(...inputs: ClassValue[]) {
5   - return twMerge(clsx(inputs));
6   -}
美国版/Food Labeling Management App React/src/app/contexts/LanguageContext.tsx deleted
1   -import { createContext, useContext, useState, ReactNode } from "react";
2   -
3   -type Language = "en" | "zh";
4   -
5   -interface LanguageContextType {
6   - language: Language;
7   - setLanguage: (lang: Language) => void;
8   - t: (key: string) => string;
9   -}
10   -
11   -const LanguageContext = createContext<LanguageContextType | undefined>(undefined);
12   -
13   -export function LanguageProvider({ children }: { children: ReactNode }) {
14   - const [language, setLanguage] = useState<Language>(
15   - (localStorage.getItem("language") as Language) || "en"
16   - );
17   -
18   - const handleSetLanguage = (lang: Language) => {
19   - setLanguage(lang);
20   - localStorage.setItem("language", lang);
21   - };
22   -
23   - const t = (key: string): string => {
24   - const translations = language === "zh" ? translationsZh : translationsEn;
25   - return translations[key] || key;
26   - };
27   -
28   - return (
29   - <LanguageContext.Provider value={{ language, setLanguage: handleSetLanguage, t }}>
30   - {children}
31   - </LanguageContext.Provider>
32   - );
33   -}
34   -
35   -export function useLanguage() {
36   - const context = useContext(LanguageContext);
37   - if (!context) {
38   - throw new Error("useLanguage must be used within a LanguageProvider");
39   - }
40   - return context;
41   -}
42   -
43   -// English translations
44   -const translationsEn: Record<string, string> = {
45   - // Common
46   - "common.back": "Back",
47   - "common.search": "Search",
48   - "common.save": "Save",
49   - "common.cancel": "Cancel",
50   - "common.delete": "Delete",
51   - "common.edit": "Edit",
52   - "common.confirm": "Confirm",
53   - "common.loading": "Loading...",
54   - "common.online": "Online",
55   - "common.offline": "Offline",
56   - "common.note": "Note",
57   -
58   - // Login
59   - "login.title": "Sign In",
60   - "login.subtitle": "Enter your credentials to access the system",
61   - "login.employeeId": "Employee ID",
62   - "login.password": "Password",
63   - "login.selectLocation": "Select Location",
64   - "login.signIn": "Sign In",
65   - "login.signingIn": "Signing In...",
66   - "login.welcome": "Welcome!",
67   - "login.loginSuccess": "Login successful",
68   -
69   - // Dashboard
70   - "dashboard.todaysLabels": "Today's Labels",
71   - "dashboard.pendingPrint": "pending print",
72   - "dashboard.openTasks": "Open Tasks",
73   - "dashboard.dueToday": "due today",
74   - "dashboard.alerts": "Alerts",
75   - "dashboard.expiringSoon": "Expiring soon",
76   - "dashboard.devicesStatus": "Devices Status",
77   - "dashboard.quickActions": "Quick Actions",
78   - "dashboard.scanAndPrint": "Scan & Print",
79   - "dashboard.batchPrint": "Batch Print",
80   - "dashboard.recordTemperature": "Record Temperature",
81   - "dashboard.reportWaste": "Report Waste",
82   -
83   - // Labels
84   - "labels.title": "Labels",
85   - "labels.selectType": "Select a label type to print",
86   - "labels.selectFood": "Select food item to print label",
87   - "labels.foodItems": "food items",
88   - "labels.searchFood": "Search food items...",
89   - "labels.noFoodFound": "No Food Items Found",
90   - "labels.noFoodDesc": "Try adjusting your search or browse by category",
91   - "labels.category": "Category",
92   -
93   - // Labels - Tabs & History
94   - "labels.tabs.create": "Create",
95   - "labels.tabs.history": "History",
96   - "labels.history.subtitle": "View printed labels",
97   - "labels.printedBy": "Printed by",
98   - "labels.status.active": "Active",
99   - "labels.status.expired": "Expired",
100   - "labels.history.empty.title": "No Labels Yet",
101   - "labels.history.empty.desc": "Labels you print will appear here",
102   -
103   - // Labels - Preview & Print
104   - "labels.preview.title": "Label Preview",
105   - "labels.preview.subtitle": "Review before printing",
106   - "labels.preview.labelPreview": "Label Preview",
107   - "labels.preview.printedBy": "Printed By",
108   - "labels.preview.printDate": "Print Date",
109   - "labels.preview.note": "This preview shows how the label will appear when printed. Please verify all information before printing.",
110   - "labels.print.button": "Print Label",
111   - "labels.print.printing": "Printing...",
112   - "labels.print.success": "Label printed successfully!",
113   -
114   - // Label Types
115   - "labelType.nutrition.name": "Nutrition Label",
116   - "labelType.nutrition.desc": "Print nutrition facts and serving information",
117   - "labelType.allergen.name": "Allergen Label",
118   - "labelType.allergen.desc": "Display allergen warnings and cross-contamination info",
119   - "labelType.storage.name": "Storage Label",
120   - "labelType.storage.desc": "Show storage temperature and handling instructions",
121   - "labelType.expiry.name": "Expiry Date Label",
122   - "labelType.expiry.desc": "Print expiration dates and best-before information",
123   - "labelType.batch.name": "Batch Tracking Label",
124   - "labelType.batch.desc": "Track batch numbers and supplier information",
125   - "labelType.preparation.name": "Preparation Label",
126   - "labelType.preparation.desc": "Document prep date, time, and responsible staff",
127   -
128   - // Label Preview Headers
129   - "labelPreview.nutrition": "NUTRITION FACTS",
130   - "labelPreview.allergen": "ALLERGEN INFORMATION",
131   - "labelPreview.storage": "STORAGE INSTRUCTIONS",
132   - "labelPreview.expiry": "EXPIRATION DATE",
133   - "labelPreview.batch": "BATCH TRACKING",
134   - "labelPreview.preparation": "PREPARATION INFO",
135   -
136   - // Nutrition Label Fields
137   - "nutrition.servingSize": "Serving Size",
138   - "nutrition.calories": "Calories",
139   - "nutrition.totalFat": "Total Fat",
140   - "nutrition.saturatedFat": "Saturated Fat",
141   - "nutrition.transFat": "Trans Fat",
142   - "nutrition.cholesterol": "Cholesterol",
143   - "nutrition.sodium": "Sodium",
144   - "nutrition.totalCarb": "Total Carbohydrate",
145   - "nutrition.dietaryFiber": "Dietary Fiber",
146   - "nutrition.sugars": "Sugars",
147   - "nutrition.protein": "Protein",
148   -
149   - // Allergen Label Fields
150   - "allergen.contains": "Contains",
151   - "allergen.mayContain": "May Contain",
152   - "allergen.crossContamination": "Cross-Contamination Risk",
153   - "allergen.preparedIn": "Prepared In",
154   - "allergen.riskLow": "Low",
155   - "allergen.riskMedium": "Medium",
156   - "allergen.riskHigh": "High",
157   -
158   - // Storage Label Fields
159   - "storage.temperature": "Storage Temperature",
160   - "storage.location": "Storage Location",
161   - "storage.shelfLife": "Shelf Life",
162   - "storage.handling": "Handling",
163   - "storage.tempRange": "°F (0-4°C)",
164   - "storage.daysFromPrep": "days from prep date",
165   - "storage.instructions": "Keep refrigerated. Use clean utensils.",
166   -
167   - // Expiry Label Fields
168   - "expiry.prepDate": "Prep Date",
169   - "expiry.expiryDate": "Expiry Date",
170   - "expiry.batchNumber": "Batch Number",
171   - "expiry.preparedBy": "Prepared By",
172   -
173   - // Batch Label Fields
174   - "batch.batchNumber": "Batch Number",
175   - "batch.productionDate": "Production Date",
176   - "batch.supplier": "Supplier",
177   - "batch.lotNumber": "Lot Number",
178   - "batch.supplierName": "Fresh Foods Co.",
179   -
180   - // Preparation Label Fields
181   - "prep.prepDate": "Prep Date",
182   - "prep.prepTime": "Prep Time",
183   - "prep.preparedBy": "Prepared By",
184   - "prep.location": "Location",
185   - "prep.useBy": "Use By",
186   -
187   - // Food Categories
188   - "category.meat": "Meat",
189   - "category.salads": "Salads",
190   - "category.seafood": "Seafood",
191   - "category.sauces": "Sauces",
192   - "category.vegetables": "Vegetables",
193   - "category.desserts": "Desserts",
194   - "category.prepared": "Prepared Foods",
195   - "category.frozen": "Frozen Foods",
196   - "category.dairy": "Dairy",
197   - "category.bakery": "Bakery",
198   - "category.beverages": "Beverages",
199   - "category.soups": "Soups",
200   -
201   - // Food Items
202   - "food.chickenBreast": "Grilled Chicken Breast",
203   - "food.chickenBreast.desc": "Fresh grilled chicken breast, boneless",
204   - "food.caesarSalad": "Caesar Salad",
205   - "food.caesarSalad.desc": "Classic Caesar salad with romaine lettuce",
206   - "food.salmonFillet": "Fresh Salmon Fillet",
207   - "food.salmonFillet.desc": "Atlantic salmon fillet, skin-on",
208   - "food.beefPatties": "Ground Beef Patties",
209   - "food.beefPatties.desc": "Fresh ground beef patties, 80/20",
210   - "food.marinaraSauce": "Marinara Sauce",
211   - "food.marinaraSauce.desc": "House-made marinara sauce",
212   - "food.vegetables": "Pre-cut Vegetables",
213   - "food.vegetables.desc": "Mixed fresh vegetables, pre-cut",
214   - "food.brownie": "Chocolate Brownie",
215   - "food.brownie.desc": "Rich chocolate brownie with walnuts",
216   - "food.shrimpPasta": "Shrimp Pasta",
217   - "food.shrimpPasta.desc": "Linguine with shrimp in garlic sauce",
218   - "food.iceCream": "Vanilla Ice Cream",
219   - "food.iceCream.desc": "Premium vanilla ice cream",
220   - "food.clubSandwich": "Club Sandwich",
221   - "food.clubSandwich.desc": "Triple-decker club sandwich",
222   - "food.yogurt": "Greek Yogurt",
223   - "food.yogurt.desc": "Plain Greek yogurt, full fat",
224   - "food.bread": "Whole Wheat Bread",
225   - "food.bread.desc": "Freshly baked whole wheat bread",
226   - "food.smoothie": "Mixed Berry Smoothie",
227   - "food.smoothie.desc": "Fresh mixed berry smoothie",
228   - "food.turkey": "Roasted Turkey Breast",
229   - "food.turkey.desc": "Oven-roasted turkey breast",
230   - "food.tomatoSoup": "Tomato Soup",
231   - "food.tomatoSoup.desc": "Creamy tomato soup with basil",
232   -
233   - // Label Fields
234   - "field.servingSize": "Serving Size",
235   - "field.servingSize.placeholder": "e.g., 100g, 1 cup",
236   - "field.calories": "Calories (per serving)",
237   - "field.calories.placeholder": "e.g., 250",
238   - "field.totalFat": "Total Fat (g)",
239   - "field.totalFat.placeholder": "e.g., 15",
240   - "field.protein": "Protein (g)",
241   - "field.protein.placeholder": "e.g., 20",
242   - "field.ingredients": "Ingredients",
243   - "field.ingredients.placeholder": "List all ingredients...",
244   - "field.allergens": "Contains Allergens",
245   - "field.allergens.select": "Select allergens",
246   - "field.crossContamination": "Cross-Contamination Risk",
247   - "field.crossContamination.select": "Select risk level",
248   - "field.additionalInfo": "Additional Information",
249   - "field.additionalInfo.placeholder": "Any additional allergen information...",
250   - "field.storageTemp": "Storage Temperature",
251   - "field.storageTemp.select": "Select temperature",
252   - "field.storageLocation": "Storage Location",
253   - "field.storageLocation.select": "Select location",
254   - "field.handlingInstructions": "Handling Instructions",
255   - "field.handlingInstructions.placeholder": "Describe proper handling...",
256   - "field.prepDate": "Preparation Date",
257   - "field.expiryDate": "Expiry Date",
258   - "field.batchNumber": "Batch Number",
259   - "field.batchNumber.placeholder": "e.g., GB-20260227-001",
260   - "field.productionDate": "Production Date",
261   - "field.lotNumber": "Lot Number",
262   - "field.lotNumber.placeholder": "Optional lot number",
263   - "field.supplier": "Supplier",
264   - "field.supplier.placeholder": "Supplier name",
265   - "field.prepTime": "Preparation Time",
266   - "field.prepTime.placeholder": "e.g., 2:30 PM",
267   - "field.prepBy": "Prepared By",
268   - "field.prepBy.placeholder": "Staff name",
269   - "field.useBy": "Use By Date",
270   -
271   - // Label Queue
272   - "queue.title": "Print Queue",
273   - "queue.searchQueue": "Search print queue...",
274   - "queue.all": "All",
275   - "queue.pending": "Pending",
276   - "queue.printing": "Printing",
277   - "queue.completed": "Completed",
278   - "queue.failed": "Failed",
279   - "queue.noQueue": "Queue is Empty",
280   - "queue.noQueueDesc": "There are no print jobs in the queue.",
281   - "queue.batch": "Batch",
282   - "queue.printer": "Printer",
283   - "queue.time": "Time",
284   - "queue.cancel": "Cancel Job",
285   - "queue.retry": "Retry",
286   - "queue.view": "View Details",
287   -
288   - // Tasks
289   - "tasks.title": "Tasks",
290   - "tasks.searchTasks": "Search tasks...",
291   - "tasks.all": "All",
292   - "tasks.pending": "Pending",
293   - "tasks.inProgress": "In Progress",
294   - "tasks.completed": "Completed",
295   - "tasks.noTasks": "No Tasks Found",
296   - "tasks.noTasksDesc": "There are no tasks matching your search criteria.",
297   - "tasks.dueDate": "Due",
298   - "tasks.priority": "Priority",
299   - "tasks.high": "High",
300   - "tasks.medium": "Medium",
301   - "tasks.low": "Low",
302   - "tasks.startTask": "Start Task",
303   -
304   - // Task Types
305   - "tasks.type.temperature": "Temperature Check",
306   - "tasks.type.hygiene": "Hygiene Check",
307   - "tasks.type.equipment": "Equipment Check",
308   -
309   - // Task Status
310   - "tasks.status.open": "Open",
311   - "tasks.status.completed": "Completed",
312   - "tasks.status.overdue": "Overdue",
313   -
314   - // Task Names
315   - "tasks.task1.name": "Refrigerator Temperature Check",
316   - "tasks.task2.name": "Kitchen Hygiene Inspection",
317   - "tasks.task3.name": "Freezer Temperature Check",
318   - "tasks.task4.name": "Equipment Safety Check",
319   - "tasks.task5.name": "Morning Temperature Log",
320   - "tasks.task6.name": "Prep Area Hygiene",
321   -
322   - // Task Execute
323   - "task.execute.taskDetails": "Task Details",
324   - "task.execute.description": "Description",
325   - "task.execute.steps": "Steps",
326   - "task.execute.step": "Step",
327   - "task.execute.complete": "Complete",
328   - "task.execute.recordTemp": "Record Temperature",
329   - "task.execute.temp": "Temperature",
330   - "task.execute.tempPlaceholder": "Enter temperature in °F",
331   - "task.execute.location": "Location",
332   - "task.execute.notes": "Notes (Optional)",
333   - "task.execute.notesPlaceholder": "Add any additional notes...",
334   - "task.execute.reportIssue": "Report Issue",
335   - "task.execute.completeTask": "Complete Task",
336   - "task.execute.completing": "Completing...",
337   - "task.execute.enterTemp": "Please enter temperature",
338   - "task.execute.success": "Task completed successfully!",
339   -
340   - // More
341   - "more.title": "More",
342   - "more.profile": "My Profile",
343   - "more.profile.desc": "View and edit your profile",
344   - "more.training": "Training Materials",
345   - "more.training.desc": "Learn and improve your skills",
346   - "more.printers": "Printer Settings",
347   - "more.printers.desc": "Manage connected printers",
348   - "more.location": "Location",
349   - "more.location.desc": "Change your work location",
350   - "more.sync": "Sync Status",
351   - "more.sync.desc": "View sync status and data",
352   - "more.language": "Language / 语言",
353   - "more.language.desc": "Change app language",
354   - "more.support": "Support",
355   - "more.support.desc": "Get help and contact support",
356   - "more.logout": "Logout",
357   -
358   - // Language Settings
359   - "language.title": "Language Settings",
360   - "language.selectLanguage": "Select Language",
361   - "language.english": "English",
362   - "language.chinese": "中文(简体)",
363   - "language.changed": "Language changed successfully",
364   -
365   - // Profile
366   - "profile.title": "My Profile",
367   - "profile.info": "Profile Information",
368   - "profile.name": "Name",
369   - "profile.employeeId": "Employee ID",
370   - "profile.role": "Role",
371   - "profile.department": "Department",
372   - "profile.email": "Email",
373   - "profile.phone": "Phone",
374   - "profile.workSchedule": "Work Schedule",
375   - "profile.preferences": "Preferences",
376   - "profile.notifications": "Push Notifications",
377   - "profile.sound": "Sound Alerts",
378   - "profile.saveChanges": "Save Changes",
379   - "profile.saving": "Saving...",
380   -
381   - // Printers
382   - "printers.title": "Printer Settings",
383   - "printers.connected": "Connected Printers",
384   - "printers.noPrinters": "No Printers Connected",
385   - "printers.noPrintersDesc": "No printers are currently connected to the system.",
386   - "printers.addPrinter": "Add Printer",
387   - "printers.available": "printers available",
388   - "printers.online": "Online",
389   - "printers.offline": "Offline",
390   - "printers.error": "Error",
391   - "printers.model": "Model",
392   - "printers.ip": "IP Address",
393   - "printers.status": "Status",
394   - "printers.setDefault": "Set as Default",
395   - "printers.default": "Default",
396   - "printers.testPrint": "Test Print",
397   -
398   - // Location
399   - "location.title": "Location",
400   - "location.current": "Current Location",
401   - "location.selectLocation": "Select Location",
402   - "location.change": "Change Location",
403   - "location.changing": "Changing...",
404   -
405   - // Sync Status
406   - "sync.title": "Sync Status",
407   - "sync.lastSync": "Last Sync",
408   - "sync.status": "Status",
409   - "sync.synced": "All data synced",
410   - "sync.syncNow": "Sync Now",
411   - "sync.syncing": "Syncing...",
412   - "sync.dataOverview": "Data Overview",
413   - "sync.labels": "Labels",
414   - "sync.tasks": "Tasks",
415   - "sync.records": "Records",
416   - "sync.pending": "Pending",
417   -
418   - // Support
419   - "support.title": "Support",
420   - "support.needHelp": "Need Help?",
421   - "support.needHelpDesc": "Contact our support team for assistance",
422   - "support.email": "Email Support",
423   - "support.phone": "Phone Support",
424   - "support.hours": "Mon-Fri, 9AM-6PM EST",
425   - "support.resources": "Resources",
426   - "support.userGuide": "User Guide",
427   - "support.userGuide.desc": "Learn how to use the app",
428   - "support.faq": "FAQ",
429   - "support.faq.desc": "Frequently asked questions",
430   - "support.training": "Training Videos",
431   - "support.training.desc": "Watch tutorial videos",
432   - "support.appInfo": "App Information",
433   - "support.version": "Version",
434   - "support.buildNumber": "Build Number",
435   -
436   - // Bottom Navigation
437   - "nav.dashboard": "Dashboard",
438   - "nav.labels": "Labels",
439   - "nav.tasks": "Tasks",
440   - "nav.more": "More",
441   -
442   - // Training
443   - "training.title": "Training Materials",
444   - "training.subtitle": "Learn and improve your skills",
445   - "training.completed": "Completed",
446   - "training.inProgress": "In Progress",
447   - "training.all": "All",
448   - "training.articles": "Articles",
449   - "training.videos": "Videos",
450   - "training.article": "Article",
451   - "training.video": "Video",
452   - "training.search": "Search training materials...",
453   - "training.noResults": "No Training Materials Found",
454   - "training.noResultsDesc": "Try adjusting your search criteria",
455   - "training.overview": "Overview",
456   - "training.keySteps": "Key Steps",
457   - "training.keyPoints": "Key Points",
458   - "training.resources": "Additional Resources",
459   - "training.downloadPDF": "Download PDF Guide",
460   - "training.printChecklist": "Print Checklist",
461   - "training.markComplete": "Mark as Complete",
462   - "training.marking": "Marking...",
463   - "training.completedSuccess": "Training completed successfully!",
464   - "training.notFound": "Training material not found",
465   - "training.videoNotSupported": "Your browser does not support video playback",
466   -
467   - // Training Categories
468   - "training.category.safety": "Food Safety",
469   - "training.category.operations": "Operations",
470   - "training.category.equipment": "Equipment",
471   - "training.category.compliance": "Compliance",
472   -
473   - // Training Items
474   - "training.foodSafety.title": "Food Safety Basics",
475   - "training.foodSafety.desc": "Essential food safety principles and practices",
476   - "training.foodSafety.content": "Food safety is critical in all food service operations. This comprehensive guide covers the fundamental principles of maintaining food safety, preventing contamination, and ensuring compliance with health regulations.\n\nUnderstanding and implementing proper food safety practices protects your customers, your business, and your reputation. Every team member plays a vital role in maintaining food safety standards.",
477   - "training.foodSafety.content.point1": "Always maintain proper handwashing and hygiene",
478   - "training.foodSafety.content.point2": "Monitor and record temperatures consistently",
479   - "training.foodSafety.content.point3": "Follow FIFO (First In, First Out) procedures",
480   - "training.foodSafety.step1": "Wash hands thoroughly with soap and warm water for at least 20 seconds before handling food",
481   - "training.foodSafety.step2": "Check and record food temperatures at regular intervals using calibrated thermometers",
482   - "training.foodSafety.step3": "Store raw and cooked foods separately to prevent cross-contamination",
483   - "training.foodSafety.step4": "Label all food items with preparation and expiry dates",
484   - "training.foodSafety.step5": "Clean and sanitize all work surfaces and equipment between tasks",
485   -
486   - "training.labelPrinting.title": "Label Printing Guide",
487   - "training.labelPrinting.desc": "Step-by-step guide to printing food labels",
488   - "training.labelPrinting.content": "Learn how to efficiently use the label printing system to create accurate, compliant food labels. This video tutorial walks you through the complete process from selecting label types to printing and applying labels.\n\nProper labeling is essential for food safety, traceability, and regulatory compliance.",
489   - "training.labelPrinting.content.point1": "Select the appropriate label type for your needs",
490   - "training.labelPrinting.content.point2": "Verify all information before printing",
491   - "training.labelPrinting.content.point3": "Apply labels immediately after printing",
492   -
493   - "training.temperature.title": "Temperature Recording",
494   - "training.temperature.desc": "Proper procedures for monitoring food temperatures",
495   - "training.temperature.content": "Accurate temperature monitoring is one of the most important food safety controls. This guide explains when and how to record temperatures, acceptable temperature ranges, and corrective actions when temperatures are out of range.\n\nConsistent temperature monitoring prevents foodborne illness and ensures food quality.",
496   - "training.temperature.content.point1": "Use calibrated thermometers for all measurements",
497   - "training.temperature.content.point2": "Record temperatures at specified intervals",
498   - "training.temperature.content.point3": "Take immediate action if temperatures are out of safe range",
499   - "training.temperature.step1": "Calibrate your thermometer daily before first use",
500   - "training.temperature.step2": "Insert thermometer into the thickest part of the food, avoiding bones or fat",
501   - "training.temperature.step3": "Wait for the reading to stabilize before recording",
502   - "training.temperature.step4": "Document temperature, time, location, and your initials in the system",
503   -
504   - "training.haccp.title": "HACCP Principles",
505   - "training.haccp.desc": "Understanding Hazard Analysis Critical Control Points",
506   - "training.haccp.content": "HACCP (Hazard Analysis and Critical Control Points) is a systematic approach to food safety. This video explains the seven principles of HACCP and how they apply to your daily work.\n\nHACCP helps identify, evaluate, and control food safety hazards throughout the food production process.",
507   - "training.haccp.content.point1": "Identify potential hazards in food preparation",
508   - "training.haccp.content.point2": "Establish critical control points",
509   - "training.haccp.content.point3": "Monitor and document control measures",
510   -
511   - "training.cleaning.title": "Equipment Cleaning & Sanitizing",
512   - "training.cleaning.desc": "Proper cleaning and sanitizing procedures",
513   - "training.cleaning.content": "Effective cleaning and sanitizing of equipment and surfaces is essential for preventing contamination and maintaining food safety. This guide covers proper cleaning procedures, sanitizer concentrations, and contact times.\n\nClean equipment and surfaces are your first line of defense against foodborne pathogens.",
514   - "training.cleaning.content.point1": "Follow the correct sequence: clean, rinse, sanitize",
515   - "training.cleaning.content.point2": "Use approved sanitizers at proper concentrations",
516   - "training.cleaning.content.point3": "Allow adequate contact time for sanitizers to work",
517   - "training.cleaning.step1": "Remove all food debris and residue from equipment",
518   - "training.cleaning.step2": "Wash with hot water and approved detergent",
519   - "training.cleaning.step3": "Rinse thoroughly with clean water",
520   - "training.cleaning.step4": "Apply sanitizer and allow proper contact time",
521   - "training.cleaning.step5": "Air dry completely before use",
522   -
523   - "training.emergency.title": "Emergency Procedures",
524   - "training.emergency.desc": "What to do in emergency situations",
525   - "training.emergency.content": "Being prepared for emergencies can prevent injuries and minimize damage. This video covers emergency procedures including fire safety, medical emergencies, power outages, and equipment failures.\n\nKnowing what to do in an emergency helps keep everyone safe.",
526   - "training.emergency.content.point1": "Know the location of emergency exits and equipment",
527   - "training.emergency.content.point2": "Follow proper evacuation procedures",
528   - "training.emergency.content.point3": "Report all emergencies immediately",
529   -
530   - "training.allergens.title": "Allergen Management",
531   - "training.allergens.desc": "Identifying and managing food allergens",
532   - "training.allergens.content": "Food allergies can cause serious health reactions. This guide teaches you to identify major allergens, prevent cross-contact, and properly label allergenic ingredients.\n\nProper allergen management protects customers with food allergies and prevents serious allergic reactions.",
533   - "training.allergens.content.point1": "Know the major food allergens",
534   - "training.allergens.content.point2": "Prevent cross-contact during preparation",
535   - "training.allergens.content.point3": "Accurately label all allergenic ingredients",
536   - "training.allergens.step1": "Review recipes and identify all allergenic ingredients",
537   - "training.allergens.step2": "Use dedicated equipment for allergen-free preparations when possible",
538   - "training.allergens.step3": "Clean and sanitize surfaces between preparing different items",
539   - "training.allergens.step4": "Clearly label all food items containing allergens",
540   -
541   - "training.storage.title": "Proper Food Storage",
542   - "training.storage.desc": "Guidelines for storing food safely",
543   - "training.storage.content": "Proper food storage prevents spoilage, maintains quality, and ensures food safety. This video covers storage temperatures, shelf life, FIFO procedures, and organization.\n\nCorrect storage practices reduce waste and prevent foodborne illness.",
544   - "training.storage.content.point1": "Store foods at proper temperatures",
545   - "training.storage.content.point2": "Use FIFO (First In, First Out) rotation",
546   - "training.storage.content.point3": "Keep raw and ready-to-eat foods separated",
547   -
548   - "training.crossContamination.title": "Preventing Cross-Contamination",
549   - "training.crossContamination.desc": "Techniques to prevent food contamination",
550   - "training.crossContamination.content": "Cross-contamination occurs when harmful bacteria or allergens are transferred from one food or surface to another. This guide teaches prevention strategies including proper handwashing, equipment sanitation, and food separation.\n\nPreventing cross-contamination is essential for food safety.",
551   - "training.crossContamination.content.point1": "Use separate cutting boards for raw and cooked foods",
552   - "training.crossContamination.content.point2": "Never place cooked food on unwashed surfaces",
553   - "training.crossContamination.content.point3": "Wash hands between handling different food types",
554   - "training.crossContamination.step1": "Use color-coded cutting boards for different food types",
555   - "training.crossContamination.step2": "Wash, rinse, and sanitize all equipment between uses",
556   - "training.crossContamination.step3": "Store raw meats on lower shelves, below ready-to-eat foods",
557   - "training.crossContamination.step4": "Use separate utensils for raw and cooked foods",
558   -
559   - "training.personalHygiene.title": "Personal Hygiene Standards",
560   - "training.personalHygiene.desc": "Maintaining proper personal hygiene",
561   - "training.personalHygiene.content": "Personal hygiene is fundamental to food safety. This video covers handwashing procedures, proper attire, illness policies, and other hygiene practices that prevent contamination.\n\nYour personal hygiene directly impacts food safety.",
562   - "training.personalHygiene.content.point1": "Wash hands properly and frequently",
563   - "training.personalHygiene.content.point2": "Wear clean uniforms and hair restraints",
564   - "training.personalHygiene.content.point3": "Report illness and avoid work when sick",
565   -
566   - // Task Execute
567   - "taskExecute.temperatureReading": "Temperature Reading (°F)",
568   - "taskExecute.enterTemperature": "Enter temperature",
569   - "taskExecute.normalRange": "Normal range: 35°F - 40°F",
570   - "taskExecute.outOfRange": "Temperature is out of normal range. You'll need to report this issue after submission.",
571   - "taskExecute.equipmentCondition": "Equipment Condition",
572   - "taskExecute.condition.good": "Good",
573   - "taskExecute.condition.fair": "Fair",
574   - "taskExecute.condition.poor": "Poor",
575   - "taskExecute.safetyChecks": "Safety Checks",
576   - "taskExecute.checks.doorSeals": "Door seals properly",
577   - "taskExecute.checks.noFrost": "No frost buildup",
578   - "taskExecute.checks.organized": "Organized storage",
579   - "taskExecute.checks.properLabel": "Proper labeling",
580   - "taskExecute.photoOptional": "Photo (Optional)",
581   - "taskExecute.uploadPhoto": "Upload Photo",
582   - "taskExecute.additionalNotes": "Additional Notes (Optional)",
583   - "taskExecute.notesPlaceholder": "Enter any additional notes...",
584   - "taskExecute.submitTask": "Submit Task",
585   - "taskExecute.submitSuccess": "Task completed successfully!",
586   -
587   - // Printers
588   - "printers.of": "of",
589   - "printers.printer1.name": "Kitchen Printer #1",
590   - "printers.printer1.location": "Main Kitchen",
591   - "printers.printer2.name": "Kitchen Printer #2",
592   - "printers.printer2.location": "Main Kitchen",
593   - "printers.printer3.name": "Prep Area Printer",
594   - "printers.printer3.location": "Prep Station",
595   - "printers.printer4.name": "Storage Printer",
596   - "printers.printer4.location": "Cold Storage",
597   -
598   - // Location
599   - "location.defaultStoreName": "Downtown Kitchen",
600   - "location.contactInfo": "Contact Information",
601   - "location.storePhone": "Store Phone",
602   - "location.operatingHours": "Operating Hours",
603   - "location.storeManager": "Store Manager",
604   - "location.name": "Name",
605   - "location.phone": "Phone",
606   -
607   - // Notifications
608   - "notifications.title": "Notifications",
609   - "notifications.unread": "Unread",
610   - "notifications.markAllRead": "Mark All Read",
611   - "notifications.all": "All",
612   - "notifications.expiry": "Expiry",
613   - "notifications.system": "System",
614   - "notifications.noNotifications": "No Notifications",
615   - "notifications.noNotificationsDesc": "You're all caught up! No new notifications.",
616   - "notifications.type.expiry": "Expiry",
617   - "notifications.type.alert": "Alert",
618   - "notifications.type.reminder": "Reminder",
619   - "notifications.type.system": "System",
620   - "notifications.markRead": "Mark as Read",
621   - "notifications.settings": "Notification Settings",
622   - "notifications.settingsDesc": "Customize your notification preferences",
623   - "notifications.expiryReminders": "Expiry Reminders",
624   - "notifications.expiryRemindersDesc": "Get notified when food is about to expire",
625   - "notifications.remindMeBefore": "Remind me before",
626   - "notifications.days": "days",
627   - "notifications.taskReminders": "Task Reminders",
628   - "notifications.taskRemindersDesc": "Receive reminders for upcoming tasks",
629   - "notifications.systemNotifications": "System Notifications",
630   - "notifications.systemNotificationsDesc": "Important updates and alerts",
631   -
632   - "notifications.item1.title": "Food Expiring Soon",
633   - "notifications.item1.message": "5 items are expiring in the next 24 hours. Please check and take action.",
634   - "notifications.item2.title": "Temperature Alert",
635   - "notifications.item2.message": "Walk-in cooler temperature has exceeded safe range. Immediate action required.",
636   - "notifications.item3.title": "Task Due Soon",
637   - "notifications.item3.message": "'Kitchen Hygiene Inspection' is due in 30 minutes.",
638   - "notifications.item4.title": "System Update",
639   - "notifications.item4.message": "New features have been added. Check out what's new!",
640   - "notifications.item5.message": "2 items have passed their expiration date. Please remove from storage.",
641   -
642   - // More - Notifications
643   - "more.notifications": "Notifications",
644   - "more.notifications.desc": "Manage alerts and reminders",
645   -
646   - // Login - Stores
647   - "login.appName": "Food Label System",
648   - "login.employeePortal": "Employee Portal",
649   - "login.email": "Email",
650   - "login.emailPlaceholder": "your.email@company.com",
651   - "login.passwordPlaceholder": "Enter your password",
652   - "login.selectStore": "Select Store",
653   - "login.chooseStore": "Choose your store location",
654   - "login.store1": "Downtown Kitchen",
655   - "login.store2": "Brooklyn Central",
656   - "login.store3": "Queens Food Hub",
657   - "login.store4": "Manhattan Express",
658   - "login.selectStoreError": "Please select a store",
659   - "login.rememberMe": "Remember me",
660   - "login.forgotPassword": "Forgot Password?",
661   - "login.copyright": "© 2026 Food Label System. All rights reserved.",
662   -
663   - // Expiry Alert
664   - "expiryAlert.title": "Items Expiring Soon",
665   - "expiryAlert.itemsExpiring": "items expiring soon",
666   - "expiryAlert.message": "The following items are approaching their expiration dates. Please check and take appropriate action.",
667   - "expiryAlert.location": "Location",
668   - "expiryAlert.expires": "Expires",
669   - "expiryAlert.viewAll": "View All Items",
670   - "expiryAlert.dismiss": "Dismiss",
671   -
672   - // Dashboard - Environmental
673   - "dashboard.environmental": "Environmental Monitoring",
674   - "dashboard.tempHumidity": "Temperature & Humidity",
675   - "dashboard.mainKitchen": "Main Kitchen",
676   - "dashboard.temperature": "Temperature",
677   - "dashboard.humidity": "Humidity",
678   - "dashboard.eTags": "Electronic Tags",
679   - "dashboard.devicesConnected": "devices connected",
680   - "dashboard.eTagsOnline": "online",
681   -
682   - // Electronic Labels (ESL)
683   - "esl.title": "Electronic Labels",
684   - "esl.subtitle": "Manage electronic shelf labels",
685   - "esl.search": "Search by device ID, food, or location...",
686   - "esl.onlineDevices": "Online",
687   - "esl.offlineDevices": "Offline",
688   - "esl.totalDevices": "Total Devices",
689   - "esl.lowBattery": "Low Battery",
690   - "esl.devicesList": "Devices List",
691   - "esl.noDevices": "No Devices Found",
692   - "esl.noDevicesDesc": "Try adjusting your search or filter",
693   - "esl.batteryLow": "Battery Low",
694   - "common.viewAll": "View All",
695   - "common.all": "All",
696   -
697   - // Profile - Password
698   - "profile.changePassword": "Change Password",
699   - "profile.currentPassword": "Current Password",
700   - "profile.newPassword": "New Password",
701   - "profile.confirmPassword": "Confirm New Password",
702   - "profile.passwordUpdated": "Password updated successfully",
703   - "profile.passwordMismatch": "Passwords do not match",
704   -
705   - // Label - How to
706   - "labelPreview.howTo": "How to Print",
707   - "labelPreview.howToTitle": "Printing Instructions",
708   - "labelPreview.step1": "1. Review the label preview above",
709   - "labelPreview.step2": "2. Ensure all information is correct",
710   - "labelPreview.step3": "3. Press the Print Label button",
711   - "labelPreview.step4": "4. Wait for the label to print",
712   - "labelPreview.step5": "5. Apply the label to the food container immediately",
713   - "labelPreview.tips": "Tips",
714   - "labelPreview.tip1": "Always apply labels to clean, dry surfaces",
715   - "labelPreview.tip2": "Make sure the label is visible and readable",
716   - "labelPreview.tip3": "Check printer paper levels before printing",
717   -
718   - // Operations Center (was Training)
719   - "operations.title": "Operations Center",
720   - "operations.subtitle": "Manage operations and access training",
721   - "more.operations": "Operations Center",
722   - "more.operations.desc": "Training and operational resources",
723   -
724   - // Timers
725   - "notifications.timers": "Timers",
726   - "notifications.addTimer": "Add Timer",
727   - "notifications.timerName": "Timer Name",
728   - "notifications.timerNamePlaceholder": "e.g., Check oven",
729   - "notifications.duration": "Duration",
730   - "notifications.minutes": "minutes",
731   - "notifications.hours": "hours",
732   - "notifications.startTimer": "Start Timer",
733   - "notifications.activeTimers": "Active Timers",
734   - "notifications.noTimers": "No Active Timers",
735   - "notifications.noTimersDesc": "Add a timer to get started",
736   - "notifications.timeRemaining": "Time Remaining",
737   - "notifications.stopTimer": "Stop",
738   - "notifications.timerComplete": "Timer Complete!",
739   - "notifications.timerCompleteMessage": "Your timer has finished",
740   -
741   - // Location - Store Switch
742   - "location.switchStore": "Switch Store",
743   - "location.currentStore": "Current Store",
744   - "location.selectNewStore": "Select a new store",
745   - "location.confirmSwitch": "Confirm Switch",
746   - "location.storeSwitched": "Store switched successfully",
747   -
748   - // Login - Store Select
749   - "login.welcomeUser": "Welcome!",
750   - "login.selectStoreDesc": "Select the store where you'll be working today",
751   - "login.storeSelected": "Store selected successfully",
752   -
753   - // Temperature Monitoring
754   - "temperature.title": "Temperature & Humidity Monitoring",
755   - "temperature.device1": "Main Cooler",
756   - "temperature.device2": "Main Freezer",
757   - "temperature.device3": "Prep Cooler",
758   - "temperature.device4": "Dry Storage",
759   - "temperature.device5": "Display Cooler",
760   - "temperature.device6": "Reach-in Fridge",
761   - "temperature.lastUpdate": "Last update",
762   - "temperature.all": "All",
763   - "temperature.alerts": "Alerts",
764   - "temperature.normal": "Normal",
765   - "temperature.warning": "Warning",
766   - "temperature.critical": "Critical",
767   - "temperature.warningMessage": "Temperature is outside normal range. Please monitor closely.",
768   - "temperature.criticalMessage": "Device offline or critical temperature! Immediate action required.",
769   -
770   - // Notifications - Temperature & Timers
771   - "notifications.temperatureAlerts": "Temperature Alerts",
772   - "notifications.temperatureAlertsDesc": "Get notified when temperature exceeds safe range",
773   - "notifications.timerStarted": "Timer started",
774   - "notifications.timerStopped": "Timer stopped",
775   -};
776   -
777   -// Chinese translations
778   -const translationsZh: Record<string, string> = {
779   - // Common
780   - "common.back": "返回",
781   - "common.search": "搜索",
782   - "common.save": "保存",
783   - "common.cancel": "取消",
784   - "common.delete": "删除",
785   - "common.edit": "编辑",
786   - "common.confirm": "确认",
787   - "common.loading": "加载中...",
788   - "common.online": "在线",
789   - "common.offline": "离线",
790   - "common.note": "注意",
791   -
792   - // Login
793   - "login.title": "登录",
794   - "login.subtitle": "请输入您的凭证以访问系统",
795   - "login.employeeId": "员工编号",
796   - "login.password": "密码",
797   - "login.selectLocation": "选择工作地点",
798   - "login.signIn": "登录",
799   - "login.signingIn": "登录中...",
800   - "login.welcome": "欢迎!",
801   - "login.loginSuccess": "登录成功",
802   -
803   - // Dashboard
804   - "dashboard.todaysLabels": "今日标签",
805   - "dashboard.pendingPrint": "待打印",
806   - "dashboard.openTasks": "待办任务",
807   - "dashboard.dueToday": "今日到期",
808   - "dashboard.alerts": "提醒",
809   - "dashboard.expiringSoon": "即将过期",
810   - "dashboard.devicesStatus": "设备状态",
811   - "dashboard.quickActions": "快捷操作",
812   - "dashboard.scanAndPrint": "扫码打印",
813   - "dashboard.batchPrint": "批量打印",
814   - "dashboard.recordTemperature": "记录温度",
815   - "dashboard.reportWaste": "报告浪费",
816   -
817   - // Labels
818   - "labels.title": "标签",
819   - "labels.selectType": "选择要打印的标签类型",
820   - "labels.selectFood": "选择要打印标签的食品",
821   - "labels.foodItems": "食品项目",
822   - "labels.searchFood": "搜索食品...",
823   - "labels.noFoodFound": "未找到食品",
824   - "labels.noFoodDesc": "尝试调整搜索或按类别浏览",
825   - "labels.category": "类别",
826   -
827   - // Labels - Tabs & History
828   - "labels.tabs.create": "创建",
829   - "labels.tabs.history": "历史",
830   - "labels.history.subtitle": "查看已打印的标签",
831   - "labels.printedBy": "打印人",
832   - "labels.status.active": "有效",
833   - "labels.status.expired": "已过期",
834   - "labels.history.empty.title": "暂无标签",
835   - "labels.history.empty.desc": "您打印的标签将显示在这里",
836   -
837   - // Labels - Preview & Print
838   - "labels.preview.title": "标签预览",
839   - "labels.preview.subtitle": "打印前请审查",
840   - "labels.preview.labelPreview": "标签预览",
841   - "labels.preview.printedBy": "打印人",
842   - "labels.preview.printDate": "打印日期",
843   - "labels.preview.note": "此预览显示标签打印后的外观。请在打印前验证所有信息。",
844   - "labels.print.button": "打印标签",
845   - "labels.print.printing": "打印中...",
846   - "labels.print.success": "标签打印成功!",
847   -
848   - // Label Types
849   - "labelType.nutrition.name": "营养标签",
850   - "labelType.nutrition.desc": "打印营养成分和份量信息",
851   - "labelType.allergen.name": "过敏原标签",
852   - "labelType.allergen.desc": "显示过敏原警告和交叉污染信息",
853   - "labelType.storage.name": "储存标签",
854   - "labelType.storage.desc": "显示储存温度和处理说明",
855   - "labelType.expiry.name": "有效期标签",
856   - "labelType.expiry.desc": "打印有效期和最佳食用日期信息",
857   - "labelType.batch.name": "批次跟踪标签",
858   - "labelType.batch.desc": "跟踪批次号和供应商信息",
859   - "labelType.preparation.name": "制作标签",
860   - "labelType.preparation.desc": "记录制作日期、时间和负责员工",
861   -
862   - // Label Preview Headers
863   - "labelPreview.nutrition": "营养成分",
864   - "labelPreview.allergen": "过敏原信息",
865   - "labelPreview.storage": "储存说明",
866   - "labelPreview.expiry": "有效期",
867   - "labelPreview.batch": "批次跟踪",
868   - "labelPreview.preparation": "制作信息",
869   -
870   - // Nutrition Label Fields
871   - "nutrition.servingSize": "份量",
872   - "nutrition.calories": "热量",
873   - "nutrition.totalFat": "总脂肪",
874   - "nutrition.saturatedFat": "饱和脂肪",
875   - "nutrition.transFat": "反式脂肪",
876   - "nutrition.cholesterol": "胆固醇",
877   - "nutrition.sodium": "钠",
878   - "nutrition.totalCarb": "总碳水化合物",
879   - "nutrition.dietaryFiber": "膳食纤维",
880   - "nutrition.sugars": "糖",
881   - "nutrition.protein": "蛋白质",
882   -
883   - // Allergen Label Fields
884   - "allergen.contains": "含有",
885   - "allergen.mayContain": "可能含有",
886   - "allergen.crossContamination": "交叉污染风险",
887   - "allergen.preparedIn": "制备于",
888   - "allergen.riskLow": "低",
889   - "allergen.riskMedium": "中",
890   - "allergen.riskHigh": "高",
891   -
892   - // Storage Label Fields
893   - "storage.temperature": "储存温度",
894   - "storage.location": "储存位置",
895   - "storage.shelfLife": "保质期",
896   - "storage.handling": "处理",
897   - "storage.tempRange": "°F (0-4°C)",
898   - "storage.daysFromPrep": "从制备日期起的天数",
899   - "storage.instructions": "冷藏保存。使用干净的餐具。",
900   -
901   - // Expiry Label Fields
902   - "expiry.prepDate": "制备日期",
903   - "expiry.expiryDate": "有效期",
904   - "expiry.batchNumber": "批次号",
905   - "expiry.preparedBy": "制备人",
906   -
907   - // Batch Label Fields
908   - "batch.batchNumber": "批次号",
909   - "batch.productionDate": "生产日期",
910   - "batch.supplier": "供应商",
911   - "batch.lotNumber": "批号",
912   - "batch.supplierName": "新鲜食品公司",
913   -
914   - // Preparation Label Fields
915   - "prep.prepDate": "制备日期",
916   - "prep.prepTime": "制备时间",
917   - "prep.preparedBy": "制备人",
918   - "prep.location": "位置",
919   - "prep.useBy": "使用期限",
920   -
921   - // Food Categories
922   - "category.meat": "肉类",
923   - "category.salads": "沙拉",
924   - "category.seafood": "海鲜",
925   - "category.sauces": "酱料",
926   - "category.vegetables": "蔬菜",
927   - "category.desserts": "甜点",
928   - "category.prepared": "预制食品",
929   - "category.frozen": "冷冻食品",
930   - "category.dairy": "乳制品",
931   - "category.bakery": "烘焙食品",
932   - "category.beverages": "饮料",
933   - "category.soups": "汤",
934   -
935   - // Food Items
936   - "food.chickenBreast": "烤鸡胸肉",
937   - "food.chickenBreast.desc": "新鲜烤鸡胸肉,去骨",
938   - "food.caesarSalad": "凯撒沙拉",
939   - "food.caesarSalad.desc": "经典凯撒沙拉,罗马生菜",
940   - "food.salmonFillet": "新鲜三文鱼片",
941   - "food.salmonFillet.desc": "大西洋三文鱼片,带皮",
942   - "food.beefPatties": "碎牛肉饼",
943   - "food.beefPatties.desc": "新鲜碎牛肉饼,80/20",
944   - "food.marinaraSauce": "意式番茄酱",
945   - "food.marinaraSauce.desc": "自制意式番茄酱",
946   - "food.vegetables": "预切蔬菜",
947   - "food.vegetables.desc": "混合新鲜蔬菜,预切",
948   - "food.brownie": "巧克力布朗尼",
949   - "food.brownie.desc": "富含核桃的巧克力布朗尼",
950   - "food.shrimpPasta": "虾意面",
951   - "food.shrimpPasta.desc": "蒜香虾意面",
952   - "food.iceCream": "香草冰淇淋",
953   - "food.iceCream.desc": "优质香草冰淇淋",
954   - "food.clubSandwich": "俱乐部三明治",
955   - "food.clubSandwich.desc": "三层俱乐部三明治",
956   - "food.yogurt": "希腊酸奶",
957   - "food.yogurt.desc": "全脂希腊酸奶",
958   - "food.bread": "全麦面包",
959   - "food.bread.desc": "新鲜烘焙全麦面包",
960   - "food.smoothie": "混合浆果奶昔",
961   - "food.smoothie.desc": "新鲜混合浆果奶昔",
962   - "food.turkey": "烤火鸡肉",
963   - "food.turkey.desc": "烤火鸡肉",
964   - "food.tomatoSoup": "番茄汤",
965   - "food.tomatoSoup.desc": "奶油番茄汤,带罗勒",
966   -
967   - // Label Fields
968   - "field.servingSize": "份量",
969   - "field.servingSize.placeholder": "例如:100克、1杯",
970   - "field.calories": "热量(每份)",
971   - "field.calories.placeholder": "例如:250",
972   - "field.totalFat": "总脂肪(克)",
973   - "field.totalFat.placeholder": "例如:15",
974   - "field.protein": "蛋白质(克)",
975   - "field.protein.placeholder": "例如:20",
976   - "field.ingredients": "配料",
977   - "field.ingredients.placeholder": "列出所有配料...",
978   - "field.allergens": "包含过敏原",
979   - "field.allergens.select": "选择过敏原",
980   - "field.crossContamination": "交叉污染风险",
981   - "field.crossContamination.select": "选择风险等级",
982   - "field.additionalInfo": "附加信息",
983   - "field.additionalInfo.placeholder": "任何额外的过敏原信息...",
984   - "field.storageTemp": "储存温度",
985   - "field.storageTemp.select": "选择温度",
986   - "field.storageLocation": "储存位置",
987   - "field.storageLocation.select": "选择位置",
988   - "field.handlingInstructions": "处理说明",
989   - "field.handlingInstructions.placeholder": "描述正确的处理方式...",
990   - "field.prepDate": "制作日期",
991   - "field.expiryDate": "有效期",
992   - "field.batchNumber": "批次号",
993   - "field.batchNumber.placeholder": "例如:GB-20260227-001",
994   - "field.productionDate": "生产日期",
995   - "field.lotNumber": "批号",
996   - "field.lotNumber.placeholder": "可选批号",
997   - "field.supplier": "供应商",
998   - "field.supplier.placeholder": "供应商名称",
999   - "field.prepTime": "制作时间",
1000   - "field.prepTime.placeholder": "例如:下午 2:30",
1001   - "field.prepBy": "制作人",
1002   - "field.prepBy.placeholder": "员工姓名",
1003   - "field.useBy": "使用期限",
1004   -
1005   - // Label Queue
1006   - "queue.title": "打印队列",
1007   - "queue.searchQueue": "搜索打印队列...",
1008   - "queue.all": "全部",
1009   - "queue.pending": "待处理",
1010   - "queue.printing": "打印中",
1011   - "queue.completed": "已完成",
1012   - "queue.failed": "失败",
1013   - "queue.noQueue": "队列为空",
1014   - "queue.noQueueDesc": "打印队列中没有任务。",
1015   - "queue.batch": "批次",
1016   - "queue.printer": "打印机",
1017   - "queue.time": "时间",
1018   - "queue.cancel": "取消任务",
1019   - "queue.retry": "重试",
1020   - "queue.view": "查看详情",
1021   -
1022   - // Tasks
1023   - "tasks.title": "任务",
1024   - "tasks.searchTasks": "搜索任务...",
1025   - "tasks.all": "全部",
1026   - "tasks.pending": "待处理",
1027   - "tasks.inProgress": "进行中",
1028   - "tasks.completed": "已完成",
1029   - "tasks.noTasks": "未找到任务",
1030   - "tasks.noTasksDesc": "没有符合您搜索条件的任务。",
1031   - "tasks.dueDate": "截止日期",
1032   - "tasks.priority": "优先级",
1033   - "tasks.high": "高",
1034   - "tasks.medium": "中",
1035   - "tasks.low": "低",
1036   - "tasks.startTask": "开始任务",
1037   -
1038   - // Task Types
1039   - "tasks.type.temperature": "温度检查",
1040   - "tasks.type.hygiene": "卫生检查",
1041   - "tasks.type.equipment": "设备检查",
1042   -
1043   - // Task Status
1044   - "tasks.status.open": "开放",
1045   - "tasks.status.completed": "已完成",
1046   - "tasks.status.overdue": "逾期",
1047   -
1048   - // Task Names
1049   - "tasks.task1.name": "冰箱温度检查",
1050   - "tasks.task2.name": "厨房卫生检查",
1051   - "tasks.task3.name": "冷冻室温度检查",
1052   - "tasks.task4.name": "设备安全检查",
1053   - "tasks.task5.name": "早晨温度记录",
1054   - "tasks.task6.name": "准备区卫生",
1055   -
1056   - // Task Execute
1057   - "task.execute.taskDetails": "任务详情",
1058   - "task.execute.description": "描述",
1059   - "task.execute.steps": "步骤",
1060   - "task.execute.step": "步骤",
1061   - "task.execute.complete": "完成",
1062   - "task.execute.recordTemp": "记录温度",
1063   - "task.execute.temp": "温度",
1064   - "task.execute.tempPlaceholder": "输入温度(华氏度)",
1065   - "task.execute.location": "位置",
1066   - "task.execute.notes": "备注(可选)",
1067   - "task.execute.notesPlaceholder": "添加任何额外的备注...",
1068   - "task.execute.reportIssue": "报告问题",
1069   - "task.execute.completeTask": "完成任务",
1070   - "task.execute.completing": "完成中...",
1071   - "task.execute.enterTemp": "请输入温度",
1072   - "task.execute.success": "任务已成功完成!",
1073   -
1074   - // More
1075   - "more.title": "更多",
1076   - "more.profile": "我的资料",
1077   - "more.profile.desc": "查看和编辑您的个人资料",
1078   - "more.training": "培训材料",
1079   - "more.training.desc": "学习和提高技能",
1080   - "more.printers": "打印机设置",
1081   - "more.printers.desc": "管理连接的打印机",
1082   - "more.location": "工作地点",
1083   - "more.location.desc": "更改您的工作地点",
1084   - "more.sync": "同步状态",
1085   - "more.sync.desc": "查看同步状态和数据",
1086   - "more.language": "语言 / Language",
1087   - "more.language.desc": "更改应用语言",
1088   - "more.support": "支持",
1089   - "more.support.desc": "获取帮助并联系支持",
1090   - "more.logout": "退出登录",
1091   -
1092   - // Language Settings
1093   - "language.title": "语言设置",
1094   - "language.selectLanguage": "选择语言",
1095   - "language.english": "English",
1096   - "language.chinese": "中文(简体)",
1097   - "language.changed": "语言已成功更改",
1098   -
1099   - // Profile
1100   - "profile.title": "我的资料",
1101   - "profile.info": "个人信息",
1102   - "profile.name": "姓名",
1103   - "profile.employeeId": "员工编号",
1104   - "profile.role": "职位",
1105   - "profile.department": "部门",
1106   - "profile.email": "邮箱",
1107   - "profile.phone": "电话",
1108   - "profile.workSchedule": "工作时间表",
1109   - "profile.preferences": "偏好设置",
1110   - "profile.notifications": "推送通知",
1111   - "profile.sound": "声音提醒",
1112   - "profile.saveChanges": "保存更改",
1113   - "profile.saving": "保存中...",
1114   -
1115   - // Printers
1116   - "printers.title": "打印机设置",
1117   - "printers.connected": "已连接的打印机",
1118   - "printers.noPrinters": "未连接打印机",
1119   - "printers.noPrintersDesc": "系统当前未连接任何打印机。",
1120   - "printers.addPrinter": "添加打印机",
1121   - "printers.available": "台可用打印机",
1122   - "printers.online": "在线",
1123   - "printers.offline": "离线",
1124   - "printers.error": "错误",
1125   - "printers.model": "型号",
1126   - "printers.ip": "IP 地址",
1127   - "printers.status": "状态",
1128   - "printers.setDefault": "设为默认",
1129   - "printers.default": "默认",
1130   - "printers.testPrint": "测试打印",
1131   -
1132   - // Location
1133   - "location.title": "工作地点",
1134   - "location.current": "当前地点",
1135   - "location.selectLocation": "选择地点",
1136   - "location.change": "更改地点",
1137   - "location.changing": "更改中...",
1138   -
1139   - // Sync Status
1140   - "sync.title": "同步状态",
1141   - "sync.lastSync": "上次同步",
1142   - "sync.status": "状态",
1143   - "sync.synced": "所有数据已同步",
1144   - "sync.syncNow": "立即同步",
1145   - "sync.syncing": "同步中...",
1146   - "sync.dataOverview": "数据概览",
1147   - "sync.labels": "标签",
1148   - "sync.tasks": "任务",
1149   - "sync.records": "记录",
1150   - "sync.pending": "待处理",
1151   -
1152   - // Support
1153   - "support.title": "支持",
1154   - "support.needHelp": "需要帮助?",
1155   - "support.needHelpDesc": "联系我们的支持团队获取帮助",
1156   - "support.email": "邮件支持",
1157   - "support.phone": "电话支持",
1158   - "support.hours": "周一至周五,上午9点至下午6点(美东时间)",
1159   - "support.resources": "资源",
1160   - "support.userGuide": "用户指南",
1161   - "support.userGuide.desc": "学习如何使用应用",
1162   - "support.faq": "常见问题",
1163   - "support.faq.desc": "常见问题解答",
1164   - "support.training": "培训视频",
1165   - "support.training.desc": "观看教程视频",
1166   - "support.appInfo": "应用信息",
1167   - "support.version": "版本",
1168   - "support.buildNumber": "构建号",
1169   -
1170   - // Bottom Navigation
1171   - "nav.dashboard": "主页",
1172   - "nav.labels": "标签",
1173   - "nav.tasks": "任务",
1174   - "nav.more": "更多",
1175   -
1176   - // Training
1177   - "training.title": "培训材料",
1178   - "training.subtitle": "学习和提高技能",
1179   - "training.completed": "已完成",
1180   - "training.inProgress": "进行中",
1181   - "training.all": "全部",
1182   - "training.articles": "文章",
1183   - "training.videos": "视频",
1184   - "training.article": "文章",
1185   - "training.video": "视频",
1186   - "training.search": "搜索培训材料...",
1187   - "training.noResults": "未找到培训材料",
1188   - "training.noResultsDesc": "尝试调整搜索条件",
1189   - "training.overview": "概述",
1190   - "training.keySteps": "关键步骤",
1191   - "training.keyPoints": "关键点",
1192   - "training.resources": "附加资源",
1193   - "training.downloadPDF": "下载PDF指南",
1194   - "training.printChecklist": "打印检查表",
1195   - "training.markComplete": "标记为完成",
1196   - "training.marking": "标记中...",
1197   - "training.completedSuccess": "培训已完成!",
1198   - "training.notFound": "未找到培训材料",
1199   - "training.videoNotSupported": "您的浏览器不支持视频播放",
1200   -
1201   - // Training Categories
1202   - "training.category.safety": "食品安全",
1203   - "training.category.operations": "操作",
1204   - "training.category.equipment": "设备",
1205   - "training.category.compliance": "合规性",
1206   -
1207   - // Training Items
1208   - "training.foodSafety.title": "食品安全基础知识",
1209   - "training.foodSafety.desc": "基本的食品安全原则和实践",
1210   - "training.foodSafety.content": "食品安全在所有食品服务操作中至关重要。本综合指南涵盖了保持食品安全、防止污染和确保遵守健康法规的基本原则。\n\n理解和实施正确的食品安全实践可以保护您的客户、您的业务和您的声誉。每个团队成员在维护食品安全标准方面都扮演着重要角色。",
1211   - "training.foodSafety.content.point1": "始终保持正确的洗手和卫生习惯",
1212   - "training.foodSafety.content.point2": "持续监测和记录温度",
1213   - "training.foodSafety.content.point3": "遵循FIFO(先进先出)程序",
1214   - "training.foodSafety.step1": "在处理食品前,用肥皂和温水彻底洗手至少20秒",
1215   - "training.foodSafety.step2": "使用校准的温度计定期检查和记录食品温度",
1216   - "training.foodSafety.step3": "将生食和熟食分开存放以防止交叉污染",
1217   - "training.foodSafety.step4": "在所有食品项目上标注制备和过期日期",
1218   - "training.foodSafety.step5": "在任务之���清洁和消毒所有工作表面和设备",
1219   -
1220   - "training.labelPrinting.title": "标签打印指南",
1221   - "training.labelPrinting.desc": "打印食品标签的步骤指南",
1222   - "training.labelPrinting.content": "学习如何高效使用标签打印系统创建准确、合规的食品标签。本视频教程将带您完成从选择标签类型到打印和应用标签的整个过程。\n\n正确的标签是食品安全、可追溯性和法规合规性的关键。",
1223   - "training.labelPrinting.content.point1": "选择适合您需求的标签类型",
1224   - "training.labelPrinting.content.point2": "打印前验证所有信息",
1225   - "training.labelPrinting.content.point3": "打印后立即应用标签",
1226   -
1227   - "training.temperature.title": "温度记录",
1228   - "training.temperature.desc": "监测食品温度的正确程序",
1229   - "training.temperature.content": "准确的温度监测是最重要的食品安全控制之一。本指南解释了何时和如何记录温度、可接受的温度范围以及温度超出范围时的纠正措施。\n\n一致的温度监测可以防止食源性疾病并确保食品质量。",
1230   - "training.temperature.content.point1": "使用校准的温度计进行所有测量",
1231   - "training.temperature.content.point2": "在指定间隔记录温度",
1232   - "training.temperature.content.point3": "如果温度超出安全范围,立即采取行动",
1233   - "training.temperature.step1": "每天首次使用前校准您的温度计",
1234   - "training.temperature.step2": "将温度计插入食物最厚的部分,避免骨头或脂肪",
1235   - "training.temperature.step3": "等待读数稳定后再记录",
1236   - "training.temperature.step4": "在系统中记录温度、时间、位置和您的首字母缩写",
1237   -
1238   - "training.haccp.title": "HACCP原则",
1239   - "training.haccp.desc": "理解危害分析关键控制点",
1240   - "training.haccp.content": "HACCP(危害分析和关键控制点)是一种系统化的食品安全方法。本视频解释了HACCP的七个原则及其如何应用于您的日常工作。\n\nHACCP有助于识别、评估和控制食品生产过程中的食品安全危害。",
1241   - "training.haccp.content.point1": "识别食品准备中的潜在危害",
1242   - "training.haccp.content.point2": "建立关键控制点",
1243   - "training.haccp.content.point3": "监控和记录控制措施",
1244   -
1245   - "training.cleaning.title": "设备清洁和消毒",
1246   - "training.cleaning.desc": "正确的清洁和消毒程序",
1247   - "training.cleaning.content": "设备和表面的有效清洁和消毒对于防止污染和维护食品安全至关重要。本指南涵盖了正确的清洁程序、消毒剂浓度和接触时间。\n\n清洁的设备和表面是防止食源性病原体的第一道防线。",
1248   - "training.cleaning.content.point1": "遵循正确的顺序:清洁、冲洗、消毒",
1249   - "training.cleaning.content.point2": "使用批准的消毒剂并以正确的浓度使用",
1250   - "training.cleaning.content.point3": "允许消毒剂充分接触时间以发挥作用",
1251   - "training.cleaning.step1": "从设备上移除所有食物残渣和残留物",
1252   - "training.cleaning.step2": "用热水和批准的清洁剂清洗",
1253   - "training.cleaning.step3": "彻底冲洗干净的水",
1254   - "training.cleaning.step4": "应用消毒剂并允许适当的接触时间",
1255   - "training.cleaning.step5": "完全风干后使用",
1256   -
1257   - "training.emergency.title": "紧急程序",
1258   - "training.emergency.desc": "紧急情况下的操作",
1259   - "training.emergency.content": "为紧急情况做好准备可以防止伤害并减少损害。本视频涵盖了紧急程序,包括消防安全、医疗紧急情况、停电和设备故障。\n\n知道在紧急情况下该做什么有助于保持每个人的安全。",
1260   - "training.emergency.content.point1": "知道紧急出口和设备的位置",
1261   - "training.emergency.content.point2": "遵循正确的疏散程序",
1262   - "training.emergency.content.point3": "立即报告所有紧急情况",
1263   -
1264   - "training.allergens.title": "过敏原管理",
1265   - "training.allergens.desc": "识别和管理食品过敏原",
1266   - "training.allergens.content": "食品过敏可能导致严重的健康反应。本指南教你识别主要过敏原、防止交叉接触和正确标记过敏性成分。\n\n正确的过敏原管理可以保护有食品过敏的客户并防止严重的过敏反应。",
1267   - "training.allergens.content.point1": "了解主要食品过敏原",
1268   - "training.allergens.content.point2": "在准备过程中防止交叉接触",
1269   - "training.allergens.content.point3": "准确标记所有过敏性成分",
1270   - "training.allergens.step1": "审查食谱并识别所有过敏性成分",
1271   - "training.allergens.step2": "尽可能使用专用设备进行无过敏原准备",
1272   - "training.allergens.step3": "在准备不同项目之间清洁和消毒表面",
1273   - "training.allergens.step4": "清楚地标记所有含有过敏原的食品项目",
1274   -
1275   - "training.storage.title": "正确储存食品",
1276   - "training.storage.desc": "安全储存食品的指南",
1277   - "training.storage.content": "正确的食品储存可以防止变质、保持质量并确保食品安全。本视频涵盖了储存温度、保质期、FIFO程序和组织。\n\n正确的储存实践可以减少浪费并防止食源性疾病。",
1278   - "training.storage.content.point1": "在适当的温度下储存食品",
1279   - "training.storage.content.point2": "使用FIFO(先进先出)轮换",
1280   - "training.storage.content.point3": "将生食和即食食品分开存放",
1281   -
1282   - "training.crossContamination.title": "防止交叉污染",
1283   - "training.crossContamination.desc": "防止食品污染的技术",
1284   - "training.crossContamination.content": "交叉污染发生在有害细菌或过敏原从一个食品或表面转移到另一个食品或表面。本指南教授预防策略,包括正确的洗手、设备消毒和食品分离。\n\n防止交叉污染对食品安全至关重要。",
1285   - "training.crossContamination.content.point1": "为生食和熟食使用单独的切割板",
1286   - "training.crossContamination.content.point2": "不要将熟食放在未清洗的表面上",
1287   - "training.crossContamination.content.point3": "在处理不同类型的食品之间洗手",
1288   - "training.crossContamination.step1": "为不同类型的食品使用彩色编码的切割板",
1289   - "training.crossContamination.step2": "使用后清洗、冲洗和消毒所有设备",
1290   - "training.crossContamination.step3": "将生肉存放在较低的架子上,低于即食食品",
1291   - "training.crossContamination.step4": "为生食和熟食使用单独的餐具",
1292   -
1293   - "training.personalHygiene.title": "个人卫生标准",
1294   - "training.personalHygiene.desc": "保持正确的个人卫生",
1295   - "training.personalHygiene.content": "个人卫生是食品安全的基础。本视频涵盖了洗手程序、适当的服装、疾病政策和其他防止污染的卫生实践。\n\n您的个人卫生直接影响食品安全。",
1296   - "training.personalHygiene.content.point1": "正确且频繁地洗手",
1297   - "training.personalHygiene.content.point2": "穿着干净的制服和发网",
1298   - "training.personalHygiene.content.point3": "报告疾病并生病时避免工作",
1299   -
1300   - // Task Execute
1301   - "taskExecute.temperatureReading": "温度读数 (°F)",
1302   - "taskExecute.enterTemperature": "输入温度",
1303   - "taskExecute.normalRange": "正常范围: 35°F - 40°F",
1304   - "taskExecute.outOfRange": "温度超出正常范围。提交后需要报告此问题。",
1305   - "taskExecute.equipmentCondition": "设备状况",
1306   - "taskExecute.condition.good": "良好",
1307   - "taskExecute.condition.fair": "一般",
1308   - "taskExecute.condition.poor": "差",
1309   - "taskExecute.safetyChecks": "安全检查",
1310   - "taskExecute.checks.doorSeals": "门封条完好",
1311   - "taskExecute.checks.noFrost": "无霜堆积",
1312   - "taskExecute.checks.organized": "存储有序",
1313   - "taskExecute.checks.properLabel": "标签正确",
1314   - "taskExecute.photoOptional": "照片 (可选)",
1315   - "taskExecute.uploadPhoto": "上传照片",
1316   - "taskExecute.additionalNotes": "附加说明 (可选)",
1317   - "taskExecute.notesPlaceholder": "输入任何附加说明...",
1318   - "taskExecute.submitTask": "提交任务",
1319   - "taskExecute.submitSuccess": "任务完成成功!",
1320   -
1321   - // Printers
1322   - "printers.of": "个",
1323   - "printers.printer1.name": "厨房打印机 #1",
1324   - "printers.printer1.location": "主厨房",
1325   - "printers.printer2.name": "厨房打印机 #2",
1326   - "printers.printer2.location": "主厨房",
1327   - "printers.printer3.name": "准备区打印机",
1328   - "printers.printer3.location": "准备站",
1329   - "printers.printer4.name": "存储打印机",
1330   - "printers.printer4.location": "冷藏存储",
1331   -
1332   - // Location
1333   - "location.defaultStoreName": "市中心厨房",
1334   - "location.contactInfo": "联系信息",
1335   - "location.storePhone": "店铺电话",
1336   - "location.operatingHours": "营业时间",
1337   - "location.storeManager": "店铺经理",
1338   - "location.name": "名称",
1339   - "location.phone": "电话",
1340   -
1341   - // Notifications
1342   - "notifications.title": "通知",
1343   - "notifications.unread": "未读",
1344   - "notifications.markAllRead": "全部标记为已读",
1345   - "notifications.all": "全部",
1346   - "notifications.expiry": "过期",
1347   - "notifications.system": "系统",
1348   - "notifications.noNotifications": "没有通知",
1349   - "notifications.noNotificationsDesc": "您已全部查看!没有新的通知。",
1350   - "notifications.type.expiry": "过期",
1351   - "notifications.type.alert": "警报",
1352   - "notifications.type.reminder": "提醒",
1353   - "notifications.type.system": "系统",
1354   - "notifications.markRead": "标记为已读",
1355   - "notifications.settings": "通知设置",
1356   - "notifications.settingsDesc": "自定义您的通知偏好",
1357   - "notifications.expiryReminders": "过期提醒",
1358   - "notifications.expiryRemindersDesc": "当食品即将过期时收到通知",
1359   - "notifications.remindMeBefore": "提前提醒",
1360   - "notifications.days": "天",
1361   - "notifications.taskReminders": "任务提醒",
1362   - "notifications.taskRemindersDesc": "接收即将到期任务的提醒",
1363   - "notifications.systemNotifications": "系统通知",
1364   - "notifications.systemNotificationsDesc": "重要更新和警报",
1365   -
1366   - "notifications.item1.title": "食品即将过期",
1367   - "notifications.item1.message": "5个食品项目将在24小时内过期。请检查并采取行动。",
1368   - "notifications.item2.title": "温度警报",
1369   - "notifications.item2.message": "步入式冷藏室温度超出安全范围。需要立即采取行动。",
1370   - "notifications.item3.title": "任务即将到期",
1371   - "notifications.item3.message": "'厨房卫生检查'将在30分钟后到期。",
1372   - "notifications.item4.title": "系统更新",
1373   - "notifications.item4.message": "添加了新功能。查看最新内容!",
1374   - "notifications.item5.message": "2个食品项目已过期。请从存储中移除。",
1375   -
1376   - // More - Notifications
1377   - "more.notifications": "通知",
1378   - "more.notifications.desc": "管理警报和提醒",
1379   -
1380   - // Login - Stores
1381   - "login.appName": "食品标签系统",
1382   - "login.employeePortal": "员工门户",
1383   - "login.email": "电子邮件",
1384   - "login.emailPlaceholder": "your.email@company.com",
1385   - "login.passwordPlaceholder": "输入您的密码",
1386   - "login.selectStore": "选择店铺",
1387   - "login.chooseStore": "选择您的店铺位置",
1388   - "login.store1": "市中心厨房",
1389   - "login.store2": "布鲁克林中心",
1390   - "login.store3": "皇后食品中心",
1391   - "login.store4": "曼哈顿快速店",
1392   - "login.selectStoreError": "请选择一个店铺",
1393   - "login.rememberMe": "记住我",
1394   - "login.forgotPassword": "忘记密码?",
1395   - "login.copyright": "© 2026 食品标签系统。保留所有权利。",
1396   -
1397   - // Expiry Alert
1398   - "expiryAlert.title": "即将过期的项目",
1399   - "expiryAlert.itemsExpiring": "即将过期的项目",
1400   - "expiryAlert.message": "以下项目即将到期。请检查并采取适当行动。",
1401   - "expiryAlert.location": "位置",
1402   - "expiryAlert.expires": "到期",
1403   - "expiryAlert.viewAll": "查看所有项目",
1404   - "expiryAlert.dismiss": "忽略",
1405   -
1406   - // Dashboard - Environmental
1407   - "dashboard.environmental": "环境监测",
1408   - "dashboard.tempHumidity": "温度 & 湿度",
1409   - "dashboard.mainKitchen": "主厨房",
1410   - "dashboard.temperature": "温度",
1411   - "dashboard.humidity": "湿度",
1412   - "dashboard.eTags": "电子标签",
1413   - "dashboard.devicesConnected": "连接的设备",
1414   - "dashboard.eTagsOnline": "在线",
1415   -
1416   - // Electronic Labels (ESL)
1417   - "esl.title": "电子标签",
1418   - "esl.subtitle": "管理电子货架标签",
1419   - "esl.search": "按设备ID、食品或位置搜索...",
1420   - "esl.onlineDevices": "在线",
1421   - "esl.offlineDevices": "离线",
1422   - "esl.totalDevices": "总设备数",
1423   - "esl.lowBattery": "低电量",
1424   - "esl.devicesList": "设备列表",
1425   - "esl.noDevices": "未找到设备",
1426   - "esl.noDevicesDesc": "尝试调整搜索或筛选条件",
1427   - "esl.batteryLow": "电量不足",
1428   - "common.viewAll": "查看全部",
1429   - "common.all": "全部",
1430   -
1431   - // Profile - Password
1432   - "profile.changePassword": "更改密码",
1433   - "profile.currentPassword": "当前密码",
1434   - "profile.newPassword": "新密码",
1435   - "profile.confirmPassword": "确认新密码",
1436   - "profile.passwordUpdated": "密码更新成功",
1437   - "profile.passwordMismatch": "密码不匹配",
1438   -
1439   - // Label - How to
1440   - "labelPreview.howTo": "如何打印",
1441   - "labelPreview.howToTitle": "打印说明",
1442   - "labelPreview.step1": "1. 查看上方的标签预览",
1443   - "labelPreview.step2": "2. 确保所有信息正确",
1444   - "labelPreview.step3": "3. 点击打印标签按钮",
1445   - "labelPreview.step4": "4. 等待标签打印",
1446   - "labelPreview.step5": "5. 立即在食品容器上应用标签",
1447   - "labelPreview.tips": "提示",
1448   - "labelPreview.tip1": "始终将标签应用到干净、干燥的表面",
1449   - "labelPreview.tip2": "确保标签可见且可读",
1450   - "labelPreview.tip3": "打印前检查打印机纸张水平",
1451   -
1452   - // Operations Center (was Training)
1453   - "operations.title": "运营中心",
1454   - "operations.subtitle": "管理运营和访问培训",
1455   - "more.operations": "运营中心",
1456   - "more.operations.desc": "培训和运营资源",
1457   -
1458   - // Timers
1459   - "notifications.timers": "计时器",
1460   - "notifications.addTimer": "添加计时器",
1461   - "notifications.timerName": "计时器名称",
1462   - "notifications.timerNamePlaceholder": "例如:检查烤箱",
1463   - "notifications.duration": "持续时间",
1464   - "notifications.minutes": "分钟",
1465   - "notifications.hours": "小时",
1466   - "notifications.startTimer": "开始计时器",
1467   - "notifications.activeTimers": "活动计时器",
1468   - "notifications.noTimers": "没有活动计时器",
1469   - "notifications.noTimersDesc": "添加计时器以开始",
1470   - "notifications.timeRemaining": "剩余时间",
1471   - "notifications.stopTimer": "停止",
1472   - "notifications.timerComplete": "计时器完成!",
1473   - "notifications.timerCompleteMessage": "您的计时器已完成",
1474   -
1475   - // Location - Store Switch
1476   - "location.switchStore": "切换店铺",
1477   - "location.currentStore": "当前店铺",
1478   - "location.selectNewStore": "选择新店铺",
1479   - "location.confirmSwitch": "确认切换",
1480   - "location.storeSwitched": "店铺切换成功",
1481   -
1482   - // Login - Store Select
1483   - "login.welcomeUser": "欢迎!",
1484   - "login.selectStoreDesc": "选择您今天工作的店铺",
1485   - "login.storeSelected": "店铺选择成功",
1486   -
1487   - // Temperature Monitoring
1488   - "temperature.title": "温湿度监控",
1489   - "temperature.device1": "主冷藏室",
1490   - "temperature.device2": "主冷冻室",
1491   - "temperature.device3": "准备区冷藏",
1492   - "temperature.device4": "干货储藏",
1493   - "temperature.device5": "展示冷柜",
1494   - "temperature.device6": "工作冰箱",
1495   - "temperature.lastUpdate": "最后更新",
1496   - "temperature.all": "全部",
1497   - "temperature.alerts": "警报",
1498   - "temperature.normal": "正常",
1499   - "temperature.warning": "警告",
1500   - "temperature.critical": "严重",
1501   - "temperature.warningMessage": "温度超出正常范围。请密切监控。",
1502   - "temperature.criticalMessage": "设备离线或温度严重异常!需要立即采取行动。",
1503   -
1504   - // Notifications - Temperature & Timers
1505   - "notifications.temperatureAlerts": "温度警报",
1506   - "notifications.temperatureAlertsDesc": "当温度超出安全范围时收到通知",
1507   - "notifications.timerStarted": "计时器已启动",
1508   - "notifications.timerStopped": "计时器已停止",
1509   -};
1510 0 \ No newline at end of file
美国版/Food Labeling Management App React/src/app/pages/Dashboard.tsx deleted
1   -import { useNavigate } from "react-router";
2   -import { Card } from "../components/ui/card";
3   -import { Button } from "../components/ui/button";
4   -import {
5   - Tag,
6   - AlertTriangle,
7   - Printer,
8   - QrCode,
9   - Layers,
10   -} from "lucide-react";
11   -import { useLanguage } from "../contexts/LanguageContext";
12   -
13   -export default function Dashboard() {
14   - const navigate = useNavigate();
15   - const { t } = useLanguage();
16   - const userName = localStorage.getItem("userName") || "Employee";
17   - const storeName = localStorage.getItem("storeName") || "Kitchen";
18   -
19   - const stats = [
20   - {
21   - title: t("dashboard.todaysLabels"),
22   - value: "247",
23   - subtitle: `12 ${t("dashboard.pendingPrint")}`,
24   - icon: Tag,
25   - color: "bg-blue-50 text-blue-600",
26   - onClick: () => navigate("/labels"),
27   - },
28   - {
29   - title: t("dashboard.alerts"),
30   - value: "5",
31   - subtitle: t("dashboard.expiringSoon"),
32   - icon: AlertTriangle,
33   - color: "bg-orange-50 text-orange-600",
34   - onClick: () => navigate("/labels"),
35   - },
36   - {
37   - title: t("dashboard.devicesStatus"),
38   - value: "4",
39   - subtitle: t("printers.available"),
40   - icon: Printer,
41   - color: "bg-purple-50 text-purple-600",
42   - onClick: () => navigate("/more/printers"),
43   - },
44   - ];
45   -
46   - const quickActions = [
47   - {
48   - label: t("dashboard.scanAndPrint"),
49   - icon: QrCode,
50   - color: "bg-blue-600 hover:bg-blue-700",
51   - onClick: () => navigate("/labels"),
52   - },
53   - {
54   - label: t("dashboard.batchPrint"),
55   - icon: Layers,
56   - color: "bg-green-600 hover:bg-green-700",
57   - onClick: () => navigate("/labels"),
58   - },
59   - ];
60   -
61   - return (
62   - <div className="min-h-screen bg-gray-50">
63   - {/* Header */}
64   - <div className="bg-white border-b border-gray-200 p-6">
65   - <div className="flex items-start justify-between">
66   - <div>
67   - <h1 className="text-2xl font-semibold text-gray-900 mb-1">
68   - {storeName}
69   - </h1>
70   - <p className="text-base text-gray-600">{userName}</p>
71   - </div>
72   - <div className="flex items-center gap-2 px-3 py-1.5 bg-green-50 rounded-lg">
73   - <div className="w-2 h-2 bg-green-600 rounded-full"></div>
74   - <span className="text-sm font-medium text-green-700">
75   - {t("common.online")}
76   - </span>
77   - </div>
78   - </div>
79   - </div>
80   -
81   - {/* Stats Grid */}
82   - <div className="p-6 space-y-4">
83   - <div className="grid grid-cols-2 gap-4">
84   - {stats.map((stat) => {
85   - const Icon = stat.icon;
86   - return (
87   - <Card
88   - key={stat.title}
89   - className="p-4 cursor-pointer hover:shadow-md transition-shadow"
90   - onClick={stat.onClick}
91   - >
92   - <div className={`inline-flex p-2 rounded-lg ${stat.color} mb-3`}>
93   - <Icon className="w-5 h-5" />
94   - </div>
95   - <div className="text-3xl font-bold text-gray-900 mb-1">
96   - {stat.value}
97   - </div>
98   - <div className="text-sm font-medium text-gray-900 mb-1">
99   - {stat.title}
100   - </div>
101   - <div className="text-sm text-gray-500">{stat.subtitle}</div>
102   - </Card>
103   - );
104   - })}
105   - </div>
106   -
107   - {/* Quick Actions */}
108   - <div className="pt-4">
109   - <h2 className="text-lg font-semibold text-gray-900 mb-4">
110   - {t("dashboard.quickActions")}
111   - </h2>
112   - <div className="grid grid-cols-2 gap-4">
113   - {quickActions.map((action) => {
114   - const Icon = action.icon;
115   - return (
116   - <Button
117   - key={action.label}
118   - onClick={action.onClick}
119   - className={`h-28 flex flex-col items-center justify-center gap-3 ${action.color} text-white`}
120   - >
121   - <Icon className="w-8 h-8" />
122   - <span className="text-base font-semibold">{action.label}</span>
123   - </Button>
124   - );
125   - })}
126   - </div>
127   - </div>
128   - </div>
129   - </div>
130   - );
131   -}
132 0 \ No newline at end of file
美国版/Food Labeling Management App React/src/app/pages/LabelFoodSelect.tsx deleted
1   -import { useState } from "react";
2   -import { useNavigate, useParams } from "react-router";
3   -import { Input } from "../components/ui/input";
4   -import { Card } from "../components/ui/card";
5   -import { ChevronLeft, Search, ChevronRight } from "lucide-react";
6   -import { useLanguage } from "../contexts/LanguageContext";
7   -
8   -interface Food {
9   - id: string;
10   - nameKey: string;
11   - descKey: string;
12   - image: string;
13   - categoryKey: string;
14   -}
15   -
16   -// 食品数据 - 使用翻译键
17   -const allFoods: Food[] = [
18   - {
19   - id: "food-001",
20   - nameKey: "food.chickenBreast",
21   - descKey: "food.chickenBreast.desc",
22   - image: "https://images.unsplash.com/photo-1532550907401-a500c9a57435?w=400",
23   - categoryKey: "category.meat",
24   - },
25   - {
26   - id: "food-002",
27   - nameKey: "food.caesarSalad",
28   - descKey: "food.caesarSalad.desc",
29   - image: "https://images.unsplash.com/photo-1546793665-c74683f339c1?w=400",
30   - categoryKey: "category.salads",
31   - },
32   - {
33   - id: "food-003",
34   - nameKey: "food.salmonFillet",
35   - descKey: "food.salmonFillet.desc",
36   - image: "https://images.unsplash.com/photo-1519708227418-c8fd9a32b7a2?w=400",
37   - categoryKey: "category.seafood",
38   - },
39   - {
40   - id: "food-004",
41   - nameKey: "food.beefPatties",
42   - descKey: "food.beefPatties.desc",
43   - image: "https://images.unsplash.com/photo-1607623488235-e2e6794c30b5?w=400",
44   - categoryKey: "category.meat",
45   - },
46   - {
47   - id: "food-005",
48   - nameKey: "food.marinaraSauce",
49   - descKey: "food.marinaraSauce.desc",
50   - image: "https://images.unsplash.com/photo-1621996346565-e3dbc646d9a9?w=400",
51   - categoryKey: "category.sauces",
52   - },
53   - {
54   - id: "food-006",
55   - nameKey: "food.vegetables",
56   - descKey: "food.vegetables.desc",
57   - image: "https://images.unsplash.com/photo-1540420773420-3366772f4999?w=400",
58   - categoryKey: "category.vegetables",
59   - },
60   - {
61   - id: "food-007",
62   - nameKey: "food.brownie",
63   - descKey: "food.brownie.desc",
64   - image: "https://images.unsplash.com/photo-1606313564200-e75d5e30476c?w=400",
65   - categoryKey: "category.desserts",
66   - },
67   - {
68   - id: "food-008",
69   - nameKey: "food.shrimpPasta",
70   - descKey: "food.shrimpPasta.desc",
71   - image: "https://images.unsplash.com/photo-1563379926898-05f4575a45d8?w=400",
72   - categoryKey: "category.prepared",
73   - },
74   - {
75   - id: "food-009",
76   - nameKey: "food.iceCream",
77   - descKey: "food.iceCream.desc",
78   - image: "https://images.unsplash.com/photo-1563805042-7684c019e1cb?w=400",
79   - categoryKey: "category.frozen",
80   - },
81   - {
82   - id: "food-010",
83   - nameKey: "food.clubSandwich",
84   - descKey: "food.clubSandwich.desc",
85   - image: "https://images.unsplash.com/photo-1528735602780-2552fd46c7af?w=400",
86   - categoryKey: "category.prepared",
87   - },
88   - {
89   - id: "food-011",
90   - nameKey: "food.yogurt",
91   - descKey: "food.yogurt.desc",
92   - image: "https://images.unsplash.com/photo-1571212515416-16823f3e8310?w=400",
93   - categoryKey: "category.dairy",
94   - },
95   - {
96   - id: "food-012",
97   - nameKey: "food.bread",
98   - descKey: "food.bread.desc",
99   - image: "https://images.unsplash.com/photo-1509440159596-0249088772ff?w=400",
100   - categoryKey: "category.bakery",
101   - },
102   - {
103   - id: "food-013",
104   - nameKey: "food.smoothie",
105   - descKey: "food.smoothie.desc",
106   - image: "https://images.unsplash.com/photo-1505252585461-04db1eb84625?w=400",
107   - categoryKey: "category.beverages",
108   - },
109   - {
110   - id: "food-014",
111   - nameKey: "food.turkey",
112   - descKey: "food.turkey.desc",
113   - image: "https://images.unsplash.com/photo-1574672280600-4accfa5b6f98?w=400",
114   - categoryKey: "category.meat",
115   - },
116   - {
117   - id: "food-015",
118   - nameKey: "food.tomatoSoup",
119   - descKey: "food.tomatoSoup.desc",
120   - image: "https://images.unsplash.com/photo-1547592166-23ac45744acd?w=400",
121   - categoryKey: "category.soups",
122   - },
123   -];
124   -
125   -const getLabelTypeIcon = (type: string) => {
126   - const icons: Record<string, string> = {
127   - nutrition: "🥗",
128   - allergen: "⚠️",
129   - storage: "❄️",
130   - expiry: "📅",
131   - batch: "📦",
132   - preparation: "👨‍🍳",
133   - };
134   - return icons[type] || "🏷️";
135   -};
136   -
137   -export default function LabelFoodSelect() {
138   - const navigate = useNavigate();
139   - const { labelType } = useParams<{ labelType: string }>();
140   - const { t } = useLanguage();
141   - const [searchTerm, setSearchTerm] = useState("");
142   -
143   - // 过滤食品 - 在翻译后的文本中搜索
144   - const filteredFoods = allFoods.filter((food) => {
145   - const name = t(food.nameKey).toLowerCase();
146   - const category = t(food.categoryKey).toLowerCase();
147   - const search = searchTerm.toLowerCase();
148   - return name.includes(search) || category.includes(search);
149   - });
150   -
151   - // 按类别分组
152   - const categoryKeys = Array.from(new Set(filteredFoods.map((f) => f.categoryKey)));
153   -
154   - return (
155   - <div className="min-h-screen bg-gray-50">
156   - {/* Header */}
157   - <div className="bg-white border-b border-gray-200 p-4">
158   - <button
159   - onClick={() => navigate("/labels")}
160   - className="flex items-center text-blue-600 mb-3"
161   - >
162   - <ChevronLeft className="w-5 h-5" />
163   - <span className="text-sm font-medium ml-1">{t("common.back")}</span>
164   - </button>
165   -
166   - <div className="flex items-center gap-2 mb-3">
167   - <span className="text-2xl">{getLabelTypeIcon(labelType || "")}</span>
168   - <div>
169   - <h1 className="text-xl font-semibold text-gray-900 leading-tight">
170   - {t(`labelType.${labelType}.name`)}
171   - </h1>
172   - <p className="text-sm text-gray-600">
173   - {t("labels.selectFood")}
174   - </p>
175   - </div>
176   - </div>
177   -
178   - {/* Search */}
179   - <div className="relative">
180   - <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-gray-400" />
181   - <Input
182   - placeholder={t("labels.searchFood")}
183   - value={searchTerm}
184   - onChange={(e) => setSearchTerm(e.target.value)}
185   - className="pl-9 h-10 text-sm"
186   - />
187   - </div>
188   - </div>
189   -
190   - {/* Content */}
191   - <div className="p-3">
192   - {filteredFoods.length === 0 ? (
193   - <div className="flex flex-col items-center justify-center py-16">
194   - <div className="w-20 h-20 bg-gray-100 rounded-full flex items-center justify-center mb-3">
195   - <Search className="w-10 h-10 text-gray-400" />
196   - </div>
197   - <h3 className="text-base font-semibold text-gray-900 mb-1">
198   - {t("labels.noFoodFound")}
199   - </h3>
200   - <p className="text-sm text-gray-500 text-center max-w-sm">
201   - {t("labels.noFoodDesc")}
202   - </p>
203   - </div>
204   - ) : (
205   - <div className="space-y-4">
206   - {categoryKeys.map((categoryKey) => {
207   - const categoryFoods = filteredFoods.filter(
208   - (f) => f.categoryKey === categoryKey
209   - );
210   - return (
211   - <div key={categoryKey}>
212   - <h2 className="text-sm font-semibold text-gray-900 mb-2 px-1">
213   - {t(categoryKey)}
214   - </h2>
215   - <div className="grid grid-cols-2 gap-2">
216   - {categoryFoods.map((food) => (
217   - <Card
218   - key={food.id}
219   - className="p-2 cursor-pointer hover:shadow-md transition-shadow"
220   - onClick={() =>
221   - navigate(`/labels/${labelType}/${food.id}/preview`)
222   - }
223   - >
224   - {/* Food Image */}
225   - <div className="w-full aspect-square rounded-lg overflow-hidden bg-gray-100 mb-2">
226   - <img
227   - src={food.image}
228   - alt={t(food.nameKey)}
229   - className="w-full h-full object-cover"
230   - />
231   - </div>
232   -
233   - {/* Food Info */}
234   - <div>
235   - <h3 className="text-xs font-semibold text-gray-900 mb-0.5 line-clamp-1 leading-tight">
236   - {t(food.nameKey)}
237   - </h3>
238   - <p className="text-xs text-gray-600 line-clamp-2 leading-tight">
239   - {t(food.descKey)}
240   - </p>
241   - </div>
242   - </Card>
243   - ))}
244   - </div>
245   - </div>
246   - );
247   - })}
248   - </div>
249   - )}
250   - </div>
251   - </div>
252   - );
253   -}
254 0 \ No newline at end of file
美国版/Food Labeling Management App React/src/app/pages/LabelPreview.tsx deleted
1   -import { useState } from "react";
2   -import { useNavigate, useParams } from "react-router";
3   -import { Button } from "../components/ui/button";
4   -import { Card } from "../components/ui/card";
5   -import { ChevronLeft, Printer, CheckCircle } from "lucide-react";
6   -import { toast } from "sonner";
7   -import { useLanguage } from "../contexts/LanguageContext";
8   -
9   -// 食品数据
10   -const foodData: Record<string, any> = {
11   - "food-001": {
12   - nameKey: "food.chickenBreast",
13   - image: "https://images.unsplash.com/photo-1532550907401-a500c9a57435?w=600",
14   - categoryKey: "category.meat",
15   - },
16   - "food-002": {
17   - nameKey: "food.caesarSalad",
18   - image: "https://images.unsplash.com/photo-1546793665-c74683f339c1?w=600",
19   - categoryKey: "category.salads",
20   - },
21   - "food-003": {
22   - nameKey: "food.salmonFillet",
23   - image: "https://images.unsplash.com/photo-1519708227418-c8fd9a32b7a2?w=600",
24   - categoryKey: "category.seafood",
25   - },
26   - "food-004": {
27   - nameKey: "food.beefPatties",
28   - image: "https://images.unsplash.com/photo-1607623488235-e2e6794c30b5?w=600",
29   - categoryKey: "category.meat",
30   - },
31   - "food-005": {
32   - nameKey: "food.marinaraSauce",
33   - image: "https://images.unsplash.com/photo-1621996346565-e3dbc646d9a9?w=600",
34   - categoryKey: "category.sauces",
35   - },
36   - "food-006": {
37   - nameKey: "food.vegetables",
38   - image: "https://images.unsplash.com/photo-1540420773420-3366772f4999?w=600",
39   - categoryKey: "category.vegetables",
40   - },
41   - "food-007": {
42   - nameKey: "food.brownie",
43   - image: "https://images.unsplash.com/photo-1606313564200-e75d5e30476c?w=600",
44   - categoryKey: "category.desserts",
45   - },
46   -};
47   -
48   -// 标签预览数据生成 - 使用翻译函数
49   -const getLabelPreviewData = (labelType: string, foodId: string, t: (key: string) => string) => {
50   - const today = new Date();
51   - const expiry = new Date(today);
52   - expiry.setDate(expiry.getDate() + 5);
53   -
54   - switch (labelType) {
55   - case "nutrition":
56   - return {
57   - titleKey: "labelPreview.nutrition",
58   - fields: [
59   - { labelKey: "nutrition.servingSize", value: "150g" },
60   - { labelKey: "nutrition.calories", value: "165 kcal", bold: true },
61   - { labelKey: "nutrition.totalFat", value: "3.6g" },
62   - { labelKey: "nutrition.saturatedFat", value: "1.0g", indent: true },
63   - { labelKey: "nutrition.transFat", value: "0g", indent: true },
64   - { labelKey: "nutrition.cholesterol", value: "85mg" },
65   - { labelKey: "nutrition.sodium", value: "74mg" },
66   - { labelKey: "nutrition.totalCarb", value: "0g" },
67   - { labelKey: "nutrition.dietaryFiber", value: "0g", indent: true },
68   - { labelKey: "nutrition.sugars", value: "0g", indent: true },
69   - { labelKey: "nutrition.protein", value: "31g", bold: true },
70   - ],
71   - };
72   - case "allergen":
73   - return {
74   - titleKey: "labelPreview.allergen",
75   - fields: [
76   - { labelKey: "allergen.contains", value: "Tree Nuts, Dairy, Eggs", warning: true },
77   - { labelKey: "allergen.mayContain", value: "Sesame, Soy" },
78   - { labelKey: "allergen.crossContamination", value: t("allergen.riskLow") },
79   - { labelKey: "allergen.preparedIn", value: "Shared facility with wheat products" },
80   - ],
81   - };
82   - case "storage":
83   - return {
84   - titleKey: "labelPreview.storage",
85   - fields: [
86   - { labelKey: "storage.temperature", value: `32-40${t("storage.tempRange")}`, bold: true },
87   - { labelKey: "storage.location", value: "Walk-in Cooler - Section B" },
88   - { labelKey: "storage.shelfLife", value: `5 ${t("storage.daysFromPrep")}` },
89   - { labelKey: "storage.handling", value: t("storage.instructions") },
90   - ],
91   - };
92   - case "expiry":
93   - return {
94   - titleKey: "labelPreview.expiry",
95   - fields: [
96   - { labelKey: "expiry.prepDate", value: today.toLocaleDateString() },
97   - { labelKey: "expiry.expiryDate", value: expiry.toLocaleDateString(), bold: true },
98   - { labelKey: "expiry.batchNumber", value: `${foodId.toUpperCase()}-${Date.now().toString().slice(-6)}` },
99   - { labelKey: "expiry.preparedBy", value: localStorage.getItem("userName") || "Staff" },
100   - ],
101   - };
102   - case "batch":
103   - return {
104   - titleKey: "labelPreview.batch",
105   - fields: [
106   - { labelKey: "batch.batchNumber", value: `BATCH-${Date.now().toString().slice(-8)}`, bold: true },
107   - { labelKey: "batch.productionDate", value: today.toLocaleDateString() },
108   - { labelKey: "batch.supplier", value: t("batch.supplierName") },
109   - { labelKey: "batch.lotNumber", value: `LOT-${Math.random().toString(36).substr(2, 9).toUpperCase()}` },
110   - ],
111   - };
112   - case "preparation":
113   - return {
114   - titleKey: "labelPreview.preparation",
115   - fields: [
116   - { labelKey: "prep.prepDate", value: today.toLocaleDateString() },
117   - { labelKey: "prep.prepTime", value: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) },
118   - { labelKey: "prep.preparedBy", value: localStorage.getItem("userName") || "Staff", bold: true },
119   - { labelKey: "prep.location", value: localStorage.getItem("storeName") || "Kitchen" },
120   - { labelKey: "prep.useBy", value: expiry.toLocaleDateString() },
121   - ],
122   - };
123   - default:
124   - return {
125   - titleKey: "FOOD LABEL",
126   - fields: [],
127   - };
128   - }
129   -};
130   -
131   -const getLabelTypeIcon = (type: string) => {
132   - const icons: Record<string, string> = {
133   - nutrition: "🥗",
134   - allergen: "⚠️",
135   - storage: "❄️",
136   - expiry: "📅",
137   - batch: "📦",
138   - preparation: "👨‍🍳",
139   - };
140   - return icons[type] || "🏷️";
141   -};
142   -
143   -export default function LabelPreview() {
144   - const navigate = useNavigate();
145   - const { labelType, foodId } = useParams<{ labelType: string; foodId: string }>();
146   - const { t } = useLanguage();
147   - const [isPrinting, setIsPrinting] = useState(false);
148   -
149   - const food = foodData[foodId || "food-001"];
150   - const labelData = getLabelPreviewData(labelType || "nutrition", foodId || "food-001", t);
151   -
152   - const handlePrint = () => {
153   - setIsPrinting(true);
154   - setTimeout(() => {
155   - setIsPrinting(false);
156   - toast.success(
157   - <div className="flex items-center gap-2">
158   - <CheckCircle className="w-5 h-5 text-green-600" />
159   - <span>{t("labels.print.success")}</span>
160   - </div>
161   - );
162   - navigate("/labels");
163   - }, 2000);
164   - };
165   -
166   - return (
167   - <div className="min-h-screen bg-gray-50 pb-32">
168   - {/* Header */}
169   - <div className="bg-white border-b border-gray-200 p-6">
170   - <button
171   - onClick={() => navigate(`/labels/${labelType}/foods`)}
172   - className="flex items-center text-blue-600 mb-4"
173   - >
174   - <ChevronLeft className="w-5 h-5" />
175   - <span className="text-base font-medium ml-1">{t("common.back")}</span>
176   - </button>
177   -
178   - <div className="flex items-center gap-3">
179   - <span className="text-3xl">{getLabelTypeIcon(labelType || "")}</span>
180   - <div>
181   - <h1 className="text-2xl font-semibold text-gray-900">
182   - {t("labels.preview.title")}
183   - </h1>
184   - <p className="text-base text-gray-600">
185   - {t("labels.preview.subtitle")}
186   - </p>
187   - </div>
188   - </div>
189   - </div>
190   -
191   - {/* Content */}
192   - <div className="p-6 space-y-6">
193   - {/* Food Info */}
194   - <Card className="p-6">
195   - <div className="flex items-center gap-4">
196   - <div className="w-20 h-20 rounded-lg overflow-hidden bg-gray-100 flex-shrink-0">
197   - <img
198   - src={food?.image}
199   - alt={t(food?.nameKey)}
200   - className="w-full h-full object-cover"
201   - />
202   - </div>
203   - <div>
204   - <h2 className="text-xl font-semibold text-gray-900 mb-1">
205   - {t(food?.nameKey)}
206   - </h2>
207   - <p className="text-sm text-gray-500">{t(food?.categoryKey)}</p>
208   - </div>
209   - </div>
210   - </Card>
211   -
212   - {/* Label Preview */}
213   - <div>
214   - <h2 className="text-lg font-semibold text-gray-900 mb-3">
215   - {t("labels.preview.labelPreview")}
216   - </h2>
217   -
218   - {/* Actual Label Design */}
219   - <Card className="p-0 overflow-hidden bg-white">
220   - <div className="border-4 border-black">
221   - {/* Label Header */}
222   - <div className="bg-black text-white p-4 text-center">
223   - <div className="text-3xl mb-2">{getLabelTypeIcon(labelType || "")}</div>
224   - <h3 className="text-xl font-bold tracking-wider">
225   - {t(labelData.titleKey)}
226   - </h3>
227   - </div>
228   -
229   - {/* Food Name */}
230   - <div className="border-b-4 border-black bg-gray-50 p-4">
231   - <h4 className="text-2xl font-bold text-center text-gray-900">
232   - {t(food?.nameKey)}
233   - </h4>
234   - </div>
235   -
236   - {/* Label Content */}
237   - <div className="p-6 space-y-3">
238   - {labelData.fields.map((field, index) => (
239   - <div
240   - key={index}
241   - className={`flex justify-between items-start pb-2 ${
242   - index < labelData.fields.length - 1 ? "border-b border-gray-200" : ""
243   - } ${field.indent ? "pl-4" : ""}`}
244   - >
245   - <span
246   - className={`text-base ${
247   - field.bold ? "font-bold" : "font-medium"
248   - } ${field.warning ? "text-red-600" : "text-gray-700"}`}
249   - >
250   - {t(field.labelKey)}
251   - </span>
252   - <span
253   - className={`text-base ${
254   - field.bold ? "font-bold" : ""
255   - } ${field.warning ? "text-red-600 font-bold" : "text-gray-900"} text-right ml-4`}
256   - >
257   - {field.value}
258   - </span>
259   - </div>
260   - ))}
261   - </div>
262   -
263   - {/* Label Footer */}
264   - <div className="border-t-4 border-black bg-gray-50 p-4">
265   - <div className="text-sm text-gray-600 text-center">
266   - <p className="mb-1">
267   - <strong>{t("labels.preview.printedBy")}:</strong>{" "}
268   - {localStorage.getItem("userName") || "Staff"}
269   - </p>
270   - <p>
271   - <strong>{t("labels.preview.printDate")}:</strong>{" "}
272   - {new Date().toLocaleString()}
273   - </p>
274   - </div>
275   - </div>
276   - </div>
277   - </Card>
278   - </div>
279   -
280   - {/* Info Note */}
281   - <Card className="p-4 bg-blue-50 border-blue-200">
282   - <p className="text-sm text-blue-900">
283   - <strong>{t("common.note")}:</strong> {t("labels.preview.note")}
284   - </p>
285   - </Card>
286   - </div>
287   -
288   - {/* Fixed Bottom Button */}
289   - <div className="fixed bottom-20 left-0 right-0 bg-white border-t border-gray-200 p-6">
290   - <div className="max-w-[480px] mx-auto">
291   - <Button
292   - onClick={handlePrint}
293   - disabled={isPrinting}
294   - className="w-full h-14 text-base font-semibold"
295   - >
296   - <Printer className="w-5 h-5 mr-2" />
297   - {isPrinting ? t("labels.print.printing") : t("labels.print.button")}
298   - </Button>
299   - </div>
300   - </div>
301   - </div>
302   - );
303   -}
美国版/Food Labeling Management App React/src/app/pages/Labels.tsx deleted
1   -import { useState } from "react";
2   -import { useNavigate } from "react-router";
3   -import { Card } from "../components/ui/card";
4   -import {
5   - ChevronRight,
6   - Utensils,
7   - AlertTriangle,
8   - Snowflake,
9   - Calendar,
10   - Package,
11   - ChefHat,
12   - Plus,
13   - Clock
14   -} from "lucide-react";
15   -import { useLanguage } from "../contexts/LanguageContext";
16   -
17   -interface LabelType {
18   - id: string;
19   - nameKey: string;
20   - descKey: string;
21   - icon: any;
22   - iconColor: string;
23   - bgColor: string;
24   - foodCount: number;
25   -}
26   -
27   -interface PrintedLabel {
28   - id: string;
29   - labelType: string;
30   - labelTypeNameKey: string;
31   - foodNameKey: string;
32   - icon: any;
33   - iconColor: string;
34   - bgColor: string;
35   - keyInfo: { labelKey: string; value: string }[];
36   - printedBy: string;
37   - printedAt: string;
38   - status: "active" | "expired";
39   -}
40   -
41   -const labelTypes: LabelType[] = [
42   - {
43   - id: "nutrition",
44   - nameKey: "labelType.nutrition.name",
45   - descKey: "labelType.nutrition.desc",
46   - icon: Utensils,
47   - iconColor: "text-blue-600",
48   - bgColor: "bg-blue-50",
49   - foodCount: 156,
50   - },
51   - {
52   - id: "allergen",
53   - nameKey: "labelType.allergen.name",
54   - descKey: "labelType.allergen.desc",
55   - icon: AlertTriangle,
56   - iconColor: "text-red-600",
57   - bgColor: "bg-red-50",
58   - foodCount: 89,
59   - },
60   - {
61   - id: "storage",
62   - nameKey: "labelType.storage.name",
63   - descKey: "labelType.storage.desc",
64   - icon: Snowflake,
65   - iconColor: "text-cyan-600",
66   - bgColor: "bg-cyan-50",
67   - foodCount: 134,
68   - },
69   - {
70   - id: "expiry",
71   - nameKey: "labelType.expiry.name",
72   - descKey: "labelType.expiry.desc",
73   - icon: Calendar,
74   - iconColor: "text-orange-600",
75   - bgColor: "bg-orange-50",
76   - foodCount: 203,
77   - },
78   - {
79   - id: "batch",
80   - nameKey: "labelType.batch.name",
81   - descKey: "labelType.batch.desc",
82   - icon: Package,
83   - iconColor: "text-purple-600",
84   - bgColor: "bg-purple-50",
85   - foodCount: 78,
86   - },
87   - {
88   - id: "preparation",
89   - nameKey: "labelType.preparation.name",
90   - descKey: "labelType.preparation.desc",
91   - icon: ChefHat,
92   - iconColor: "text-green-600",
93   - bgColor: "bg-green-50",
94   - foodCount: 112,
95   - },
96   -];
97   -
98   -// Mock printed labels data
99   -const mockPrintedLabels: PrintedLabel[] = [
100   - {
101   - id: "label-001",
102   - labelType: "expiry",
103   - labelTypeNameKey: "labelType.expiry.name",
104   - foodNameKey: "food.chickenBreast",
105   - icon: Calendar,
106   - iconColor: "text-orange-600",
107   - bgColor: "bg-orange-50",
108   - keyInfo: [
109   - { labelKey: "expiry.prepDate", value: "2026-02-27" },
110   - { labelKey: "expiry.expiryDate", value: "2026-03-04" },
111   - { labelKey: "expiry.batchNumber", value: "FOOD-001-123456" },
112   - ],
113   - printedBy: "John Smith",
114   - printedAt: "2026-02-27 09:30",
115   - status: "active",
116   - },
117   - {
118   - id: "label-002",
119   - labelType: "storage",
120   - labelTypeNameKey: "labelType.storage.name",
121   - foodNameKey: "food.salmonFillet",
122   - icon: Snowflake,
123   - iconColor: "text-cyan-600",
124   - bgColor: "bg-cyan-50",
125   - keyInfo: [
126   - { labelKey: "storage.temperature", value: "32-40°F" },
127   - { labelKey: "storage.location", value: "Walk-in Cooler - B" },
128   - { labelKey: "storage.shelfLife", value: "5 days" },
129   - ],
130   - printedBy: "Sarah Lee",
131   - printedAt: "2026-02-27 08:15",
132   - status: "active",
133   - },
134   - {
135   - id: "label-003",
136   - labelType: "allergen",
137   - labelTypeNameKey: "labelType.allergen.name",
138   - foodNameKey: "food.caesarSalad",
139   - icon: AlertTriangle,
140   - iconColor: "text-red-600",
141   - bgColor: "bg-red-50",
142   - keyInfo: [
143   - { labelKey: "allergen.contains", value: "Dairy, Eggs, Fish" },
144   - { labelKey: "allergen.mayContain", value: "Gluten, Soy" },
145   - ],
146   - printedBy: "Mike Chen",
147   - printedAt: "2026-02-26 16:45",
148   - status: "active",
149   - },
150   - {
151   - id: "label-004",
152   - labelType: "batch",
153   - labelTypeNameKey: "labelType.batch.name",
154   - foodNameKey: "food.beefPatties",
155   - icon: Package,
156   - iconColor: "text-purple-600",
157   - bgColor: "bg-purple-50",
158   - keyInfo: [
159   - { labelKey: "batch.batchNumber", value: "BATCH-20260227" },
160   - { labelKey: "batch.productionDate", value: "2026-02-27" },
161   - { labelKey: "batch.lotNumber", value: "LOT-ABC123XYZ" },
162   - ],
163   - printedBy: "Emma Wilson",
164   - printedAt: "2026-02-26 14:20",
165   - status: "active",
166   - },
167   - {
168   - id: "label-005",
169   - labelType: "preparation",
170   - labelTypeNameKey: "labelType.preparation.name",
171   - foodNameKey: "food.marinaraSauce",
172   - icon: ChefHat,
173   - iconColor: "text-green-600",
174   - bgColor: "bg-green-50",
175   - keyInfo: [
176   - { labelKey: "prep.prepDate", value: "2026-02-27" },
177   - { labelKey: "prep.prepTime", value: "07:30 AM" },
178   - { labelKey: "prep.preparedBy", value: "Chef David" },
179   - ],
180   - printedBy: "David Kim",
181   - printedAt: "2026-02-26 12:00",
182   - status: "active",
183   - },
184   - {
185   - id: "label-006",
186   - labelType: "nutrition",
187   - labelTypeNameKey: "labelType.nutrition.name",
188   - foodNameKey: "food.vegetables",
189   - icon: Utensils,
190   - iconColor: "text-blue-600",
191   - bgColor: "bg-blue-50",
192   - keyInfo: [
193   - { labelKey: "nutrition.calories", value: "45 kcal" },
194   - { labelKey: "nutrition.protein", value: "2.5g" },
195   - { labelKey: "nutrition.totalFat", value: "0.5g" },
196   - ],
197   - printedBy: "Lisa Brown",
198   - printedAt: "2026-02-25 18:30",
199   - status: "active",
200   - },
201   -];
202   -
203   -export default function Labels() {
204   - const navigate = useNavigate();
205   - const { t } = useLanguage();
206   - const [activeTab, setActiveTab] = useState<"create" | "history">("create");
207   -
208   - return (
209   - <div className="min-h-screen bg-gray-50">
210   - {/* Header */}
211   - <div className="bg-white border-b border-gray-200">
212   - <div className="p-4 pb-0">
213   - <h1 className="text-2xl font-semibold text-gray-900 mb-1">
214   - {t("labels.title")}
215   - </h1>
216   - <p className="text-sm text-gray-600 mb-4">
217   - {activeTab === "create" ? t("labels.selectType") : t("labels.history.subtitle")}
218   - </p>
219   - </div>
220   -
221   - {/* Tabs */}
222   - <div className="flex border-b border-gray-200">
223   - <button
224   - onClick={() => setActiveTab("create")}
225   - className={`flex-1 px-4 py-3 text-sm font-medium border-b-2 transition-colors ${
226   - activeTab === "create"
227   - ? "border-blue-600 text-blue-600"
228   - : "border-transparent text-gray-600 hover:text-gray-900"
229   - }`}
230   - >
231   - <Plus className="w-4 h-4 inline-block mr-1 mb-0.5" />
232   - {t("labels.tabs.create")}
233   - </button>
234   - <button
235   - onClick={() => setActiveTab("history")}
236   - className={`flex-1 px-4 py-3 text-sm font-medium border-b-2 transition-colors ${
237   - activeTab === "history"
238   - ? "border-blue-600 text-blue-600"
239   - : "border-transparent text-gray-600 hover:text-gray-900"
240   - }`}
241   - >
242   - <Clock className="w-4 h-4 inline-block mr-1 mb-0.5" />
243   - {t("labels.tabs.history")}
244   - </button>
245   - </div>
246   - </div>
247   -
248   - {/* Content */}
249   - {activeTab === "create" ? (
250   - /* Create Tab - Label Types Grid */
251   - <div className="p-3">
252   - <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-2.5">
253   - {labelTypes.map((labelType) => {
254   - const Icon = labelType.icon;
255   - return (
256   - <Card
257   - key={labelType.id}
258   - className="p-3 cursor-pointer hover:shadow-md transition-shadow"
259   - onClick={() => navigate(`/labels/${labelType.id}/foods`)}
260   - >
261   - <div className="flex items-center gap-3">
262   - <div className={`w-11 h-11 rounded-full ${labelType.bgColor} flex items-center justify-center flex-shrink-0`}>
263   - <Icon className={`w-5 h-5 ${labelType.iconColor}`} />
264   - </div>
265   - <div className="flex-1 min-w-0">
266   - <h3 className="text-sm font-semibold text-gray-900">
267   - {t(labelType.nameKey)}
268   - </h3>
269   - <span className="text-xs text-gray-500">
270   - {labelType.foodCount} {t("labels.foodItems")}
271   - </span>
272   - </div>
273   - <ChevronRight className="w-4 h-4 text-gray-400 flex-shrink-0" />
274   - </div>
275   - </Card>
276   - );
277   - })}
278   - </div>
279   - </div>
280   - ) : (
281   - /* History Tab - Printed Labels List */
282   - <div className="p-3">
283   - <div className="space-y-2.5">
284   - {mockPrintedLabels.map((label) => {
285   - const Icon = label.icon;
286   - return (
287   - <Card
288   - key={label.id}
289   - className="p-3 cursor-pointer hover:shadow-md transition-shadow"
290   - >
291   - <div className="flex items-start gap-3">
292   - <div className={`w-11 h-11 rounded-full ${label.bgColor} flex items-center justify-center flex-shrink-0 mt-0.5`}>
293   - <Icon className={`w-5 h-5 ${label.iconColor}`} />
294   - </div>
295   - <div className="flex-1 min-w-0">
296   - {/* Food Name & Label Type */}
297   - <div className="flex items-start justify-between gap-2 mb-2">
298   - <div>
299   - <h3 className="text-sm font-semibold text-gray-900">
300   - {t(label.foodNameKey)}
301   - </h3>
302   - <span className="text-xs text-gray-500">
303   - {t(label.labelTypeNameKey)}
304   - </span>
305   - </div>
306   - <span
307   - className={`text-xs px-2 py-0.5 rounded-full flex-shrink-0 ${
308   - label.status === "active"
309   - ? "bg-green-50 text-green-700"
310   - : "bg-gray-100 text-gray-600"
311   - }`}
312   - >
313   - {t(`labels.status.${label.status}`)}
314   - </span>
315   - </div>
316   -
317   - {/* Key Information */}
318   - <div className="space-y-1 mb-2">
319   - {label.keyInfo.map((info, index) => (
320   - <div key={index} className="flex items-center justify-between text-xs">
321   - <span className="text-gray-600">{t(info.labelKey)}:</span>
322   - <span className="font-medium text-gray-900">{info.value}</span>
323   - </div>
324   - ))}
325   - </div>
326   -
327   - {/* Footer Info */}
328   - <div className="flex items-center justify-between text-xs text-gray-500 pt-2 border-t border-gray-100">
329   - <span>{t("labels.printedBy")}: {label.printedBy}</span>
330   - <span>{label.printedAt}</span>
331   - </div>
332   - </div>
333   - </div>
334   - </Card>
335   - );
336   - })}
337   - </div>
338   -
339   - {/* Empty State - if no labels */}
340   - {mockPrintedLabels.length === 0 && (
341   - <div className="text-center py-12">
342   - <div className="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center mx-auto mb-4">
343   - <Clock className="w-8 h-8 text-gray-400" />
344   - </div>
345   - <h3 className="text-base font-semibold text-gray-900 mb-1">
346   - {t("labels.history.empty.title")}
347   - </h3>
348   - <p className="text-sm text-gray-600">
349   - {t("labels.history.empty.desc")}
350   - </p>
351   - </div>
352   - )}
353   - </div>
354   - )}
355   - </div>
356   - );
357   -}
358 0 \ No newline at end of file
美国版/Food Labeling Management App React/src/app/pages/Login.tsx deleted
1   -import { useState } from "react";
2   -import { useNavigate } from "react-router";
3   -import { Button } from "../components/ui/button";
4   -import { Input } from "../components/ui/input";
5   -import { Label } from "../components/ui/label";
6   -import { Switch } from "../components/ui/switch";
7   -import { Utensils } from "lucide-react";
8   -import { useLanguage } from "../contexts/LanguageContext";
9   -import { toast } from "sonner";
10   -
11   -export default function Login() {
12   - const navigate = useNavigate();
13   - const { t } = useLanguage();
14   - const [email, setEmail] = useState("");
15   - const [password, setPassword] = useState("");
16   - const [rememberMe, setRememberMe] = useState(false);
17   - const [isLoading, setIsLoading] = useState(false);
18   -
19   - const handleLogin = (e: React.FormEvent) => {
20   - e.preventDefault();
21   - setIsLoading(true);
22   -
23   - // Simulate login
24   - setTimeout(() => {
25   - localStorage.setItem("isLoggedIn", "true");
26   - localStorage.setItem("userName", "John Smith");
27   - toast.success(t("login.loginSuccess"));
28   - navigate("/store-select");
29   - setIsLoading(false);
30   - }, 1000);
31   - };
32   -
33   - return (
34   - <div className="min-h-screen bg-white flex items-center justify-center p-6">
35   - <div className="w-full max-w-md">
36   - {/* Logo and Title */}
37   - <div className="text-center mb-12">
38   - <div className="inline-flex items-center justify-center w-20 h-20 bg-blue-600 rounded-2xl mb-6">
39   - <Utensils className="w-10 h-10 text-white" />
40   - </div>
41   - <h1 className="text-2xl font-semibold text-gray-900 mb-2">
42   - {t("login.appName")}
43   - </h1>
44   - <p className="text-base text-gray-500">
45   - {t("login.employeePortal")}
46   - </p>
47   - </div>
48   -
49   - {/* Login Form */}
50   - <form onSubmit={handleLogin} className="space-y-6">
51   - <div className="space-y-2">
52   - <Label htmlFor="email" className="text-base">{t("login.email")}</Label>
53   - <Input
54   - id="email"
55   - type="email"
56   - placeholder={t("login.emailPlaceholder")}
57   - value={email}
58   - onChange={(e) => setEmail(e.target.value)}
59   - required
60   - className="h-12 text-base"
61   - />
62   - </div>
63   -
64   - <div className="space-y-2">
65   - <Label htmlFor="password" className="text-base">{t("login.password")}</Label>
66   - <Input
67   - id="password"
68   - type="password"
69   - placeholder={t("login.passwordPlaceholder")}
70   - value={password}
71   - onChange={(e) => setPassword(e.target.value)}
72   - required
73   - className="h-12 text-base"
74   - />
75   - </div>
76   -
77   - <div className="flex items-center justify-between">
78   - <div className="flex items-center space-x-2">
79   - <Switch
80   - id="remember"
81   - checked={rememberMe}
82   - onCheckedChange={setRememberMe}
83   - />
84   - <Label htmlFor="remember" className="text-base text-gray-700 cursor-pointer">
85   - {t("login.rememberMe")}
86   - </Label>
87   - </div>
88   - <button
89   - type="button"
90   - className="text-base text-blue-600 hover:text-blue-700 font-medium"
91   - >
92   - {t("login.forgotPassword")}
93   - </button>
94   - </div>
95   -
96   - <Button
97   - type="submit"
98   - className="w-full h-12 text-base font-semibold"
99   - disabled={isLoading}
100   - >
101   - {isLoading ? t("login.signingIn") : t("login.signIn")}
102   - </Button>
103   - </form>
104   -
105   - <div className="mt-8 text-center text-sm text-gray-500">
106   - <p>{t("login.copyright")}</p>
107   - </div>
108   - </div>
109   - </div>
110   - );
111   -}
112 0 \ No newline at end of file
美国版/Food Labeling Management App React/src/app/pages/More.tsx deleted
1   -import { useNavigate } from "react-router";
2   -import { Card } from "../components/ui/card";
3   -import {
4   - User,
5   - Printer,
6   - MapPin,
7   - RefreshCw,
8   - Languages,
9   - HelpCircle,
10   - LogOut,
11   - ChevronRight,
12   -} from "lucide-react";
13   -import {
14   - AlertDialog,
15   - AlertDialogAction,
16   - AlertDialogCancel,
17   - AlertDialogContent,
18   - AlertDialogDescription,
19   - AlertDialogFooter,
20   - AlertDialogHeader,
21   - AlertDialogTitle,
22   - AlertDialogTrigger,
23   -} from "../components/ui/alert-dialog";
24   -import { useLanguage } from "../contexts/LanguageContext";
25   -
26   -export default function More() {
27   - const navigate = useNavigate();
28   - const { t } = useLanguage();
29   - const userName = localStorage.getItem("userName") || "Employee";
30   -
31   - const handleLogout = () => {
32   - localStorage.removeItem("isLoggedIn");
33   - localStorage.removeItem("userName");
34   - localStorage.removeItem("storeName");
35   - navigate("/login");
36   - };
37   -
38   - return (
39   - <div className="min-h-screen bg-gray-50">
40   - {/* Header */}
41   - <div className="bg-white border-b border-gray-200 p-6">
42   - <h1 className="text-2xl font-semibold text-gray-900 mb-1">{t("more.title")}</h1>
43   - <p className="text-base text-gray-600">{userName}</p>
44   - </div>
45   -
46   - {/* Menu Items */}
47   - <div className="p-6">
48   - <div className="space-y-2">
49   - <Card
50   - className="p-5 cursor-pointer hover:shadow-md transition-shadow"
51   - onClick={() => navigate("/more/profile")}
52   - >
53   - <div className="flex items-center gap-4">
54   - <div className="w-12 h-12 rounded-full bg-blue-100 flex items-center justify-center flex-shrink-0">
55   - <User className="w-6 h-6 text-blue-600" />
56   - </div>
57   - <div className="flex-1 min-w-0">
58   - <h3 className="text-base font-semibold text-gray-900">
59   - {t("more.profile")}
60   - </h3>
61   - <p className="text-sm text-gray-600">
62   - {t("more.profile.desc")}
63   - </p>
64   - </div>
65   - <ChevronRight className="w-5 h-5 text-gray-400 flex-shrink-0" />
66   - </div>
67   - </Card>
68   -
69   - <Card
70   - className="p-5 cursor-pointer hover:shadow-md transition-shadow"
71   - onClick={() => navigate("/more/printers")}
72   - >
73   - <div className="flex items-center gap-4">
74   - <div className="w-12 h-12 rounded-full bg-gray-100 flex items-center justify-center flex-shrink-0">
75   - <Printer className="w-6 h-6 text-gray-600" />
76   - </div>
77   - <div className="flex-1 min-w-0">
78   - <h3 className="text-base font-semibold text-gray-900">
79   - {t("more.printers")}
80   - </h3>
81   - <p className="text-sm text-gray-600">
82   - {t("more.printers.desc")}
83   - </p>
84   - </div>
85   - <ChevronRight className="w-5 h-5 text-gray-400 flex-shrink-0" />
86   - </div>
87   - </Card>
88   -
89   - <Card
90   - className="p-5 cursor-pointer hover:shadow-md transition-shadow"
91   - onClick={() => navigate("/more/location")}
92   - >
93   - <div className="flex items-center gap-4">
94   - <div className="w-12 h-12 rounded-full bg-gray-100 flex items-center justify-center flex-shrink-0">
95   - <MapPin className="w-6 h-6 text-gray-600" />
96   - </div>
97   - <div className="flex-1 min-w-0">
98   - <h3 className="text-base font-semibold text-gray-900">
99   - {t("more.location")}
100   - </h3>
101   - <p className="text-sm text-gray-600">
102   - {t("more.location.desc")}
103   - </p>
104   - </div>
105   - <ChevronRight className="w-5 h-5 text-gray-400 flex-shrink-0" />
106   - </div>
107   - </Card>
108   -
109   - <Card
110   - className="p-5 cursor-pointer hover:shadow-md transition-shadow"
111   - onClick={() => navigate("/more/sync")}
112   - >
113   - <div className="flex items-center gap-4">
114   - <div className="w-12 h-12 rounded-full bg-gray-100 flex items-center justify-center flex-shrink-0">
115   - <RefreshCw className="w-6 h-6 text-gray-600" />
116   - </div>
117   - <div className="flex-1 min-w-0">
118   - <h3 className="text-base font-semibold text-gray-900">
119   - {t("more.sync")}
120   - </h3>
121   - <p className="text-sm text-gray-600">
122   - {t("more.sync.desc")}
123   - </p>
124   - </div>
125   - <ChevronRight className="w-5 h-5 text-gray-400 flex-shrink-0" />
126   - </div>
127   - </Card>
128   -
129   - <Card
130   - className="p-5 cursor-pointer hover:shadow-md transition-shadow"
131   - onClick={() => navigate("/more/language")}
132   - >
133   - <div className="flex items-center gap-4">
134   - <div className="w-12 h-12 rounded-full bg-gray-100 flex items-center justify-center flex-shrink-0">
135   - <Languages className="w-6 h-6 text-gray-600" />
136   - </div>
137   - <div className="flex-1 min-w-0">
138   - <h3 className="text-base font-semibold text-gray-900">
139   - {t("more.language")}
140   - </h3>
141   - <p className="text-sm text-gray-600">
142   - {t("more.language.desc")}
143   - </p>
144   - </div>
145   - <ChevronRight className="w-5 h-5 text-gray-400 flex-shrink-0" />
146   - </div>
147   - </Card>
148   -
149   - <Card
150   - className="p-5 cursor-pointer hover:shadow-md transition-shadow"
151   - onClick={() => navigate("/more/support")}
152   - >
153   - <div className="flex items-center gap-4">
154   - <div className="w-12 h-12 rounded-full bg-gray-100 flex items-center justify-center flex-shrink-0">
155   - <HelpCircle className="w-6 h-6 text-gray-600" />
156   - </div>
157   - <div className="flex-1 min-w-0">
158   - <h3 className="text-base font-semibold text-gray-900">
159   - {t("more.support")}
160   - </h3>
161   - <p className="text-sm text-gray-600">
162   - {t("more.support.desc")}
163   - </p>
164   - </div>
165   - <ChevronRight className="w-5 h-5 text-gray-400 flex-shrink-0" />
166   - </div>
167   - </Card>
168   -
169   - {/* Logout */}
170   - <AlertDialog>
171   - <AlertDialogTrigger asChild>
172   - <Card className="p-4 cursor-pointer hover:shadow-md transition-shadow border-red-200">
173   - <div className="flex items-center gap-4">
174   - <div className="p-2 bg-red-50 rounded-lg">
175   - <LogOut className="w-6 h-6 text-red-600" />
176   - </div>
177   - <div className="flex-1">
178   - <h3 className="text-base font-semibold text-red-600 mb-0.5">
179   - {t("more.logout")}
180   - </h3>
181   - <p className="text-sm text-gray-500">Sign out of your account</p>
182   - </div>
183   - <ChevronRight className="w-5 h-5 text-gray-400" />
184   - </div>
185   - </Card>
186   - </AlertDialogTrigger>
187   - <AlertDialogContent>
188   - <AlertDialogHeader>
189   - <AlertDialogTitle>Confirm Logout</AlertDialogTitle>
190   - <AlertDialogDescription>
191   - Are you sure you want to logout? Any unsaved changes will be lost.
192   - </AlertDialogDescription>
193   - </AlertDialogHeader>
194   - <AlertDialogFooter>
195   - <AlertDialogCancel>{t("common.cancel")}</AlertDialogCancel>
196   - <AlertDialogAction
197   - onClick={handleLogout}
198   - className="bg-red-600 hover:bg-red-700"
199   - >
200   - {t("more.logout")}
201   - </AlertDialogAction>
202   - </AlertDialogFooter>
203   - </AlertDialogContent>
204   - </AlertDialog>
205   - </div>
206   - </div>
207   -
208   - {/* App Info */}
209   - <div className="p-6 text-center">
210   - <p className="text-sm text-gray-500 mb-1">Food Label System</p>
211   - <p className="text-sm text-gray-400">Version 1.0.0</p>
212   - </div>
213   - </div>
214   - );
215   -}
216 0 \ No newline at end of file
美国版/Food Labeling Management App React/src/app/pages/NotFound.tsx deleted
1   -import { useNavigate } from "react-router";
2   -import { Button } from "../components/ui/button";
3   -import { FileQuestion } from "lucide-react";
4   -
5   -export default function NotFound() {
6   - const navigate = useNavigate();
7   -
8   - return (
9   - <div className="min-h-screen bg-gray-50 flex items-center justify-center p-6">
10   - <div className="text-center">
11   - <div className="w-24 h-24 bg-gray-100 rounded-full flex items-center justify-center mx-auto mb-6">
12   - <FileQuestion className="w-12 h-12 text-gray-400" />
13   - </div>
14   - <h1 className="text-2xl font-semibold text-gray-900 mb-2">
15   - Page Not Found
16   - </h1>
17   - <p className="text-base text-gray-600 mb-8 max-w-sm mx-auto">
18   - The page you're looking for doesn't exist or has been moved.
19   - </p>
20   - <Button
21   - onClick={() => navigate("/")}
22   - className="h-12 text-base font-semibold px-8"
23   - >
24   - Go to Dashboard
25   - </Button>
26   - </div>
27   - </div>
28   - );
29   -}
美国版/Food Labeling Management App React/src/app/pages/StoreSelect.tsx deleted
1   -import { useState } from "react";
2   -import { useNavigate } from "react-router";
3   -import { Card } from "../components/ui/card";
4   -import { Button } from "../components/ui/button";
5   -import { MapPin, ChevronRight, Building2 } from "lucide-react";
6   -import { useLanguage } from "../contexts/LanguageContext";
7   -import { toast } from "sonner";
8   -
9   -interface Store {
10   - id: string;
11   - nameKey: string;
12   - address: string;
13   - manager: string;
14   - phone: string;
15   -}
16   -
17   -const stores: Store[] = [
18   - {
19   - id: "1",
20   - nameKey: "login.store1",
21   - address: "123 Main St, New York, NY 10001",
22   - manager: "Sarah Johnson",
23   - phone: "(212) 555-0101",
24   - },
25   - {
26   - id: "2",
27   - nameKey: "login.store2",
28   - address: "456 Oak Ave, Brooklyn, NY 11201",
29   - manager: "Michael Chen",
30   - phone: "(718) 555-0102",
31   - },
32   - {
33   - id: "3",
34   - nameKey: "login.store3",
35   - address: "789 Pine Rd, Queens, NY 11354",
36   - manager: "Emily Rodriguez",
37   - phone: "(718) 555-0103",
38   - },
39   - {
40   - id: "4",
41   - nameKey: "login.store4",
42   - address: "321 Elm St, Manhattan, NY 10002",
43   - manager: "David Kim",
44   - phone: "(212) 555-0104",
45   - },
46   -];
47   -
48   -export default function StoreSelect() {
49   - const navigate = useNavigate();
50   - const { t } = useLanguage();
51   - const [selectedStore, setSelectedStore] = useState<string>("");
52   - const userName = localStorage.getItem("userName") || "Employee";
53   -
54   - const handleConfirm = () => {
55   - if (!selectedStore) {
56   - toast.error(t("login.selectStoreError"));
57   - return;
58   - }
59   -
60   - const store = stores.find((s) => s.id === selectedStore);
61   - if (store) {
62   - localStorage.setItem("storeId", selectedStore);
63   - localStorage.setItem("storeName", t(store.nameKey));
64   - toast.success(t("login.storeSelected"));
65   - navigate("/");
66   - }
67   - };
68   -
69   - return (
70   - <div className="min-h-screen bg-gray-50">
71   - {/* Header */}
72   - <div className="bg-white border-b border-gray-200 p-6">
73   - <div className="flex items-center gap-3 mb-4">
74   - <div className="p-3 bg-blue-50 rounded-xl">
75   - <Building2 className="w-6 h-6 text-blue-600" />
76   - </div>
77   - <div>
78   - <h1 className="text-2xl font-semibold text-gray-900">
79   - {t("login.selectStore")}
80   - </h1>
81   - <p className="text-base text-gray-600">
82   - {t("login.welcomeUser")} {userName}
83   - </p>
84   - </div>
85   - </div>
86   - <p className="text-base text-gray-600">
87   - {t("login.selectStoreDesc")}
88   - </p>
89   - </div>
90   -
91   - {/* Store List */}
92   - <div className="p-6 space-y-3">
93   - {stores.map((store) => (
94   - <Card
95   - key={store.id}
96   - className={`p-5 cursor-pointer transition-all ${
97   - selectedStore === store.id
98   - ? "border-2 border-blue-600 bg-blue-50 shadow-md"
99   - : "border-2 border-transparent hover:shadow-md"
100   - }`}
101   - onClick={() => setSelectedStore(store.id)}
102   - >
103   - <div className="flex items-start gap-4">
104   - {/* Icon */}
105   - <div
106   - className={`p-3 rounded-lg flex-shrink-0 ${
107   - selectedStore === store.id
108   - ? "bg-blue-600"
109   - : "bg-gray-100"
110   - }`}
111   - >
112   - <MapPin
113   - className={`w-6 h-6 ${
114   - selectedStore === store.id
115   - ? "text-white"
116   - : "text-gray-600"
117   - }`}
118   - />
119   - </div>
120   -
121   - {/* Content */}
122   - <div className="flex-1 min-w-0">
123   - <h3 className="text-lg font-semibold text-gray-900 mb-2">
124   - {t(store.nameKey)}
125   - </h3>
126   - <div className="space-y-1">
127   - <p className="text-sm text-gray-600 flex items-start gap-2">
128   - <MapPin className="w-4 h-4 mt-0.5 flex-shrink-0" />
129   - <span>{store.address}</span>
130   - </p>
131   - <p className="text-sm text-gray-600">
132   - {t("location.storeManager")}: {store.manager}
133   - </p>
134   - <p className="text-sm text-gray-600">
135   - {t("location.storePhone")}: {store.phone}
136   - </p>
137   - </div>
138   - </div>
139   -
140   - {/* Arrow/Check */}
141   - <div className="flex-shrink-0">
142   - {selectedStore === store.id ? (
143   - <div className="w-6 h-6 bg-blue-600 rounded-full flex items-center justify-center">
144   - <svg
145   - className="w-4 h-4 text-white"
146   - fill="none"
147   - strokeLinecap="round"
148   - strokeLinejoin="round"
149   - strokeWidth="2"
150   - viewBox="0 0 24 24"
151   - stroke="currentColor"
152   - >
153   - <path d="M5 13l4 4L19 7" />
154   - </svg>
155   - </div>
156   - ) : (
157   - <ChevronRight className="w-6 h-6 text-gray-400" />
158   - )}
159   - </div>
160   - </div>
161   - </Card>
162   - ))}
163   - </div>
164   -
165   - {/* Bottom Button */}
166   - <div className="fixed bottom-0 left-0 right-0 p-6 bg-white border-t border-gray-200">
167   - <Button
168   - onClick={handleConfirm}
169   - disabled={!selectedStore}
170   - className="w-full h-12 text-base font-semibold"
171   - >
172   - {t("common.confirm")}
173   - </Button>
174   - </div>
175   - </div>
176   - );
177   -}
178 0 \ No newline at end of file