diff --git a/dictionary/en.json b/dictionary/en.json index 60f7e8e..e6f902c 100644 --- a/dictionary/en.json +++ b/dictionary/en.json @@ -6,7 +6,8 @@ "Header": { "appName": "Fast3DText", "editorName": "Editor", - "blogName": "Blog" + "blogName": "Blog", + "styleName": "Style Library" }, "ErrorPage": { "title": "Some thing went wrong", @@ -106,5 +107,28 @@ "ctaTitle": "Create Your 3D Background Now", "ctaSubtitle": "Start generating professional 3D 'Do Not Write On This Page' designs", "ctaButton": "Generate 3D Text" + }, + "StylePage": { + "title": "3D Text Styles Library", + "seoTitle": "3D Text Styles Library", + "seoDescription": "Explore our collection of 3D text styles tutorials, tips and inspiration. Learn how to create stunning 3D text effects for your projects.", + "templateFontLabel": "Font", + "templateBgColorLabel": "Background Color", + "templateTextColorLabel": "Text Color", + "templateTextGradientColorLabel": "Text Gradient Color" + }, + "StyleBarbie": { + "title": "Create Stunning Barbie-Pink 3D Text", + "summary": "Use our online 3D text editor to craft eye-catching Barbie-inspired designs.", + "cta": "Start Designing Now", + "simpleTitle": "Barbie Pink 3D Text Generator Online", + "description": "Looking for a way to create Barbie-style 3D text? Our editor lets you apply pink gradients, custom fonts, and high-quality 3D effects all from your browser.", + "templateTitle": "Template Style", + "templateFont": "Bartex", + "templateBgColor": "#ffe3f0 (soft pink)", + "templateTextGradient": "#ff5ac7 → #ff94da", + "tipsTitle": "Tips", + "content1": "The Barbie-pink style is perfect for playful logos, birthday cards, social media graphics, and more. With our easy-to-use editor, you can adjust shadows, lighting, and font styles effortlessly.", + "content2": "Get started in seconds—no downloads required. Just enter your text, choose a style, and export beautiful 3D visuals instantly." } } \ No newline at end of file diff --git a/dictionary/zh.json b/dictionary/zh.json index f7a3a12..17e4a7c 100644 --- a/dictionary/zh.json +++ b/dictionary/zh.json @@ -6,7 +6,8 @@ "Header": { "appName": "Fast3DText", "editorName": "编辑器", - "blogName": "博文记录" + "blogName": "博文记录", + "styleName": "模板库" }, "ErrorPage": { "title": " 错误页面", @@ -106,5 +107,28 @@ "ctaTitle": "立即创建3D'请勿在此页书写'背景", "ctaSubtitle": "开始生成专业的3D文字设计", "ctaButton": "生成3D文字" + }, + "StylePage": { + "title": "模板库", + "seoTitle": "3D文字模板库", + "seoDescription": "探索我们的3D文字设计不同风格集合。学习如何为您的项目创建惊艳的3D文字效果。", + "templateFontLabel": "字体", + "templateBgColorLabel": "背景颜色", + "templateTextColorLabel": "文字颜色", + "templateTextGradientColorLabel": "文字渐变色" + }, + "StyleBarbie": { + "title": "创建梦幻芭比粉3D文字", + "summary": "使用我们的在线3D文字编辑器,轻松打造吸睛的3D芭比风格设计。", + "cta": "立即开始设计", + "simpleTitle": "在线芭比粉3D文字生成器", + "description": "想要制作芭比风格的3D文字?我们的编辑器支持粉色渐变、自定义字体与高质量的三维效果,全部在浏览器中完成。", + "templateTitle": "模板风格", + "templateFont": "Bartex", + "templateBgColor": "#ffe3f0(柔和粉色)", + "templateTextGradient": "#ff5ac7 → #ff94da", + "tipsTitle": "提示", + "content1": "芭比粉风格非常适合用于可爱风格的Logo、生日卡片、社交媒体图像等。只需几步操作,即可轻松调整阴影、光照和字体样式。", + "content2": "无需下载,几秒即可上手。输入文字,选择风格,即刻导出精美的3D视觉效果。" } } \ No newline at end of file diff --git a/package.json b/package.json index a4d4bc7..e5d81d0 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "crypto-js": "^4.2.0", "lucide-react": "^0.536.0", "lz-string": "^1.5.0", - "motion": "^12.23.11", + "motion": "^12.23.12", "next": "15.2.4", "next-intl": "^4.3.4", "next-themes": "^0.4.6", @@ -40,7 +40,7 @@ "eslint": "^9.32.0", "eslint-config-next": "15.2.3", "tailwindcss": "^4.1.11", - "typescript": "^5.8.3" + "typescript": "^5.9.2" }, "overrides": { "@types/react": "19.0.12", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3e8a5c4..dcd99e1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,14 +33,14 @@ importers: specifier: ^1.5.0 version: 1.5.0 motion: - specifier: ^12.23.11 - version: 12.23.11(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: ^12.23.12 + version: 12.23.12(react-dom@19.0.0(react@19.0.0))(react@19.0.0) next: specifier: 15.2.4 version: 15.2.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0) next-intl: specifier: ^4.3.4 - version: 4.3.4(next@15.2.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)(typescript@5.8.3) + version: 4.3.4(next@15.2.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)(typescript@5.9.2) next-themes: specifier: ^0.4.6 version: 0.4.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -52,7 +52,7 @@ importers: version: 19.0.0(react@19.0.0) react-schemaorg: specifier: ^2.0.0 - version: 2.0.0(react@19.0.0)(schema-dts@1.1.5)(typescript@5.8.3) + version: 2.0.0(react@19.0.0)(schema-dts@1.1.5)(typescript@5.9.2) schema-dts: specifier: ^1.1.5 version: 1.1.5 @@ -92,13 +92,13 @@ importers: version: 9.32.0(jiti@2.5.1) eslint-config-next: specifier: 15.2.3 - version: 15.2.3(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3) + version: 15.2.3(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) tailwindcss: specifier: ^4.1.11 version: 4.1.11 typescript: - specifier: ^5.8.3 - version: 5.8.3 + specifier: ^5.9.2 + version: 5.9.2 packages: @@ -160,14 +160,14 @@ packages: resolution: {integrity: sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@floating-ui/core@1.7.2': - resolution: {integrity: sha512-wNB5ooIKHQc+Kui96jE/n69rHFWAVoxn5CAzL1Xdd8FG03cgY3MLO+GF9U3W737fYDSgPWA6MReKhBQBop6Pcw==} + '@floating-ui/core@1.7.3': + resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} - '@floating-ui/dom@1.7.2': - resolution: {integrity: sha512-7cfaOQuCS27HD7DX+6ib2OrnW+b4ZBwDNnCcT0uTyidcmyWb03FnQqJybDBoCnpdxwBSfA94UAYlRCt7mV+TbA==} + '@floating-ui/dom@1.7.3': + resolution: {integrity: sha512-uZA413QEpNuhtb3/iIKoYMSK07keHPYeXF02Zhd6e213j+d1NamLix/mCLxBUDW/Gx52sPH2m+chlUsyaBs/Ag==} - '@floating-ui/react-dom@2.1.4': - resolution: {integrity: sha512-JbbpPhp38UmXDDAu60RJmbeme37Jbgsm7NrHGgzYYFKmblzRUh6Pa641dII6LsjwF4XlScDrde2UAzDo/b9KPw==} + '@floating-ui/react-dom@2.1.5': + resolution: {integrity: sha512-HDO/1/1oH9fjj4eLgegrlH3dklZpHtUYYFiVwMUwfGvk9jWDRWqkklA2/NFScknrcNSspbV868WjXORvreDX+Q==} peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' @@ -1255,63 +1255,63 @@ packages: '@types/webxr@0.5.22': resolution: {integrity: sha512-Vr6Stjv5jPRqH690f5I5GLjVk8GSsoQSYJ2FVd/3jJF7KaqfwPi3ehfBS96mlQ2kPCwZaX6U0rG2+NGHBKkA/A==} - '@typescript-eslint/eslint-plugin@8.38.0': - resolution: {integrity: sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA==} + '@typescript-eslint/eslint-plugin@8.39.0': + resolution: {integrity: sha512-bhEz6OZeUR+O/6yx9Jk6ohX6H9JSFTaiY0v9/PuKT3oGK0rn0jNplLmyFUGV+a9gfYnVNwGDwS/UkLIuXNb2Rw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.38.0 + '@typescript-eslint/parser': ^8.39.0 eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.38.0': - resolution: {integrity: sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==} + '@typescript-eslint/parser@8.39.0': + resolution: {integrity: sha512-g3WpVQHngx0aLXn6kfIYCZxM6rRJlWzEkVpqEFLT3SgEDsp9cpCbxxgwnE504q4H+ruSDh/VGS6nqZIDynP+vg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.38.0': - resolution: {integrity: sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg==} + '@typescript-eslint/project-service@8.39.0': + resolution: {integrity: sha512-CTzJqaSq30V/Z2Og9jogzZt8lJRR5TKlAdXmWgdu4hgcC9Kww5flQ+xFvMxIBWVNdxJO7OifgdOK4PokMIWPew==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.38.0': - resolution: {integrity: sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ==} + '@typescript-eslint/scope-manager@8.39.0': + resolution: {integrity: sha512-8QOzff9UKxOh6npZQ/4FQu4mjdOCGSdO3p44ww0hk8Vu+IGbg0tB/H1LcTARRDzGCC8pDGbh2rissBuuoPgH8A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.38.0': - resolution: {integrity: sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ==} + '@typescript-eslint/tsconfig-utils@8.39.0': + resolution: {integrity: sha512-Fd3/QjmFV2sKmvv3Mrj8r6N8CryYiCS8Wdb/6/rgOXAWGcFuc+VkQuG28uk/4kVNVZBQuuDHEDUpo/pQ32zsIQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.38.0': - resolution: {integrity: sha512-c7jAvGEZVf0ao2z+nnz8BUaHZD09Agbh+DY7qvBQqLiz8uJzRgVPj5YvOh8I8uEiH8oIUGIfHzMwUcGVco/SJg==} + '@typescript-eslint/type-utils@8.39.0': + resolution: {integrity: sha512-6B3z0c1DXVT2vYA9+z9axjtc09rqKUPRmijD5m9iv8iQpHBRYRMBcgxSiKTZKm6FwWw1/cI4v6em35OsKCiN5Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.38.0': - resolution: {integrity: sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw==} + '@typescript-eslint/types@8.39.0': + resolution: {integrity: sha512-ArDdaOllnCj3yn/lzKn9s0pBQYmmyme/v1HbGIGB0GB/knFI3fWMHloC+oYTJW46tVbYnGKTMDK4ah1sC2v0Kg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.38.0': - resolution: {integrity: sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ==} + '@typescript-eslint/typescript-estree@8.39.0': + resolution: {integrity: sha512-ndWdiflRMvfIgQRpckQQLiB5qAKQ7w++V4LlCHwp62eym1HLB/kw7D9f2e8ytONls/jt89TEasgvb+VwnRprsw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.38.0': - resolution: {integrity: sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==} + '@typescript-eslint/utils@8.39.0': + resolution: {integrity: sha512-4GVSvNA0Vx1Ktwvf4sFE+exxJ3QGUorQG1/A5mRfRNZtkBT2xrA/BCO2H0eALx/PnvCS6/vmYwRdDA41EoffkQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.38.0': - resolution: {integrity: sha512-pWrTcoFNWuwHlA9CvlfSsGWs14JxfN1TH25zM5L7o0pRLhsoZkDnTsXfQRJBEWJoV5DL0jf+Z+sxiud+K0mq1g==} + '@typescript-eslint/visitor-keys@8.39.0': + resolution: {integrity: sha512-ldgiJ+VAhQCfIjeOgu8Kj5nSxds0ktPOSO9p4+0VDH2R2pLvQraaM5Oen2d7NxzMCm+Sn/vJT+mv2H5u6b/3fA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@unrs/resolver-binding-android-arm-eabi@1.11.1': @@ -1688,8 +1688,8 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - enhanced-resolve@5.18.2: - resolution: {integrity: sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==} + enhanced-resolve@5.18.3: + resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} engines: {node: '>=10.13.0'} es-abstract@1.24.0: @@ -1898,8 +1898,8 @@ packages: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} - framer-motion@12.23.11: - resolution: {integrity: sha512-VzNi+exyI3bn7Pzvz1Fjap1VO9gQu8mxrsSsNamMidsZ8AA8W2kQsR+YQOciEUbMtkKAWIbPHPttfn5e9jqqJQ==} + framer-motion@12.23.12: + resolution: {integrity: sha512-6e78rdVtnBvlEVgu6eFEAgG9v3wLnYEboM8I5O5EXvfKC8gxGQB8wXJdhkMy10iVcn05jl6CNw7/HTsTCfwcWg==} peerDependencies: '@emotion/is-prop-valid': '*' react: ^18.0.0 || ^19.0.0 @@ -2300,14 +2300,14 @@ packages: engines: {node: '>=10'} hasBin: true - motion-dom@12.23.9: - resolution: {integrity: sha512-6Sv++iWS8XMFCgU1qwKj9l4xuC47Hp4+2jvPfyTXkqDg2tTzSgX6nWKD4kNFXk0k7llO59LZTPuJigza4A2K1A==} + motion-dom@12.23.12: + resolution: {integrity: sha512-RcR4fvMCTESQBD/uKQe49D5RUeDOokkGRmz4ceaJKDBgHYtZtntC/s2vLvY38gqGaytinij/yi3hMcWVcEF5Kw==} motion-utils@12.23.6: resolution: {integrity: sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==} - motion@12.23.11: - resolution: {integrity: sha512-AHv/2SivIz9fjvND8wwN2LldDTuwkPyTSWecAY/xzB1/2eF7zxvh9JRkf8aF4eGoGsy1e2YKp+CQC5yxcssnEw==} + motion@12.23.12: + resolution: {integrity: sha512-8jCD8uW5GD1csOoqh1WhH1A6j5APHVE15nuBkFeRiMzYBdRwyAHmSP/oXSuW0WJPZRXTFdBoG4hY9TFWNhhwng==} peerDependencies: '@emotion/is-prop-valid': '*' react: ^18.0.0 || ^19.0.0 @@ -2770,8 +2770,8 @@ packages: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} - typescript@5.8.3: - resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} + typescript@5.9.2: + resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} engines: {node: '>=14.17'} hasBin: true @@ -2922,18 +2922,18 @@ snapshots: '@eslint/core': 0.15.1 levn: 0.4.1 - '@floating-ui/core@1.7.2': + '@floating-ui/core@1.7.3': dependencies: '@floating-ui/utils': 0.2.10 - '@floating-ui/dom@1.7.2': + '@floating-ui/dom@1.7.3': dependencies: - '@floating-ui/core': 1.7.2 + '@floating-ui/core': 1.7.3 '@floating-ui/utils': 0.2.10 - '@floating-ui/react-dom@2.1.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@floating-ui/react-dom@2.1.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@floating-ui/dom': 1.7.2 + '@floating-ui/dom': 1.7.3 react: 19.0.0 react-dom: 19.0.0(react@19.0.0) @@ -3520,7 +3520,7 @@ snapshots: '@radix-ui/react-popper@1.2.7(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@floating-ui/react-dom': 2.1.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@floating-ui/react-dom': 2.1.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.0.4(@types/react@19.0.12))(@types/react@19.0.12)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.12)(react@19.0.0) '@radix-ui/react-context': 1.1.2(@types/react@19.0.12)(react@19.0.0) @@ -3902,7 +3902,7 @@ snapshots: '@tailwindcss/node@4.1.11': dependencies: '@ampproject/remapping': 2.3.0 - enhanced-resolve: 5.18.2 + enhanced-resolve: 5.18.3 jiti: 2.5.1 lightningcss: 1.30.1 magic-string: 0.30.17 @@ -4012,97 +4012,97 @@ snapshots: '@types/webxr@0.5.22': {} - '@typescript-eslint/eslint-plugin@8.38.0(@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3)': + '@typescript-eslint/eslint-plugin@8.39.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3) - '@typescript-eslint/scope-manager': 8.38.0 - '@typescript-eslint/type-utils': 8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3) - '@typescript-eslint/utils': 8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3) - '@typescript-eslint/visitor-keys': 8.38.0 + '@typescript-eslint/parser': 8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.39.0 + '@typescript-eslint/type-utils': 8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/utils': 8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/visitor-keys': 8.39.0 eslint: 9.32.0(jiti@2.5.1) graphemer: 1.4.0 ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@5.8.3) - typescript: 5.8.3 + ts-api-utils: 2.1.0(typescript@5.9.2) + typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3)': + '@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: - '@typescript-eslint/scope-manager': 8.38.0 - '@typescript-eslint/types': 8.38.0 - '@typescript-eslint/typescript-estree': 8.38.0(typescript@5.8.3) - '@typescript-eslint/visitor-keys': 8.38.0 + '@typescript-eslint/scope-manager': 8.39.0 + '@typescript-eslint/types': 8.39.0 + '@typescript-eslint/typescript-estree': 8.39.0(typescript@5.9.2) + '@typescript-eslint/visitor-keys': 8.39.0 debug: 4.4.1 eslint: 9.32.0(jiti@2.5.1) - typescript: 5.8.3 + typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.38.0(typescript@5.8.3)': + '@typescript-eslint/project-service@8.39.0(typescript@5.9.2)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.38.0(typescript@5.8.3) - '@typescript-eslint/types': 8.38.0 + '@typescript-eslint/tsconfig-utils': 8.39.0(typescript@5.9.2) + '@typescript-eslint/types': 8.39.0 debug: 4.4.1 - typescript: 5.8.3 + typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.38.0': + '@typescript-eslint/scope-manager@8.39.0': dependencies: - '@typescript-eslint/types': 8.38.0 - '@typescript-eslint/visitor-keys': 8.38.0 + '@typescript-eslint/types': 8.39.0 + '@typescript-eslint/visitor-keys': 8.39.0 - '@typescript-eslint/tsconfig-utils@8.38.0(typescript@5.8.3)': + '@typescript-eslint/tsconfig-utils@8.39.0(typescript@5.9.2)': dependencies: - typescript: 5.8.3 + typescript: 5.9.2 - '@typescript-eslint/type-utils@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3)': + '@typescript-eslint/type-utils@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: - '@typescript-eslint/types': 8.38.0 - '@typescript-eslint/typescript-estree': 8.38.0(typescript@5.8.3) - '@typescript-eslint/utils': 8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3) + '@typescript-eslint/types': 8.39.0 + '@typescript-eslint/typescript-estree': 8.39.0(typescript@5.9.2) + '@typescript-eslint/utils': 8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) debug: 4.4.1 eslint: 9.32.0(jiti@2.5.1) - ts-api-utils: 2.1.0(typescript@5.8.3) - typescript: 5.8.3 + ts-api-utils: 2.1.0(typescript@5.9.2) + typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.38.0': {} + '@typescript-eslint/types@8.39.0': {} - '@typescript-eslint/typescript-estree@8.38.0(typescript@5.8.3)': + '@typescript-eslint/typescript-estree@8.39.0(typescript@5.9.2)': dependencies: - '@typescript-eslint/project-service': 8.38.0(typescript@5.8.3) - '@typescript-eslint/tsconfig-utils': 8.38.0(typescript@5.8.3) - '@typescript-eslint/types': 8.38.0 - '@typescript-eslint/visitor-keys': 8.38.0 + '@typescript-eslint/project-service': 8.39.0(typescript@5.9.2) + '@typescript-eslint/tsconfig-utils': 8.39.0(typescript@5.9.2) + '@typescript-eslint/types': 8.39.0 + '@typescript-eslint/visitor-keys': 8.39.0 debug: 4.4.1 fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.7.2 - ts-api-utils: 2.1.0(typescript@5.8.3) - typescript: 5.8.3 + ts-api-utils: 2.1.0(typescript@5.9.2) + typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3)': + '@typescript-eslint/utils@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: '@eslint-community/eslint-utils': 4.7.0(eslint@9.32.0(jiti@2.5.1)) - '@typescript-eslint/scope-manager': 8.38.0 - '@typescript-eslint/types': 8.38.0 - '@typescript-eslint/typescript-estree': 8.38.0(typescript@5.8.3) + '@typescript-eslint/scope-manager': 8.39.0 + '@typescript-eslint/types': 8.39.0 + '@typescript-eslint/typescript-estree': 8.39.0(typescript@5.9.2) eslint: 9.32.0(jiti@2.5.1) - typescript: 5.8.3 + typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.38.0': + '@typescript-eslint/visitor-keys@8.39.0': dependencies: - '@typescript-eslint/types': 8.38.0 + '@typescript-eslint/types': 8.39.0 eslint-visitor-keys: 4.2.1 '@unrs/resolver-binding-android-arm-eabi@1.11.1': @@ -4427,7 +4427,7 @@ snapshots: emoji-regex@9.2.2: {} - enhanced-resolve@5.18.2: + enhanced-resolve@5.18.3: dependencies: graceful-fs: 4.2.11 tapable: 2.2.2 @@ -4535,21 +4535,21 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-config-next@15.2.3(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3): + eslint-config-next@15.2.3(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2): dependencies: '@next/eslint-plugin-next': 15.2.3 '@rushstack/eslint-patch': 1.12.0 - '@typescript-eslint/eslint-plugin': 8.38.0(@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3) - '@typescript-eslint/parser': 8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3) + '@typescript-eslint/eslint-plugin': 8.39.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/parser': 8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) eslint: 9.32.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.32.0(jiti@2.5.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.5.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.5.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.32.0(jiti@2.5.1)) eslint-plugin-react: 7.37.5(eslint@9.32.0(jiti@2.5.1)) eslint-plugin-react-hooks: 5.2.0(eslint@9.32.0(jiti@2.5.1)) optionalDependencies: - typescript: 5.8.3 + typescript: 5.9.2 transitivePeerDependencies: - eslint-import-resolver-webpack - eslint-plugin-import-x @@ -4574,22 +4574,22 @@ snapshots: tinyglobby: 0.2.14 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.5.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.5.1)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.5.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.5.1)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3) + '@typescript-eslint/parser': 8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) eslint: 9.32.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.32.0(jiti@2.5.1)) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.5.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.5.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -4600,7 +4600,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.32.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.5.1)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.32.0(jiti@2.5.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -4612,7 +4612,7 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.8.3) + '@typescript-eslint/parser': 8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -4788,9 +4788,9 @@ snapshots: dependencies: is-callable: 1.2.7 - framer-motion@12.23.11(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + framer-motion@12.23.12(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: - motion-dom: 12.23.9 + motion-dom: 12.23.12 motion-utils: 12.23.6 tslib: 2.8.1 optionalDependencies: @@ -5168,15 +5168,15 @@ snapshots: mkdirp@3.0.1: {} - motion-dom@12.23.9: + motion-dom@12.23.12: dependencies: motion-utils: 12.23.6 motion-utils@12.23.6: {} - motion@12.23.11(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + motion@12.23.12(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: - framer-motion: 12.23.11(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + framer-motion: 12.23.12(react-dom@19.0.0(react@19.0.0))(react@19.0.0) tslib: 2.8.1 optionalDependencies: react: 19.0.0 @@ -5192,7 +5192,7 @@ snapshots: negotiator@1.0.0: {} - next-intl@4.3.4(next@15.2.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)(typescript@5.8.3): + next-intl@4.3.4(next@15.2.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)(typescript@5.9.2): dependencies: '@formatjs/intl-localematcher': 0.5.10 negotiator: 1.0.0 @@ -5200,7 +5200,7 @@ snapshots: react: 19.0.0 use-intl: 4.3.4(react@19.0.0) optionalDependencies: - typescript: 5.8.3 + typescript: 5.9.2 next-themes@0.4.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: @@ -5428,11 +5428,11 @@ snapshots: optionalDependencies: '@types/react': 19.0.12 - react-schemaorg@2.0.0(react@19.0.0)(schema-dts@1.1.5)(typescript@5.8.3): + react-schemaorg@2.0.0(react@19.0.0)(schema-dts@1.1.5)(typescript@5.9.2): dependencies: react: 19.0.0 schema-dts: 1.1.5 - typescript: 5.8.3 + typescript: 5.9.2 react-style-singleton@2.2.3(@types/react@19.0.12)(react@19.0.0): dependencies: @@ -5707,9 +5707,9 @@ snapshots: dependencies: is-number: 7.0.0 - ts-api-utils@2.1.0(typescript@5.8.3): + ts-api-utils@2.1.0(typescript@5.9.2): dependencies: - typescript: 5.8.3 + typescript: 5.9.2 tsconfig-paths@3.15.0: dependencies: @@ -5757,7 +5757,7 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 - typescript@5.8.3: {} + typescript@5.9.2: {} unbox-primitive@1.1.0: dependencies: diff --git a/src/app/[locale]/page.tsx b/src/app/[locale]/page.tsx index 12d087c..662b734 100644 --- a/src/app/[locale]/page.tsx +++ b/src/app/[locale]/page.tsx @@ -1,7 +1,7 @@ import { getTranslations } from "next-intl/server"; import Footer from "@/components/Footer"; import Header from "@/components/Header"; -import Editor from "@/components/SimpleEditor"; +import Editor from "@/components/FullEditor"; import { useTranslations } from "next-intl"; import { Locales } from "@/i18n/config"; import { Metadata } from "next"; diff --git a/src/app/[locale]/styles/barbie-pink/1024_576.png b/src/app/[locale]/styles/barbie-pink/1024_576.png new file mode 100644 index 0000000..dc444c1 Binary files /dev/null and b/src/app/[locale]/styles/barbie-pink/1024_576.png differ diff --git a/src/app/[locale]/styles/barbie-pink/512_288.png b/src/app/[locale]/styles/barbie-pink/512_288.png new file mode 100644 index 0000000..9d06807 Binary files /dev/null and b/src/app/[locale]/styles/barbie-pink/512_288.png differ diff --git a/src/app/[locale]/styles/barbie-pink/page.tsx b/src/app/[locale]/styles/barbie-pink/page.tsx new file mode 100644 index 0000000..5a5c931 --- /dev/null +++ b/src/app/[locale]/styles/barbie-pink/page.tsx @@ -0,0 +1,148 @@ +import Image from 'next/image'; +import { useLocale, useTranslations } from 'next-intl'; +import { StyleItem } from '../list'; +import { Locales } from '@/i18n/config'; +import { Metadata } from 'next'; +import { Box, Flex, Container, Heading, Text, Button, Strong } from '@radix-ui/themes'; +import Footer from '@/components/Footer'; +import Header from '@/components/Header'; +import highCover from "./1024_576.png"; +import cover from "./512_288.png"; +const host = process.env.NEXT_PUBLIC_HOST; + +export const styleContent = { + id: "barbie-pink", + cover: cover, + date: "2025-08-07", + en: { + title: "Barbie-Pink 3D Text", + summary: "Use our online 3D text editor to craft eye-catching Barbie-inspired designs.", + }, + zh: { + title: "芭比粉3D文本", + summary: "使用我们的在线3D文本编辑器,为项目创建引人注目的芭比粉3D文本。", + }, +} satisfies StyleItem; + +export default function BarbiePinkLandingPage() { + const t = useTranslations('StyleBarbie'); + const common = useTranslations('StylePage'); + const locale = useLocale(); + + return ( + + + + + + + + + + {t('title')} + {t('description')} + + + + + {t('templateTitle')} + + + {common("templateFontLabel")}: + {t('templateFont')} + + + {common("templateBgColorLabel")}: + {t('templateBgColor')} + + + {common("templateTextGradientColorLabel")}: + {t('templateTextGradient')} + + + + + + {t('tipsTitle')} + {t('content1')} + {t('content2')} + + + + + + {t('cta')} + + + + you can also try Barbie_Doll + + + + you can also try Barbie_Princess + + + + + + + + + + ); +} + +const locales = Locales; +export function generateStaticParams() { + return locales.map((locale) => ({ locale })); +} + +export async function generateMetadata({ + params, +}: { + params: Promise<{ locale: string }>; +}): Promise { + const { locale } = await params; + const name = styleContent.id; + const title = styleContent[locale as "en" | "zh"].title; + const description = styleContent[locale as "en" | "zh"].summary; + return { + title, + description, + keywords: [], + openGraph: { + title, + description, + url: `${host}/${locale}/styles/${name}`, + images: [ + { + url: `${process.env.NEXT_PUBLIC_HOST}/og-image.png`, + width: 1200, + height: 630, + alt: title, + }, + ], + locale: locale, + type: "website", + }, + twitter: { + card: "summary_large_image", + title, + description, + images: [`${process.env.NEXT_PUBLIC_HOST}/og-image.png`], + }, + alternates: { + canonical: `${host}/styles/${name}`, + languages: { + en: `${host}/en/styles/${name}`, + zh: `${host}/zh/styles/${name}`, + }, + }, + }; +} diff --git a/src/app/[locale]/styles/list.ts b/src/app/[locale]/styles/list.ts new file mode 100644 index 0000000..5e8d8f7 --- /dev/null +++ b/src/app/[locale]/styles/list.ts @@ -0,0 +1,17 @@ +import { StaticImageData } from "next/image"; +import { styleContent as barbieStyle } from "./barbie-pink/page"; +export interface StyleItem { + id: string; + date: string; + cover: StaticImageData; + en: { + title: string; + summary: string; + }; + zh: { + title: string; + summary: string; + }; +} + +export const styles: StyleItem[] = [barbieStyle]; diff --git a/src/app/[locale]/styles/page.tsx b/src/app/[locale]/styles/page.tsx new file mode 100644 index 0000000..aecd877 --- /dev/null +++ b/src/app/[locale]/styles/page.tsx @@ -0,0 +1,94 @@ +import Footer from '@/components/Footer' +import Header from '@/components/Header' +import { Card, Flex, Text, Heading, Box, Link } from '@radix-ui/themes' +import { styles } from './list' +import { useLocale, useTranslations } from 'next-intl'; +import { Locales } from '@/i18n/config'; +import { Metadata } from 'next'; +import { getTranslations } from 'next-intl/server'; +import Image from 'next/image'; +const host = process.env.NEXT_PUBLIC_HOST; + +export default function StyleListPage() { + const locale = useLocale() as "zh" | "en"; + const t = useTranslations("StylePage"); + + return ( + + + + {t("title")} + + {styles.map(styleItem => ( + + + + + + + + {styleItem[locale].title} + {styleItem.date} + {styleItem[locale].summary} + + + + + ))} + + + + + ) +} + + +const locales = Locales; + +export function generateStaticParams() { + return locales.map((locale) => ({ locale })); +} + +export async function generateMetadata({ + params, +}: { + params: Promise<{ locale: string }>; +}): Promise { + const { locale } = await params; + const t = await getTranslations({ locale, namespace: "StylePage" }); + + const name = "styles"; + + return { + title: t("seoTitle"), + description: t("seoDescription"), + openGraph: { + title: t("seoTitle"), + description: t("seoDescription"), + url: `${host}/${locale}/${name}`, + images: [ + { + url: `${process.env.NEXT_PUBLIC_HOST}/og-image.png`, + width: 1200, + height: 630, + alt: t("seoTitle"), + }, + ], + locale: locale, + type: "website", + }, + twitter: { + card: "summary_large_image", + title: t("seoTitle"), + description: t("seoDescription"), + images: [`${process.env.NEXT_PUBLIC_HOST}/og-image.png`], + }, + alternates: { + canonical: `${host}/${name}`, + languages: { + en: `${host}/en/${name}`, + zh: `${host}/zh/${name}`, + }, + }, + }; +} diff --git a/src/app/sitemap.ts b/src/app/sitemap.ts index 48f9a43..32ce5af 100644 --- a/src/app/sitemap.ts +++ b/src/app/sitemap.ts @@ -1,73 +1,39 @@ import { Locales } from "@/i18n/config"; import { MetadataRoute } from "next"; +import { blogs } from "./[locale]/blogs/list"; +import { styles } from "./[locale]/styles/list"; const host = process.env.NEXT_PUBLIC_HOST; export default function sitemap(): MetadataRoute.Sitemap { const baseUrl = host!; const locales = Locales; + const urls = ["/", "/blogs", "/editor", "/do-not-write-on-this-page"]; + blogs.forEach((blog) => { + urls.push(`/blogs/${blog.id}`); + }); + styles.forEach((style) => { + urls.push(`/styles/${style.id}`); + }); + + const multiLocaleUrls = locales + .map((locale) => + urls.map((url) => ({ + url: `${baseUrl}/${locale}${url}`, + lastModified: new Date(), + changeFrequency: "monthly" as const, + priority: 0.8, + })) + ) + .flat(); + return [ - { - url: baseUrl, + ...urls.map((url) => ({ + url: `${baseUrl}${url}`, lastModified: new Date(), - changeFrequency: "yearly", + changeFrequency: "daily" as const, priority: 1, - }, - ...locales.map((locale) => ({ - url: `${baseUrl}/${locale}`, - lastModified: new Date(), - changeFrequency: "monthly" as const, - priority: 0.8, - })), - { - url: baseUrl + "/editor", - lastModified: new Date(), - changeFrequency: "yearly", - priority: 1, - }, - ...locales.map((locale) => ({ - url: `${baseUrl}/${locale}/editor`, - lastModified: new Date(), - changeFrequency: "monthly" as const, - priority: 0.8, - })), - { - url: baseUrl + "/do-not-write-on-this-page", - lastModified: new Date(), - changeFrequency: "yearly", - priority: 1, - }, - ...locales.map((locale) => ({ - url: `${baseUrl}/${locale}/do-not-write-on-this-page`, - lastModified: new Date(), - changeFrequency: "monthly" as const, - priority: 0.8, - })), - - { - url: baseUrl + "/blogs", - lastModified: new Date(), - changeFrequency: "yearly", - priority: 1, - }, - ...locales.map((locale) => ({ - url: `${baseUrl}/${locale}/blogs`, - lastModified: new Date(), - changeFrequency: "monthly" as const, - priority: 0.8, - })), - - { - url: baseUrl + "/blogs/Create-3D-Text-with-the-Barbie-Font", - lastModified: new Date(), - changeFrequency: "yearly", - priority: 1, - }, - ...locales.map((locale) => ({ - url: `${baseUrl}/${locale}/blogs/Create-3D-Text-with-the-Barbie-Font`, - lastModified: new Date(), - changeFrequency: "monthly" as const, - priority: 0.8, })), + ...multiLocaleUrls, ]; } diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx index 7ae88f4..09729cd 100644 --- a/src/components/Footer.tsx +++ b/src/components/Footer.tsx @@ -20,12 +20,19 @@ export default function Footer() { > {t("editorName")} + + {t("styleName")} + {t("blogName")} + + + {t("styleName")} + {t("blogName")} - - Features Wanted - + + diff --git a/src/components/SimpleEditor.tsx b/src/components/SimpleEditor.tsx deleted file mode 100644 index 0dbdd09..0000000 --- a/src/components/SimpleEditor.tsx +++ /dev/null @@ -1,81 +0,0 @@ -"use client"; -import { Flex, Box, Link } from "@radix-ui/themes"; -import BackgroundSelector, { - BackgroundProp, -} from "./common/BackgroundSelector"; -import PreviewToolbar from "./common/PreviewToolbar"; -import SimpleTextSetting from "./common/SimpleTextSetting"; -import { useEffect, useState } from "react"; -import { useLocale, useTranslations } from "next-intl"; -import { TextProp } from "./common/TextSetting"; -import { useRouter } from "@/i18n/navigation"; - -/** - * 简易工具 - * @returns - */ -export default function SimpleEditor({ textProp, backgroundProp }: { textProp: TextProp | undefined, backgroundProp: BackgroundProp | undefined }) { - - const t = useTranslations("TextEditor"); - const tIndex = useTranslations("HomePage"); - - const router = useRouter(); - - backgroundProp = { - type: "color", - color: "#c4b1b1", - image: null, - } satisfies BackgroundProp; - - textProp = textProp || TextProp.default(t("defaultText")); - - const [background, setBackground] = useState(backgroundProp); - - const [text, setText] = useState(textProp); - - // useEffect(() => { - // let bg = sessionStorage.getItem("background"); - - // if (bg) { - // console.log("初始化设置 bg", bg); - - // setBackground(JSON.parse(bg)); - // } - - // let txt = sessionStorage.getItem("text"); - - // if (txt) { - // console.log("初始化设置 txt", txt); - - // setText(JSON.parse(txt)); - // } - - // }, []); - - useEffect(() => { - sessionStorage.setItem("background", JSON.stringify(background)); - }, [background]); - - useEffect(() => { - sessionStorage.setItem("text", JSON.stringify(text)); - - }, [text]); - const locale = useLocale(); - - return ( - - - - - {tIndex("toolMore")} ? - - - - - - - ); -} diff --git a/src/components/common/BackgroundSelector.tsx b/src/components/common/BackgroundSelector.tsx index 29cbd3a..dba7676 100644 --- a/src/components/common/BackgroundSelector.tsx +++ b/src/components/common/BackgroundSelector.tsx @@ -40,7 +40,7 @@ export default function BackgroundSelector({ }; return ( - + {t("title")} @@ -53,13 +53,24 @@ export default function BackgroundSelector({ {background.type === "color" && ( - + + + + + + + )} {background.type === "image" && ( diff --git a/src/components/common/PreviewToolbar.tsx b/src/components/common/PreviewToolbar.tsx index 5194525..f38e734 100644 --- a/src/components/common/PreviewToolbar.tsx +++ b/src/components/common/PreviewToolbar.tsx @@ -32,8 +32,9 @@ export default function PreviewToolbar({ }) { let host = process.env.NEXT_PUBLIC_HOST?.substring("https://".length); const t = useTranslations("PreviewBar"); - const [aspectRadio, setAspectRadio] = useState(0); - const split = Sizes[0].split("x").map(Number); + const initAspectRadio = 0; + const [aspectRadio, setAspectRadio] = useState(initAspectRadio); + const split = Sizes[initAspectRadio].split("x").map(Number); const [size, setSize] = useState({ width: split[0], height: split[1] }); const container = useRef(null); const fullscreenElement = useRef(null); diff --git a/src/components/common/SimpleTextSetting.tsx b/src/components/common/SimpleTextSetting.tsx deleted file mode 100644 index 523379b..0000000 --- a/src/components/common/SimpleTextSetting.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import { Flex, Heading, Select } from "@radix-ui/themes"; -import { useTranslations } from "next-intl"; -import { FontNames, FontWeights, TextProp } from "./TextSetting"; - -export default function TextSetting({ - text, - setText, -}: { - text: TextProp; - setText: (text: TextProp) => void; -}) { - const t = useTranslations("TextEditor"); - - return ( - - {t("title")} - setText({ ...text, text: e.target.value })} - className="w-full p-3 border rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring" - rows={4} - /> - - - {t("textColor")} - - setText({ ...text, color: e.target.value })} - className="w-full h-10 rounded-md cursor-pointer" - /> - - - - {t("fontFamily")} - - setText({ ...text, font: e })}> - - - {FontNames.map((name) => {name})} - - - - - - {t("fontWeight")} - - - setText({ ...text, weight: e })}> - - - {FontWeights.map((name) => {name})} - - - - - - ); -} diff --git a/src/components/common/TextSetting.tsx b/src/components/common/TextSetting.tsx index c3d0bb4..47e7f22 100644 --- a/src/components/common/TextSetting.tsx +++ b/src/components/common/TextSetting.tsx @@ -1,14 +1,15 @@ 'use client' +import { containsChinese, DefaultFontChinese, FontLang, Fonts, FontWeight, getFontWeight, getOnlineFontPath } from "@/lib/fonts"; import { Flex, Heading, Select, Tooltip, IconButton, Link, Box, Tabs, RadioGroup } from "@radix-ui/themes"; import { PlusIcon, CircleQuestionMarkIcon } from "lucide-react"; import { useLocale, useTranslations } from "next-intl"; import { useEffect, useRef, useState } from "react"; -export const FontWeights = ["Regular", "Bold"]; -export const FontNames = ["Gentilis", "Helvetiker", "Optimer", "Noto_Sans_SC_zh", "Alibaba_PuHuiTi_3.0_zh"]; - export type ColorGradientDir = "l2r" | "t2b"; -export type FontFrom = "online" | "upload"; +export enum FontFrom { + online, + upload, +} export class TextProp { text: string color: string | string[] @@ -16,13 +17,13 @@ export class TextProp { fontFrom: FontFrom font: string fontUrl: string - weight: string + weight: FontWeight constructor( text: string, color: string, fontFrom: FontFrom, font: string, - weight: string) { + weight: FontWeight) { this.text = text; this.color = color; @@ -35,35 +36,22 @@ export class TextProp { static default(text: string): TextProp { - let font = FontNames[0]; + let font = Fonts[0].name; if (containsChinese(text)) { - font = "Alibaba_PuHuiTi_3.0_zh"; + font = DefaultFontChinese; } return { text, color: "#8e86fe", colorGradientDir: "l2r", font, - fontUrl: getOnlineFontPath(font, FontWeights[0]), - weight: FontWeights[0], - fontFrom: "online", + fontUrl: getOnlineFontPath(font, FontWeight.Regular), + weight: FontWeight.Regular, + fontFrom: FontFrom.online, } } } -function getOnlineFontPath(fontName: string, fontWeight: String) { - - let font = fontName; - if (fontName.endsWith("zh")) { - font = fontName.slice(0, -3); - } - return `https://fast3dtest.mysoul.fun/${font}_${fontWeight}.json`; - -} - -function containsChinese(str: string) { - return /[\u4e00-\u9fa5]/.test(str); -} export interface UploadFont { name: string; @@ -72,6 +60,17 @@ export interface UploadFont { type TextMode = "color" | "gradient"; +const getFontWeightEnabled = (font: string) => { + + let f = Fonts.find(item => item.name == font); + + const map = new Map() + + if (f) { + f.weight.forEach(w => map.set(w, true)) + } + return map; +}; export default function TextSetting({ text, setText, @@ -81,15 +80,16 @@ export default function TextSetting({ }) { const locale = useLocale(); - const t = useTranslations("TextEditor"); + + const t = useTranslations("TextEditor"); const [uploadFonts, setUploadFonts] = useState([]); const isPureColor = !Array.isArray(text.color); const [textColorMode, setTextColorMode] = useState(isPureColor ? "color" : "gradient"); const [textColor, setTextColor] = useState(isPureColor ? text.color as string : "#000000"); const [textGradientColor, setTextGradientColor] = useState(!isPureColor ? text.color as string[] : ["#ce6464", "#63635a"]); const [colorGradientDir, setColorGradientDir] = useState(text.colorGradientDir as ColorGradientDir); - + const [fontWeightEnbled, setFontWeightEnabled] = useState>(getFontWeightEnabled(text.font)); let inited = useRef(false); useEffect(() => { @@ -102,7 +102,7 @@ export default function TextSetting({ if (uploadFonts.length > 0) { handleSelectFont(uploadFonts[uploadFonts.length - 1].name) } else { - handleSelectFont(FontNames[0]) + handleSelectFont(Fonts[0].name); } }, [uploadFonts]); @@ -150,14 +150,25 @@ export default function TextSetting({ }, [colorGradientDir]); const handleSelectFont = (font: string) => { - if (FontNames.indexOf(font) !== -1) { - setText({ ...text, font: font, fontFrom: "online", fontUrl: getOnlineFontPath(font, text.weight) }); + const f = Fonts.find(item => item.name == font); + if (f) { + if (f.weight.includes(text.weight)) { + setText({ ...text, font: font, fontFrom: FontFrom.online, fontUrl: getOnlineFontPath(font, text.weight) }); + } else { + const w = f.weight[0]; + setText({ ...text, font: font, fontFrom: FontFrom.online, fontUrl: getOnlineFontPath(font, w), weight: w }); + } } else { let f = uploadFonts.find((item) => item.name === font)!; - setText({ ...text, font: font, fontFrom: "upload", fontUrl: f.url }); + setText({ ...text, font: font, fontFrom: FontFrom.upload, fontUrl: f.url }); } + + const map = getFontWeightEnabled(font); + setFontWeightEnabled(map); }; + + return ( {t("title")} @@ -271,7 +282,7 @@ export default function TextSetting({ Online - {FontNames.map((name) => {name})} + {Fonts.map(({ name }) => {name})} @@ -311,13 +322,13 @@ export default function TextSetting({ {t("fontWeight")} - setText({ ...text, weight: e })}> + setText({ ...text, weight: getFontWeight(e) })}> - {FontWeights.map((name) => {name})} + {Object.entries(FontWeight).map(([name, value]) => + {value})} - ); diff --git a/src/components/common/ThreeTools.ts b/src/components/common/ThreeTools.ts index bc7fc01..d80c14a 100644 --- a/src/components/common/ThreeTools.ts +++ b/src/components/common/ThreeTools.ts @@ -97,6 +97,8 @@ export function resize( console.log("resize to width = " + width + " height = " + height); camera.aspect = width / height; + camera.updateProjectionMatrix(); + // camera = new THREE.OrthographicCamera( // clientWidth / -2, // clientWidth / 2, @@ -105,6 +107,7 @@ export function resize( // 0.1, // 1000 // ); + renderer.setSize(width, height, false); } diff --git a/src/lib/fonts.ts b/src/lib/fonts.ts new file mode 100644 index 0000000..4738be7 --- /dev/null +++ b/src/lib/fonts.ts @@ -0,0 +1,85 @@ +export enum FontWeight { + Regular = "Regular", + Bold = "Bold", +} + +export enum FontLang { + EN = "en", + ZH = "zh", +} + +export function getFontWeight(s: string) { + switch (s) { + case "Regular": + return FontWeight.Regular; + case "Bold": + return FontWeight.Bold; + default: + return FontWeight.Regular; + } +} + +export class FontDefine { + name: string; + weight: FontWeight[]; + lang: FontLang[]; + + constructor(name: string, weight: FontWeight[], lang: FontLang[]) { + this.name = name; + this.weight = weight; + this.lang = lang; + } +} + +export function getOnlineFontPath(fontName: string, w: FontWeight) { + return `https://fast3dtest.mysoul.fun/${fontName}_${w}.json`; +} + +export function containsChinese(str: string) { + return /[\u4e00-\u9fa5]/.test(str); +} + +export const DefaultFontChinese: string = "Alibaba_PuHuiTi_3.0"; + +export const Fonts: FontDefine[] = [ + { + name: "Gentilis", + weight: [FontWeight.Regular, FontWeight.Bold], + lang: [FontLang.EN], + }, + { + name: "Helvetiker", + weight: [FontWeight.Regular, FontWeight.Bold], + lang: [FontLang.EN], + }, + { + name: "Optimer", + weight: [FontWeight.Regular, FontWeight.Bold], + lang: [FontLang.EN], + }, + { + name: "Alibaba_PuHuiTi_3.0", + weight: [FontWeight.Regular, FontWeight.Bold], + lang: [FontLang.EN, FontLang.ZH], + }, + { + name: "Noto_Sans_SC", + weight: [FontWeight.Regular, FontWeight.Bold], + lang: [FontLang.EN, FontLang.ZH], + }, + { + name: "Barbie_Doll", + weight: [FontWeight.Regular], + lang: [FontLang.EN], + }, + { + name: "Barbie_Princess", + weight: [FontWeight.Regular], + lang: [FontLang.EN], + }, + { + name: "Bartex", + weight: [FontWeight.Regular], + lang: [FontLang.EN], + }, +];