@rxdrag/website-studio 0.0.18 → 0.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -6,10 +6,10 @@ var __publicField = (obj, key, value) => {
6
6
  };
7
7
  import * as React from "react";
8
8
  import React__default, { createContext, useContext, useMemo, memo, useEffect, useCallback, useState, useRef, forwardRef as forwardRef$2, useImperativeHandle, isValidElement, cloneElement } from "react";
9
- import { ThemeFields, PageQueryOptions, PageFields, FrontComponentQueryOptions, FrontComponentFields, ComponentCategoryFields, SectionTemplateQueryOptions, SectionTemplateFields, ComponentCategoryQueryOptions, TemplateCategoryQueryOptions, TemplateCategoryFields, ThemeQueryOptions, StyleConfigFields, LangFields, PageAssciations, ProductCategoryEntityName, ProductCategoryQueryOptions, ProductCategoryFields, ProductQueryOptions, ProductFields, PublishableStatus, PageType, ExtendFieldType, ThemeConfigQueryOptions, ThemeConfigFields, ThemeConfigAssciations, MediaQueryOptions, themeConfigToInputCascade, ThemeConfigEntityName, MediaType, themeConfigToInput, websiteToInput, LangQueryOptions, WebsiteAssciations, PageEntityName, ThemeEntityName, themeToInputCascade, ThemeCategoryFields, FrontComponentEntityName, pageToInputCascade, sectionTemplateToInput, PageMetaFields, pageToInput, frontComponentToInput, ComponentCategoryEntityName, componentCategoryToInput, themeToInput, SectionTemplateEntityName, TemplateCategoryEntityName, templateCategoryToInput } from "@rxdrag/rxcms-models";
9
+ import { ThemeFields, PageQueryOptions, PageFields, FrontComponentQueryOptions, FrontComponentFields, ComponentCategoryFields, SectionTemplateQueryOptions, SectionTemplateFields, ComponentCategoryQueryOptions, TemplateCategoryQueryOptions, TemplateCategoryFields, ThemeQueryOptions, StyleConfigFields, LangFields, ThemeConfigFields, PageAssciations, ProductCategoryEntityName, ProductCategoryQueryOptions, ProductCategoryFields, ProductQueryOptions, ProductFields, PublishableStatus, PageType, websiteToInput, LangQueryOptions, WebsiteAssciations, ExtendFieldType, ThemeConfigQueryOptions, ThemeConfigAssciations, MediaQueryOptions, themeConfigToInputCascade, ThemeConfigEntityName, MediaType, themeConfigToInput, PageEntityName, ThemeEntityName, themeToInputCascade, ThemeCategoryFields, FrontComponentEntityName, pageToInputCascade, sectionTemplateToInput, PageMetaFields, pageToInput, PageMetaAssciations, frontComponentToInput, ComponentCategoryEntityName, componentCategoryToInput, themeToInput, SectionTemplateEntityName, TemplateCategoryEntityName, templateCategoryToInput } from "@rxdrag/rxcms-models";
10
10
  import { GlobalLoading, EntityForm, SubmitButton, useListData, SearchInput, EntityPagination, useIsLoading, QueryListScope, useRemoveRow, useEditRow, EntityEditModal, useSelectionsState, EntityTable, EntityListScope, NewButton, EntityRowScope, EntitySelectField, useNewRow } from "@rxdrag/rxcms-models-ui";
11
- import { useOneTheme, usePageList, useTemplateCategoryList, useSectionTemplateList, useComponentCategoryList, useFrontComponentList, useOneThemeById, useUpsertOneTheme, useOneThemeConfig, useUpsertOneThemeConfig, useUpsertOneWebsite, useDeleteThemeById, useLangList, useUpsertOnePage, useUpsertOneSectionTemplate, useDeletePageById, useUpsertOneFrontComponent } from "@rxdrag/rxcms-model-hooks";
12
- import { newPageMetaOptions, useWebsite, useCurrentLang, ComponentType, MediaSingleSelectField, currentLangState, TitleAndSlug, TitleViewField, DescriptionViewField, SiteRoot } from "@rxdrag/biz-components";
11
+ import { useOneTheme, usePageList, useTemplateCategoryList, useSectionTemplateList, useComponentCategoryList, useFrontComponentList, useOneThemeById, useUpsertOneWebsite, useDeleteThemeById, useUpsertOneTheme, useLangList, useOneThemeConfig, useUpsertOneThemeConfig, useUpsertOnePage, useUpsertOneSectionTemplate, useDeletePageById, useUpsertOneFrontComponent } from "@rxdrag/rxcms-model-hooks";
12
+ import { newPageMetaOptions, useWebsite, useCurrentLang, ComponentType, currentLangState, MediaSingleSelectField, FullImageSelectField, TitleAndSlug, TitleViewField, DescriptionViewField, SiteRoot } from "@rxdrag/biz-components";
13
13
  import { parseExpressionValue, isExpression, extractVariables, compileCode, AsyncFunction, transformCodeToSchema, transformSchemaToCode } from "@rxdrag/astro-compiler";
14
14
  import { CommentNodeName, TextNodeName, CharNodeName } from "@rxdrag/schema-pro";
15
15
  import { useDesignerEngine, useComponentManager, useTreeNode, useComponentDesigner, usePlaceHolder, DefaultPlaceHolder, useBehavior, NodeContext, DocumentContext, useNode, Designer, useUndo, useRedo, useCurrentNode, useNodeMeta, useChangeNodeMeta, useSetters, useDocument, useDocumentChangedState, useActiveIdState, useSelect, useGetNode, useActions, useCurrentTree, useSelectedNodeIds, useResourceNode, DocumentRoot } from "@rxdrag/react-core-pro";
@@ -19,19 +19,19 @@ import { isHTMLElement, isStr } from "@rxdrag/shared";
19
19
  import { isFunction, debounce, keys, uniqueId } from "lodash-es";
20
20
  import { useEntifyEndpoint, useEntifyToken, useLazyQueryEntityList, useLazyQueryOneEntity, useCreateEntityClient, emitEntityChange } from "@rxdrag/entify-hooks";
21
21
  import dayjs from "dayjs";
22
- import { ErrorBoundary, ColorPicker, saveFile, SettingsIcon, AddIcon, ModalBody, ModalFooter, CheckCircleIcon, CloseIcon, TaskStopIcon, AiStarIcon, ConfirmDialog, Drawer, ModalHeader, ModalClose, SearchIcon, ModalContent, Modal, ModalOverlay, ChevronDownIcon, MonacoEditor, DarkIcon, LightIcon, MoreIcon, LanguageIcon, StyledTooltip, PlayIcon, Logo, WarningIcon, PinIcon, PredefinedColorPicker, PagesIcon, WidgetIcon, SeoIcon, LeafNode, GroupNode, TreeView, DesignIcon, EditIcon, RemoveIcon, ResetIcon, ImportIcon, AstroIcon, AddFolderIcon, TemplateIcon, getTheFile, AddTemplateIcon } from "@rxdrag/rxcms-common";
22
+ import { ErrorBoundary, ColorPicker, useSave, CheckCircleIcon, CloseIcon, ModalBody, AddIcon, TaskStopIcon, AiStarIcon, ConfirmDialog, SettingsIcon, ModalFooter, FavouriteIcon, LightIcon, DarkIcon, Drawer, ModalHeader, ModalClose, SearchIcon, ModalContent, Modal, ModalOverlay, ChevronDownIcon, MonacoEditor, MoreIcon, LanguageIcon, StyledTooltip, PlayIcon, Logo, GlobalIcon, SnsIcon, LightBoltIcon, WarningIcon, PinIcon, PredefinedColorPicker, PagesIcon, WidgetIcon, SeoIcon, LeafNode, GroupNode, TreeView, DesignIcon, EditIcon, RemoveIcon, ResetIcon, ImportIcon, AstroIcon, AddFolderIcon, TemplateIcon, getTheFile, AddTemplateIcon } from "@rxdrag/rxcms-common";
23
23
  import { PageLoader, PopoverController, ModalController, AnimateController, TabsController, NumberController, FlipController, CollapseController, AosController } from "@rxdrag/website-lib-core";
24
24
  import gsap from "gsap";
25
25
  import { Input, Textarea, StringArrayInput, ImageSelect, TargetSetter, propSetters, DeviceBreakpoints, DeviceContext } from "@rxdrag/schema-setters";
26
- import { Switch, Accordion, AccordionItem, Input as Input$1, Select, SelectItem, Button as Button$1, Tabs, Tab, Divider, Card, CardHeader, CardBody, CircularProgress, Dropdown, DropdownTrigger, DropdownMenu, DropdownItem, Skeleton, CardFooter, Image, Chip, Checkbox, useDisclosure, cn, Popover, PopoverTrigger, PopoverContent } from "@heroui/react";
26
+ import { Switch, Card, CardBody, Button as Button$1, CircularProgress, CardHeader, Select, SelectItem, Dropdown, DropdownTrigger, DropdownMenu, DropdownItem, Accordion, AccordionItem, Input as Input$1, Tabs, Tab, Divider, Skeleton, CardFooter, Image, Chip, Checkbox, useDisclosure, cn, Popover, PopoverTrigger, PopoverContent } from "@heroui/react";
27
+ import { useSetRecoilState, atom, useRecoilState, useRecoilValue, selector } from "recoil";
27
28
  import { globalErrorState, useUpsertEntityWithIndicator, globalSuccessState } from "@rxdrag/rxcms-entify-wrapper";
28
- import { atom, useSetRecoilState, useRecoilValue, useRecoilState, selector } from "recoil";
29
29
  import JSZip from "jszip";
30
- import { InputField, TextareaField, Form } from "@rxdrag/fieldy-heroui";
31
- import { ObjectField, VirtualForm } from "@rxdrag/react-fieldy-pro";
32
30
  import { Icon } from "@iconify/react";
33
31
  import { useInprogressTaskByKey, useUpdateTask, taskPool, TranslateThemeTask, TaskManager, ResetPageTask, ImportPagesTask, ImportComponentsTask } from "@rxdrag/ai-tasks";
34
32
  import { useAiUrl, useAiAgent, AiWidget, AiAgentRoot } from "@rxdrag/ai-agent";
33
+ import { InputField, TextareaField, toField, ColorField, Form } from "@rxdrag/fieldy-heroui";
34
+ import { ObjectField, useFormValue, useForm, VirtualForm } from "@rxdrag/react-fieldy-pro";
35
35
  import { useParams } from "react-router-dom";
36
36
  import { LazyMotion, AnimatePresence, m } from "framer-motion";
37
37
  import { ComponentRender } from "@rxdrag/react-runner-pro";
@@ -1167,6 +1167,10 @@ function newThemeQueryOptions(websiteId, langId) {
1167
1167
  LangFields.cnName,
1168
1168
  LangFields.localName,
1169
1169
  LangFields.enName
1170
+ ]).config([
1171
+ ThemeConfigFields.id,
1172
+ ThemeConfigFields.domain,
1173
+ ThemeConfigFields.websiteTitle
1170
1174
  ]).setNoQuery(!websiteId || !langId);
1171
1175
  }
1172
1176
  function fullThemeQueryOptions() {
@@ -1177,6 +1181,15 @@ function fullThemeQueryOptions() {
1177
1181
  StyleConfigFields.cssVariants,
1178
1182
  StyleConfigFields.tailwindConfig,
1179
1183
  StyleConfigFields.description
1184
+ ]).config([
1185
+ ThemeConfigFields.id,
1186
+ ThemeConfigFields.domain,
1187
+ ThemeConfigFields.websiteTitle,
1188
+ ThemeConfigFields.svgIcon,
1189
+ ThemeConfigFields.themeColor,
1190
+ ThemeConfigFields.pngIcon,
1191
+ ThemeConfigFields.icoIcon,
1192
+ ThemeConfigFields.appleTouchIcon
1180
1193
  ]).lang([LangFields.id, LangFields.abbr]);
1181
1194
  }
1182
1195
  function newThemeByIdQueryOptions() {
@@ -2129,6 +2142,13 @@ Ideal for **manufacturing, logistics, automation, and more**, our **[Product Nam
2129
2142
  };
2130
2143
  }
2131
2144
  );
2145
+ const mockWebsite = {
2146
+ id: "website",
2147
+ name: "TestWebsite",
2148
+ title: "测试网站",
2149
+ baseLang: mockLangs[0],
2150
+ langs: mockLangs
2151
+ };
2132
2152
  class MockEntify {
2133
2153
  queryEntityList(options, staticKey) {
2134
2154
  if ((options == null ? void 0 : options.entityName) === ProductCategoryEntityName) {
@@ -2181,6 +2201,9 @@ class MockEntify {
2181
2201
  }
2182
2202
  return Promise.resolve({ items: [] });
2183
2203
  }
2204
+ getWebsite() {
2205
+ return Promise.resolve(mockWebsite);
2206
+ }
2184
2207
  getTheme() {
2185
2208
  return Promise.resolve(mockTheme);
2186
2209
  }
@@ -2466,9 +2489,7 @@ function useImportVariables() {
2466
2489
  websiteId: (website == null ? void 0 : website.id) || "",
2467
2490
  entifyServerUrl: endpoint || "",
2468
2491
  entifyGuestToken: token || "",
2469
- language: (lang == null ? void 0 : lang.abbr) || "",
2470
- formSalt: "yizhanfei"
2471
- //实际无效
2492
+ language: (lang == null ? void 0 : lang.abbr) || ""
2472
2493
  };
2473
2494
  return {
2474
2495
  rx: new MockEntify(),
@@ -2479,7 +2500,8 @@ function useImportVariables() {
2479
2500
  PublishableStatus,
2480
2501
  getEnvVariables: () => envs,
2481
2502
  dayjs,
2482
- rxPage: mockRxPage
2503
+ rxPage: mockRxPage,
2504
+ FORM_SALT: "form_salt"
2483
2505
  };
2484
2506
  }, [endpoint, lang == null ? void 0 : lang.abbr, token, website == null ? void 0 : website.id]);
2485
2507
  return variables;
@@ -3091,8 +3113,6 @@ const createEnv = (theme) => {
3091
3113
  #nodejs服务地址
3092
3114
  #PUBLIC_WEBSITE_ID = 4299262263296
3093
3115
  PUBLIC_ENTIFY_GUEST_TOKEN = "17bD#4!fG8^2wS*0z"
3094
- #表单加密盐
3095
- PUBLIC_FORM_SALT = "yizhanfeinb"
3096
3116
  `;
3097
3117
  };
3098
3118
  const gitignoreCode = `# build output
@@ -3132,11 +3152,12 @@ const faviconCode = `<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox
3132
3152
  </defs>
3133
3153
  </svg>`;
3134
3154
  const createBaseCssCode = (theme) => {
3155
+ var _a;
3135
3156
  return `@tailwind base;
3136
3157
  @tailwind components;
3137
3158
  @tailwind utilities;
3138
3159
 
3139
- ${theme.css || ""}
3160
+ ${((_a = theme.styleConfig) == null ? void 0 : _a.css) || ""}
3140
3161
 
3141
3162
  `;
3142
3163
  };
@@ -3178,14 +3199,13 @@ const libCode = `import {
3178
3199
  entifyServerUrl: ({}).PUBLIC_ENTIFY_SERVER_URL,
3179
3200
  entifyGuestToken: ({}).PUBLIC_ENTIFY_GUEST_TOKEN,
3180
3201
  language: ({}).PUBLIC_LANGUAGE,
3181
- formSalt: ({}).PUBLIC_FORM_SALT || "yizhanfei",
3182
3202
  };
3183
3203
  }
3184
3204
 
3185
3205
  export const rx = Entify.getInstance(getEnvVariables()) as IEntify;
3186
3206
  `;
3187
3207
  const layoutCode = `---
3188
- import "../base.css";
3208
+ import "../style.css";
3189
3209
  import { ClientRouter } from "astro:transitions";
3190
3210
  ---
3191
3211
 
@@ -3306,7 +3326,7 @@ const askForQuoteCode = `import type { APIRoute } from "astro";
3306
3326
  // 验证加密字段
3307
3327
  const isValid = verifyEncryption(
3308
3328
  //加密盐
3309
- envVariables.formSalt,
3329
+ "yizhanfeinb",
3310
3330
  encryptedField,
3311
3331
  phone || "",
3312
3332
  30 // 30分钟有效期
@@ -3478,34 +3498,6 @@ const askForQuoteCode = `import type { APIRoute } from "astro";
3478
3498
  }
3479
3499
  };
3480
3500
  `;
3481
- const settingsCode = `{
3482
- "css.validate": true,
3483
- "less.validate": true,
3484
- "scss.validate": true,
3485
- "stylelint.validate": ["css", "scss"],
3486
- "editor.quickSuggestions": {
3487
- "strings": true
3488
- },
3489
- "css.lint.unknownAtRules": "ignore"
3490
- }
3491
- `;
3492
- const extensionsCode = `{
3493
- "recommendations": ["astro-build.astro-vscode"],
3494
- "unwantedRecommendations": []
3495
- }
3496
- `;
3497
- const launchCode = `{
3498
- "version": "0.2.0",
3499
- "configurations": [
3500
- {
3501
- "command": "./node_modules/.bin/astro dev",
3502
- "name": "Development server",
3503
- "request": "launch",
3504
- "type": "node-terminal"
3505
- }
3506
- ]
3507
- }
3508
- `;
3509
3501
  const createBaseFiles = (theme) => {
3510
3502
  return {
3511
3503
  "package.json": {
@@ -3538,25 +3530,6 @@ const createBaseFiles = (theme) => {
3538
3530
  contents: tailwindConfigCode
3539
3531
  }
3540
3532
  },
3541
- ".vscode": {
3542
- directory: {
3543
- "settings.json": {
3544
- file: {
3545
- contents: settingsCode
3546
- }
3547
- },
3548
- "extensions.json": {
3549
- file: {
3550
- contents: extensionsCode
3551
- }
3552
- },
3553
- "launch.json": {
3554
- file: {
3555
- contents: launchCode
3556
- }
3557
- }
3558
- }
3559
- },
3560
3533
  src: {
3561
3534
  directory: {
3562
3535
  layouts: {
@@ -3593,7 +3566,7 @@ const createBaseFiles = (theme) => {
3593
3566
  }
3594
3567
  }
3595
3568
  },
3596
- "base.css": {
3569
+ "style.css": {
3597
3570
  file: {
3598
3571
  contents: createBaseCssCode(theme)
3599
3572
  }
@@ -3775,20 +3748,57 @@ function useGetFiles() {
3775
3748
  );
3776
3749
  return getFiles;
3777
3750
  }
3778
- function useSave(onSaved) {
3779
- const save = useCallback(
3780
- (name, content) => {
3781
- saveFile(name, content).then(
3782
- (savedName) => {
3783
- if (savedName) {
3784
- onSaved && onSaved();
3751
+ function useExportWebsite() {
3752
+ const [isExporting, setIsExporting] = useState(false);
3753
+ const setError = useSetRecoilState(globalErrorState);
3754
+ const theme = useStudioTheme();
3755
+ const save = useSave();
3756
+ const getFiles = useGetFiles();
3757
+ const addFilesToZip = useCallback(
3758
+ (zip, files, currentPath = "") => {
3759
+ for (const [name, content] of Object.entries(files)) {
3760
+ const path = currentPath ? `${currentPath}/${name}` : name;
3761
+ if (content.file && content.file.contents) {
3762
+ zip.file(path, content.file.contents);
3763
+ } else if (content.directory) {
3764
+ const folder = zip.folder(path);
3765
+ if (folder) {
3766
+ addFilesToZip(folder, content.directory, "");
3767
+ }
3768
+ } else if (typeof content === "object" && content !== null) {
3769
+ if (name === "src" || name === "public" || name === "components" || name === "pages") {
3770
+ const folder = zip.folder(path);
3771
+ if (folder) {
3772
+ addFilesToZip(folder, content, "");
3773
+ }
3774
+ } else {
3775
+ addFilesToZip(zip, content, path);
3785
3776
  }
3786
3777
  }
3787
- );
3778
+ }
3788
3779
  },
3789
- [onSaved]
3780
+ []
3790
3781
  );
3791
- return save;
3782
+ const exportWebsite = useCallback(async () => {
3783
+ try {
3784
+ if (theme == null ? void 0 : theme.id) {
3785
+ setIsExporting(true);
3786
+ const files = await getFiles(theme);
3787
+ const zip = new JSZip();
3788
+ console.log("开始导出文件...");
3789
+ addFilesToZip(zip, files);
3790
+ const content = await zip.generateAsync({ type: "blob" });
3791
+ const fileName = `website-${theme.name || theme.id}-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`;
3792
+ save(fileName, content);
3793
+ }
3794
+ } catch (e) {
3795
+ console.error(e);
3796
+ setError(e == null ? void 0 : e.message);
3797
+ } finally {
3798
+ setIsExporting(false);
3799
+ }
3800
+ }, [getFiles, save, setError, theme, addFilesToZip]);
3801
+ return { exportWebsite, isExporting };
3792
3802
  }
3793
3803
  var ContentType = /* @__PURE__ */ ((ContentType2) => {
3794
3804
  ContentType2["Page"] = "page";
@@ -3819,78 +3829,6 @@ var ViewMode = /* @__PURE__ */ ((ViewMode2) => {
3819
3829
  ViewMode2["Code"] = "code";
3820
3830
  return ViewMode2;
3821
3831
  })(ViewMode || {});
3822
- const defaultSchema = {
3823
- componentName: "Root"
3824
- };
3825
- const emptyValue = { schema: void 0, config: void 0 };
3826
- function useSchema(selectedContent) {
3827
- const [schema, setSchema] = useState(emptyValue);
3828
- const components = useFrontComponents();
3829
- const pages = usePages();
3830
- const componentsRef = useRef(components);
3831
- const pagesRef = useRef(pages);
3832
- componentsRef.current = components;
3833
- pagesRef.current = pages;
3834
- const templates = useTemplates();
3835
- const templatesRef = useRef(templates);
3836
- templatesRef.current = templates;
3837
- useEffect(() => {
3838
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
3839
- let code;
3840
- let hasContent = false;
3841
- let defaultConfig;
3842
- if ((selectedContent == null ? void 0 : selectedContent.type) === ContentType.Component) {
3843
- const component = (_a = componentsRef.current) == null ? void 0 : _a.find(
3844
- (component2) => component2.id === selectedContent.id
3845
- );
3846
- if (component) {
3847
- code = component.code;
3848
- hasContent = true;
3849
- }
3850
- } else if ((selectedContent == null ? void 0 : selectedContent.type) === ContentType.PredefinedPage || (selectedContent == null ? void 0 : selectedContent.type) === ContentType.Page) {
3851
- const page = (_b = pagesRef.current) == null ? void 0 : _b.find(
3852
- (item) => item.id === selectedContent.id
3853
- );
3854
- defaultConfig = {
3855
- pageMeta: {
3856
- seoTitle: (_c = page == null ? void 0 : page.meta) == null ? void 0 : _c.seoTitle,
3857
- seoDescription: (_d = page == null ? void 0 : page.meta) == null ? void 0 : _d.seoDescription,
3858
- seoKeywords: (_e = page == null ? void 0 : page.meta) == null ? void 0 : _e.seoKeywords,
3859
- ogTitle: (_f = page == null ? void 0 : page.meta) == null ? void 0 : _f.ogTitle,
3860
- ogDescription: (_g = page == null ? void 0 : page.meta) == null ? void 0 : _g.ogDescription,
3861
- ogType: (_h = page == null ? void 0 : page.meta) == null ? void 0 : _h.ogType,
3862
- ogImage: (_i = page == null ? void 0 : page.meta) == null ? void 0 : _i.ogImage
3863
- }
3864
- };
3865
- if (page) {
3866
- code = page.code;
3867
- hasContent = true;
3868
- }
3869
- } else if ((selectedContent == null ? void 0 : selectedContent.type) === ContentType.Template) {
3870
- const template = (_j = templatesRef.current) == null ? void 0 : _j.find(
3871
- (template2) => template2.id === selectedContent.id
3872
- );
3873
- if (template) {
3874
- code = template.code;
3875
- hasContent = true;
3876
- }
3877
- }
3878
- if (code) {
3879
- transformCodeToSchema(code).then((value) => {
3880
- setSchema({
3881
- schema: { ...defaultSchema, children: (value == null ? void 0 : value.template) || [] },
3882
- config: { ...defaultConfig, ...value.resources }
3883
- });
3884
- });
3885
- } else if (hasContent) {
3886
- setSchema({
3887
- schema: { ...defaultSchema, children: [] }
3888
- });
3889
- }
3890
- }, [selectedContent == null ? void 0 : selectedContent.id, selectedContent == null ? void 0 : selectedContent.type]);
3891
- console.log("===>schema", schema);
3892
- return schema;
3893
- }
3894
3832
  const defaultDesktopWidth = 1280;
3895
3833
  const defaultTabletWidth = 800;
3896
3834
  const defaultMobileWidth = 480;
@@ -3966,74 +3904,6 @@ const bgColorState = atom({
3966
3904
  key: "studio.bgColor",
3967
3905
  default: "#ffffff"
3968
3906
  });
3969
- function useCloseDrawer() {
3970
- const setDrawerType = useSetRecoilState(drawerTypeState);
3971
- const drawerDocked = useRecoilValue(drawerDockedState);
3972
- const close = useCallback(() => {
3973
- if (!drawerDocked) {
3974
- setDrawerType(void 0);
3975
- }
3976
- }, [drawerDocked, setDrawerType]);
3977
- return close;
3978
- }
3979
- function useIsBaseLangTheme() {
3980
- var _a, _b;
3981
- const theme = useStudioTheme();
3982
- const website = useWebsite();
3983
- return ((_a = theme == null ? void 0 : theme.lang) == null ? void 0 : _a.id) === ((_b = website == null ? void 0 : website.baseLang) == null ? void 0 : _b.id);
3984
- }
3985
- function useExportWebsite() {
3986
- const [isExporting, setIsExporting] = useState(false);
3987
- const setError = useSetRecoilState(globalErrorState);
3988
- const theme = useStudioTheme();
3989
- const save = useSave();
3990
- const getFiles = useGetFiles();
3991
- const addFilesToZip = useCallback(
3992
- (zip, files, currentPath = "") => {
3993
- for (const [name, content] of Object.entries(files)) {
3994
- const path = currentPath ? `${currentPath}/${name}` : name;
3995
- if (content.file && content.file.contents) {
3996
- zip.file(path, content.file.contents);
3997
- } else if (content.directory) {
3998
- const folder = zip.folder(path);
3999
- if (folder) {
4000
- addFilesToZip(folder, content.directory, "");
4001
- }
4002
- } else if (typeof content === "object" && content !== null) {
4003
- if (name === "src" || name === "public" || name === "components" || name === "pages") {
4004
- const folder = zip.folder(path);
4005
- if (folder) {
4006
- addFilesToZip(folder, content, "");
4007
- }
4008
- } else {
4009
- addFilesToZip(zip, content, path);
4010
- }
4011
- }
4012
- }
4013
- },
4014
- []
4015
- );
4016
- const exportWebsite = useCallback(async () => {
4017
- try {
4018
- if (theme == null ? void 0 : theme.id) {
4019
- setIsExporting(true);
4020
- const files = await getFiles(theme);
4021
- const zip = new JSZip();
4022
- console.log("开始导出文件...");
4023
- addFilesToZip(zip, files);
4024
- const content = await zip.generateAsync({ type: "blob" });
4025
- const fileName = `website-${theme.name || theme.id}-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`;
4026
- save(fileName, content);
4027
- }
4028
- } catch (e) {
4029
- console.error(e);
4030
- setError(e == null ? void 0 : e.message);
4031
- } finally {
4032
- setIsExporting(false);
4033
- }
4034
- }, [getFiles, save, setError, theme, addFilesToZip]);
4035
- return { exportWebsite, isExporting };
4036
- }
4037
3907
  var ThemeConfigType = /* @__PURE__ */ ((ThemeConfigType2) => {
4038
3908
  ThemeConfigType2["MultiLang"] = "multi-Lang";
4039
3909
  ThemeConfigType2["Tailwind"] = "tailwind";
@@ -4043,1045 +3913,1349 @@ var ThemeConfigType = /* @__PURE__ */ ((ThemeConfigType2) => {
4043
3913
  ThemeConfigType2["WebsiteInfo"] = "websiteInfo";
4044
3914
  ThemeConfigType2["EmailTemplates"] = "emailTemplates";
4045
3915
  ThemeConfigType2["Fonts"] = "fonts";
3916
+ ThemeConfigType2["Favicon"] = "favicon";
4046
3917
  return ThemeConfigType2;
4047
3918
  })(ThemeConfigType || {});
4048
- const inputClassNames$1 = {
4049
- label: "w-16 flex items-center ps-0 pe-0 shrink-0 justify-end pr-2 text-default-500",
4050
- base: "flex items-center px-0",
4051
- wrapper: "flex-1",
4052
- mainWrapper: "flex-1 pr-4"
4053
- };
4054
- function ExtendsTable(props) {
4055
- const { fields: fields2, onChange } = props;
4056
- const handleAddField = useCallback(() => {
4057
- onChange == null ? void 0 : onChange([...fields2 || [], {
4058
- name: "newField",
4059
- title: "新建字段",
4060
- type: ExtendFieldType.String,
4061
- component: ComponentType.Input
4062
- }]);
4063
- }, [fields2, onChange]);
4064
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4065
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4066
- Accordion,
4067
- {
4068
- isCompact: true,
4069
- children: (fields2 == null ? void 0 : fields2.map((field, index) => {
4070
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
4071
- AccordionItem,
4072
- {
4073
- classNames: {
4074
- title: "text-sm"
4075
- },
4076
- title: `#${index + 1} ${field.title || field.name}`,
4077
- children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2 px-3", children: [
4078
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4079
- Input$1,
4080
- {
4081
- variant: "flat",
4082
- value: field.name,
4083
- size: "sm",
4084
- label: "名称",
4085
- labelPlacement: "outside-left",
4086
- classNames: inputClassNames$1,
4087
- onChange: (e) => {
4088
- const newName = e.target.value;
4089
- onChange == null ? void 0 : onChange(fields2.map((field2, i2) => {
4090
- if (i2 === index) {
4091
- return {
4092
- ...field2,
4093
- name: newName
4094
- };
4095
- }
4096
- return field2;
4097
- }));
4098
- }
4099
- }
4100
- ),
4101
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4102
- Input$1,
4103
- {
4104
- label: "标题",
4105
- size: "sm",
4106
- variant: "flat",
4107
- value: field.title,
4108
- labelPlacement: "outside-left",
4109
- classNames: inputClassNames$1,
4110
- onChange: (e) => {
4111
- const newTitle = e.target.value;
4112
- onChange == null ? void 0 : onChange(fields2.map((field2, i2) => {
4113
- if (i2 === index) {
4114
- return {
4115
- ...field2,
4116
- title: newTitle
4117
- };
4118
- }
4119
- return field2;
4120
- }));
4121
- }
4122
- }
4123
- ),
4124
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
4125
- Select,
4126
- {
4127
- label: "类型",
4128
- size: "sm",
4129
- variant: "flat",
4130
- selectedKeys: field.type ? [field.type] : [],
4131
- labelPlacement: "outside-left",
4132
- classNames: inputClassNames$1,
4133
- onChange: (e) => {
4134
- onChange == null ? void 0 : onChange(fields2.map((field2, i2) => {
4135
- if (i2 === index) {
4136
- return {
4137
- ...field2,
4138
- type: e.target.value || void 0
4139
- };
4140
- }
4141
- return field2;
4142
- }));
4143
- },
4144
- children: [
4145
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "文本" }, ExtendFieldType.String),
4146
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "数字" }, ExtendFieldType.Number),
4147
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "布尔" }, ExtendFieldType.Boolean),
4148
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "JSON" }, ExtendFieldType.Json),
4149
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "日期" }, ExtendFieldType.Date)
4150
- ]
4151
- }
4152
- ),
4153
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
4154
- Select,
4155
- {
4156
- label: "编辑组件",
4157
- size: "sm",
4158
- variant: "flat",
4159
- selectedKeys: field.component ? [field.component] : [],
4160
- labelPlacement: "outside-left",
4161
- classNames: inputClassNames$1,
4162
- onChange: (e) => {
4163
- onChange == null ? void 0 : onChange(fields2.map((field2, i2) => {
4164
- if (i2 === index) {
4165
- return {
4166
- ...field2,
4167
- component: e.target.value || void 0
4168
- };
4169
- }
4170
- return field2;
4171
- }));
4172
- },
4173
- endContent: /* @__PURE__ */ jsxRuntimeExports.jsx(
4174
- Button$1,
4175
- {
4176
- as: "div",
4177
- size: "sm",
4178
- variant: "light",
4179
- isIconOnly: true,
4180
- className: "flex items-center justify-center",
4181
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(SettingsIcon, { className: "size-4" })
4182
- }
4183
- ),
4184
- children: [
4185
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "单行输入框" }, ComponentType.Input),
4186
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "数字入框" }, ComponentType.NumberInput),
4187
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "多行输入框" }, ComponentType.Textarea),
4188
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "开关" }, ComponentType.Switch),
4189
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "图片选择" }, ComponentType.ImageSelect),
4190
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "链接目标" }, ComponentType.LinkTarget)
4191
- ]
4192
- }
4193
- ),
4194
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4195
- Button$1,
4196
- {
4197
- size: "sm",
4198
- variant: "light",
4199
- color: "danger",
4200
- onPress: () => {
4201
- onChange == null ? void 0 : onChange(fields2.filter((_2, i2) => i2 !== index));
4202
- },
4203
- children: "删除字段"
4204
- }
4205
- )
4206
- ] })
4207
- },
4208
- index
4209
- );
4210
- })) || []
3919
+ function LangCard(props) {
3920
+ var _a;
3921
+ const { isSelected, isBaseLang, lang, onSelect } = props;
3922
+ const website = useWebsite();
3923
+ const [removing, setRemoving] = useState(false);
3924
+ const [upsertWebsite, { isMutating }] = useUpsertOneWebsite();
3925
+ const [currentLang, setCurrentLang] = useRecoilState(currentLangState);
3926
+ const setSelectedContent = useSetRecoilState(selectedContentState);
3927
+ const queryTheme = useLazyQueryOneEntity();
3928
+ const [removeTheme] = useDeleteThemeById();
3929
+ const handleDelete = useCallback(async () => {
3930
+ var _a2, _b, _c;
3931
+ try {
3932
+ setRemoving(true);
3933
+ if (((_a2 = website == null ? void 0 : website.baseLang) == null ? void 0 : _a2.id) === lang.id) {
3934
+ return;
4211
3935
  }
4212
- ),
4213
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4214
- Button$1,
4215
- {
4216
- variant: "flat",
4217
- size: "sm",
4218
- className: "mt-2",
4219
- startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(AddIcon, { className: "size-5" }),
4220
- onPress: handleAddField,
4221
- children: "添加"
3936
+ await upsertWebsite(
3937
+ websiteToInput({
3938
+ id: website == null ? void 0 : website.id,
3939
+ langs: (_b = website == null ? void 0 : website.langs) == null ? void 0 : _b.filter((l2) => l2.id !== lang.id)
3940
+ })
3941
+ );
3942
+ if (currentLang === lang.id) {
3943
+ setCurrentLang((_c = website == null ? void 0 : website.baseLang) == null ? void 0 : _c.id);
3944
+ setSelectedContent(void 0);
4222
3945
  }
4223
- )
4224
- ] });
4225
- }
4226
- function PostPanel(props) {
4227
- const { settings, onChange } = props;
3946
+ const langTheme = await queryTheme(
3947
+ new ThemeQueryOptions([ThemeFields.id], {
3948
+ where: {
3949
+ website: {
3950
+ id: {
3951
+ _eq: website == null ? void 0 : website.id
3952
+ }
3953
+ },
3954
+ lang: {
3955
+ id: {
3956
+ _eq: lang.id
3957
+ }
3958
+ }
3959
+ }
3960
+ }).toGqlOptions()
3961
+ );
3962
+ if (langTheme.id) {
3963
+ removeTheme(langTheme.id);
3964
+ }
3965
+ } finally {
3966
+ setRemoving(false);
3967
+ }
3968
+ }, [
3969
+ currentLang,
3970
+ lang.id,
3971
+ queryTheme,
3972
+ removeTheme,
3973
+ setCurrentLang,
3974
+ setSelectedContent,
3975
+ upsertWebsite,
3976
+ (_a = website == null ? void 0 : website.baseLang) == null ? void 0 : _a.id,
3977
+ website == null ? void 0 : website.id,
3978
+ website == null ? void 0 : website.langs
3979
+ ]);
4228
3980
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
4229
- "div",
3981
+ Card,
4230
3982
  {
4231
- className: "flex flex-col gap-4 overflow-x-hidden py-2",
4232
- children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col gap-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4233
- ExtendsTable,
4234
- {
4235
- fields: settings == null ? void 0 : settings.fields,
4236
- onChange: (fields2) => {
4237
- onChange == null ? void 0 : onChange({
4238
- ...settings,
4239
- fields: fields2
4240
- });
4241
- }
4242
- }
4243
- ) })
3983
+ shadow: "sm",
3984
+ className: "bg-background cursor-pointer transition-colors group relative",
3985
+ classNames: {
3986
+ base: isSelected ? "outline-2 outline-primary" : "hover:bg-default-100"
3987
+ },
3988
+ isPressable: !removing,
3989
+ as: "div",
3990
+ isDisabled: removing,
3991
+ onPress: () => onSelect(lang.id),
3992
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(CardBody, { className: "p-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
3993
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
3994
+ lang.icon && /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { icon: lang.icon, className: "text-2xl shrink-0" }),
3995
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
3996
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
3997
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "font-medium truncate", children: lang.cnName }),
3998
+ isBaseLang && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "shrink-0 inline-flex items-center px-1.5 py-0.5 rounded-full bg-success/10 border border-primary/20", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-primary font-medium leading-none", children: "基准语言" }) })
3999
+ ] }),
4000
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-default-500 truncate", children: lang.abbr })
4001
+ ] })
4002
+ ] }),
4003
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
4004
+ isSelected && /* @__PURE__ */ jsxRuntimeExports.jsx(CheckCircleIcon, { className: "text-primary size-5 shrink-0" }),
4005
+ !isBaseLang && !isMutating && /* @__PURE__ */ jsxRuntimeExports.jsx(
4006
+ Button$1,
4007
+ {
4008
+ isIconOnly: true,
4009
+ size: "sm",
4010
+ variant: "light",
4011
+ className: "absolute top-1 right-1 w-6 h-6 min-w-6 min-h-6 rounded-full text-default-400 hover:text-default-500 group-hover:opacity-100 opacity-0 transition-opacity duration-300",
4012
+ onPress: handleDelete,
4013
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(CloseIcon, { className: "size-4" })
4014
+ }
4015
+ ),
4016
+ isMutating && /* @__PURE__ */ jsxRuntimeExports.jsx(
4017
+ CircularProgress,
4018
+ {
4019
+ "aria-label": "Loading...",
4020
+ size: "sm",
4021
+ className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2"
4022
+ }
4023
+ )
4024
+ ] })
4025
+ ] }) })
4244
4026
  }
4245
4027
  );
4246
4028
  }
4247
- function ProductPanel(props) {
4248
- const { settings, onChange } = props;
4249
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
4250
- "div",
4251
- {
4252
- className: "flex flex-col gap-4 overflow-x-hidden py-2",
4253
- children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col gap-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4254
- ExtendsTable,
4255
- {
4256
- fields: settings == null ? void 0 : settings.fields,
4257
- onChange: (fields2) => {
4258
- onChange == null ? void 0 : onChange({
4259
- ...settings,
4260
- fields: fields2
4261
- });
4262
- }
4263
- }
4264
- ) })
4265
- }
4029
+ const TRANSLATE_THEME_KEY = "translate-theme";
4030
+ function useTranslateThemeTask() {
4031
+ const theme = useStudioTheme();
4032
+ const lang = useCurrentLang();
4033
+ const baseThemeId = useBaseLangThemeId();
4034
+ const appKey = (theme == null ? void 0 : theme.id) || "";
4035
+ const taskState = useInprogressTaskByKey(TRANSLATE_THEME_KEY, appKey);
4036
+ const setTask = useUpdateTask(appKey);
4037
+ const entifyClient = useCreateEntityClient();
4038
+ const task = taskState && taskState.status !== "done" ? taskPool[taskState.taskId] : void 0;
4039
+ const aiUrl = useAiUrl();
4040
+ const handleTaskChange = useCallback(
4041
+ (data) => {
4042
+ setTask(data);
4043
+ },
4044
+ [setTask]
4266
4045
  );
4267
- }
4268
- function ExtendsPanel() {
4269
- const [themeSettings, setThemeSettings] = useState();
4270
- const initialSettings = useThemeSettings();
4271
- const webTheme = useStudioTheme();
4272
- const [save, { isMutating }] = useUpsertOneTheme();
4273
- const changed = useMemo(() => {
4274
- return JSON.stringify(themeSettings || {}) !== JSON.stringify(initialSettings || {});
4275
- }, [themeSettings, initialSettings]);
4276
- const handleReset = useCallback(() => {
4277
- setThemeSettings(initialSettings);
4278
- }, [initialSettings]);
4279
- const handleSave = useCallback(() => {
4280
- save({
4281
- id: webTheme == null ? void 0 : webTheme.id,
4282
- settings: themeSettings || void 0
4046
+ const translateAndReset = useCallback(() => {
4047
+ if (!(theme == null ? void 0 : theme.id)) {
4048
+ console.error("没设置Theme");
4049
+ return;
4050
+ }
4051
+ if (!entifyClient) {
4052
+ console.error("entifyClient 创建失败");
4053
+ return;
4054
+ }
4055
+ if (!aiUrl) {
4056
+ console.error("没设置aiUrl");
4057
+ return;
4058
+ }
4059
+ if (!baseThemeId) {
4060
+ console.error("没设置baseThemeId");
4061
+ return;
4062
+ }
4063
+ const task2 = new TranslateThemeTask({
4064
+ key: TRANSLATE_THEME_KEY,
4065
+ entifyClient,
4066
+ baseThemeId,
4067
+ themeId: theme == null ? void 0 : theme.id,
4068
+ lang,
4069
+ aiUrl
4283
4070
  });
4284
- }, [save, themeSettings, webTheme == null ? void 0 : webTheme.id]);
4285
- useEffect(() => {
4286
- setThemeSettings(initialSettings);
4287
- }, [initialSettings]);
4288
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4289
- /* @__PURE__ */ jsxRuntimeExports.jsx(ModalBody, { className: "flex-1 min-h-0 overflow-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
4290
- Tabs,
4071
+ taskPool[task2.id] = task2;
4072
+ task2.onDataChange(handleTaskChange);
4073
+ task2.start();
4074
+ }, [aiUrl, baseThemeId, entifyClient, handleTaskChange, lang, theme == null ? void 0 : theme.id]);
4075
+ return { taskState, translateAndReset, task };
4076
+ }
4077
+ const linkTypes = [
4078
+ {
4079
+ key: "path",
4080
+ label: "子网址",
4081
+ description: "例如:example.com/en",
4082
+ icon: /* @__PURE__ */ jsxRuntimeExports.jsx(
4083
+ "svg",
4291
4084
  {
4292
- "aria-label": "extends",
4293
- className: "mt-2",
4294
- size: "sm",
4295
- children: [
4296
- /* @__PURE__ */ jsxRuntimeExports.jsx(Tab, { title: "产品", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4297
- ProductPanel,
4085
+ xmlns: "http://www.w3.org/2000/svg",
4086
+ className: "size-5 text-default-500",
4087
+ viewBox: "0 0 24 24",
4088
+ children: /* @__PURE__ */ jsxRuntimeExports.jsxs("g", { fill: "none", children: [
4089
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4090
+ "path",
4298
4091
  {
4299
- settings: themeSettings == null ? void 0 : themeSettings.product,
4300
- onChange: (settings) => {
4301
- setThemeSettings({
4302
- ...themeSettings,
4303
- product: settings
4304
- });
4305
- }
4092
+ stroke: "currentColor",
4093
+ strokeWidth: 1.5,
4094
+ d: "M2 12c0-4.714 0-7.071 1.464-8.536C4.93 2 7.286 2 12 2s7.071 0 8.535 1.464C22 4.93 22 7.286 22 12s0 7.071-1.465 8.535C19.072 22 16.714 22 12 22s-7.071 0-8.536-1.465C2 19.072 2 16.714 2 12Z"
4306
4095
  }
4307
- ) }, "product"),
4308
- /* @__PURE__ */ jsxRuntimeExports.jsx(Tab, { title: "文章", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4309
- PostPanel,
4096
+ ),
4097
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4098
+ "path",
4310
4099
  {
4311
- settings: themeSettings == null ? void 0 : themeSettings.post,
4312
- onChange: (settings) => {
4313
- setThemeSettings({
4314
- ...themeSettings,
4315
- post: settings
4316
- });
4317
- }
4100
+ fill: "currentColor",
4101
+ d: "M11.25 18a.75.75 0 0 0 1.5 0zM18 8l.53.53a.75.75 0 0 0 0-1.06zm-.97-2.03a.75.75 0 1 0-1.06 1.06zm-1.06 3a.75.75 0 1 0 1.06 1.06zM12.75 18v-6h-1.5v6zM16 8.75h2v-1.5h-2zm2.53-1.28l-1.5-1.5l-1.06 1.06l1.5 1.5zm-1.06 0l-1.5 1.5l1.06 1.06l1.5-1.5zM12.75 12A3.25 3.25 0 0 1 16 8.75v-1.5A4.75 4.75 0 0 0 11.25 12z"
4318
4102
  }
4319
- ) }, "post")
4320
- ]
4103
+ ),
4104
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4105
+ "path",
4106
+ {
4107
+ fill: "currentColor",
4108
+ d: "M11.25 18a.75.75 0 0 0 1.5 0zM6 8l-.53-.53a.75.75 0 0 0 0 1.06zm2.03-.97a.75.75 0 0 0-1.06-1.06zm-1.06 3a.75.75 0 1 0 1.06-1.06zM12.75 18v-6h-1.5v6zM8 7.25H6v1.5h2zM6.53 8.53l1.5-1.5l-1.06-1.06l-1.5 1.5zm-1.06 0l1.5 1.5l1.06-1.06l-1.5-1.5zM12.75 12A4.75 4.75 0 0 0 8 7.25v1.5A3.25 3.25 0 0 1 11.25 12z"
4109
+ }
4110
+ )
4111
+ ] })
4321
4112
  }
4322
- ) }),
4323
- /* @__PURE__ */ jsxRuntimeExports.jsxs(ModalFooter, { children: [
4324
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4325
- Button$1,
4326
- {
4327
- size: "sm",
4328
- isDisabled: !changed,
4329
- onPress: handleReset,
4330
- children: "重置"
4331
- }
4332
- ),
4333
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4334
- Button$1,
4335
- {
4336
- size: "sm",
4337
- isDisabled: !changed,
4338
- isLoading: isMutating,
4339
- color: "primary",
4340
- onPress: handleSave,
4341
- children: "保存"
4342
- }
4343
- )
4344
- ] })
4345
- ] });
4346
- }
4347
- function newThemeConfigOptions(theme) {
4348
- return new ThemeConfigQueryOptions(
4349
- [
4350
- ThemeConfigFields.id,
4351
- ThemeConfigFields.emailTemplates,
4352
- ThemeConfigFields.address,
4353
- ThemeConfigFields.contact,
4354
- ThemeConfigFields.email,
4355
- ThemeConfigFields.tel,
4356
- ThemeConfigFields.fax,
4357
- ThemeConfigFields.mobile,
4358
- ThemeConfigFields.wechat,
4359
- ThemeConfigFields.websiteTitle
4360
- ],
4361
- {
4362
- where: {
4363
- [ThemeConfigAssciations.theme]: {
4364
- id: {
4365
- _eq: theme == null ? void 0 : theme.id
4113
+ )
4114
+ },
4115
+ {
4116
+ key: "subdomain",
4117
+ label: "二级域名",
4118
+ description: "例如:en.example.com",
4119
+ icon: /* @__PURE__ */ jsxRuntimeExports.jsx(
4120
+ "svg",
4121
+ {
4122
+ xmlns: "http://www.w3.org/2000/svg",
4123
+ className: "size-5 text-default-500",
4124
+ viewBox: "0 0 24 24",
4125
+ children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
4126
+ "g",
4127
+ {
4128
+ fill: "none",
4129
+ stroke: "currentColor",
4130
+ strokeLinecap: "round",
4131
+ strokeWidth: 1.5,
4132
+ children: [
4133
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M14 12a6 6 0 1 1-6-6" }),
4134
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M10 12a6 6 0 1 1 6 6" })
4135
+ ]
4366
4136
  }
4367
- }
4137
+ )
4368
4138
  }
4369
- }
4370
- ).contactAvatar(new MediaQueryOptions().file(["thumbnail", "url"])).setNoQuery(!(theme == null ? void 0 : theme.id));
4371
- }
4372
- function WebsiteInfoPanel(props) {
4373
- const { onSuccess } = props;
4374
- const theme = useStudioTheme();
4139
+ )
4140
+ }
4141
+ ];
4142
+ function MultiLangPanel() {
4143
+ var _a, _b, _c, _d, _e, _f;
4144
+ const [linkType, setLinkType] = useState("subdomain");
4145
+ const [confirmOpen, setConfirmOpen] = useState(false);
4146
+ const [currentLang, setCurrentLang] = useRecoilState(currentLangState);
4147
+ const [selectedContent, setSelectedContent] = useRecoilState(selectedContentState);
4375
4148
  const website = useWebsite();
4376
- const websiteId = website == null ? void 0 : website.id;
4377
- const { data: themeConfig2 } = useOneThemeConfig(newThemeConfigOptions(theme));
4378
- const [save, { isMutating }] = useUpsertOneThemeConfig({
4379
- onSuccess
4380
- });
4381
- const handleSave = useCallback(
4382
- (value) => {
4383
- if (!value)
4384
- return;
4385
- save(themeConfigToInputCascade(value));
4386
- },
4387
- [save]
4149
+ const isChanginBaseLangRef = useRef(false);
4150
+ const [upsertTheme, { isMutating: isCreating }] = useUpsertOneTheme();
4151
+ const { taskState, task, translateAndReset } = useTranslateThemeTask();
4152
+ useEffect(() => {
4153
+ var _a2;
4154
+ if (website && !currentLang) {
4155
+ setCurrentLang((_a2 = website.baseLang) == null ? void 0 : _a2.id);
4156
+ }
4157
+ }, [currentLang, setCurrentLang, website]);
4158
+ const { data: allLangs, isLoading: allLangsLoading } = useLangList(
4159
+ new LangQueryOptions([
4160
+ LangFields.id,
4161
+ LangFields.abbr,
4162
+ LangFields.enName,
4163
+ LangFields.cnName,
4164
+ LangFields.localName,
4165
+ LangFields.description,
4166
+ LangFields.circleIcon,
4167
+ LangFields.icon
4168
+ ])
4388
4169
  );
4389
- return /* @__PURE__ */ jsxRuntimeExports.jsx(ModalBody, { className: "flex-1 min-h-0 overflow-auto p-4 px-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
4390
- EntityForm,
4391
- {
4392
- entityName: ThemeConfigEntityName,
4393
- initialValue: themeConfig2 || {
4394
- [ThemeConfigAssciations.theme]: {
4395
- id: theme == null ? void 0 : theme.id
4396
- }
4397
- },
4398
- globalValidationErrorMessage: "部分输入项有错误,请检查",
4399
- isMutating,
4400
- onSubmit: handleSave,
4401
- children: [
4402
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-4", children: [
4403
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-4", children: [
4404
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4405
- InputField,
4170
+ const [upsertWebsite, { isMutating }] = useUpsertOneWebsite();
4171
+ useEffect(() => {
4172
+ if (!isMutating) {
4173
+ isChanginBaseLangRef.current = false;
4174
+ }
4175
+ }, [isMutating]);
4176
+ const handleBaseLangChange = useCallback(
4177
+ (selection) => {
4178
+ isChanginBaseLangRef.current = true;
4179
+ upsertWebsite(
4180
+ websiteToInput({
4181
+ id: website == null ? void 0 : website.id,
4182
+ [WebsiteAssciations.baseLang]: { id: selection.currentKey }
4183
+ })
4184
+ );
4185
+ },
4186
+ [upsertWebsite, website == null ? void 0 : website.id]
4187
+ );
4188
+ const handleLangSelect = useCallback(
4189
+ (langId) => {
4190
+ setCurrentLang(langId);
4191
+ if ((selectedContent == null ? void 0 : selectedContent.id) && langId !== currentLang) {
4192
+ setSelectedContent(void 0);
4193
+ }
4194
+ },
4195
+ [selectedContent == null ? void 0 : selectedContent.id, setCurrentLang, setSelectedContent, currentLang]
4196
+ );
4197
+ const leftLangs = useMemo(() => {
4198
+ var _a2;
4199
+ return (_a2 = allLangs == null ? void 0 : allLangs.items) == null ? void 0 : _a2.filter(
4200
+ (lang) => {
4201
+ var _a3;
4202
+ return !((_a3 = website == null ? void 0 : website.langs) == null ? void 0 : _a3.some((l2) => l2.id === lang.id));
4203
+ }
4204
+ );
4205
+ }, [allLangs, website]);
4206
+ const handleAddLanguage = useCallback(
4207
+ async (langId) => {
4208
+ var _a2;
4209
+ await upsertWebsite(
4210
+ websiteToInput({
4211
+ id: website == null ? void 0 : website.id,
4212
+ [WebsiteAssciations.langs]: [
4213
+ ...((_a2 = website == null ? void 0 : website.langs) == null ? void 0 : _a2.map((lang) => ({
4214
+ id: lang.id
4215
+ }))) || [],
4216
+ { id: langId }
4217
+ ]
4218
+ })
4219
+ );
4220
+ if ((website == null ? void 0 : website.id) && langId) {
4221
+ console.log("create theme");
4222
+ await upsertTheme({
4223
+ name: (website.name || "") + (langId || "") + "主题",
4224
+ lang: {
4225
+ sync: { id: langId }
4226
+ },
4227
+ website: {
4228
+ sync: { id: website.id }
4229
+ }
4230
+ });
4231
+ }
4232
+ },
4233
+ [upsertTheme, upsertWebsite, website == null ? void 0 : website.id, website == null ? void 0 : website.langs, website == null ? void 0 : website.name]
4234
+ );
4235
+ const handleTranslate = useCallback(() => {
4236
+ setConfirmOpen(true);
4237
+ }, []);
4238
+ const handleStop = useCallback(() => {
4239
+ task == null ? void 0 : task.stop();
4240
+ }, [task]);
4241
+ const handleCloseConfirm = useCallback(() => {
4242
+ setConfirmOpen(false);
4243
+ }, []);
4244
+ const handleConfirm = useCallback(() => {
4245
+ translateAndReset();
4246
+ }, [translateAndReset]);
4247
+ const isRunning = (taskState == null ? void 0 : taskState.status) === "in-progress";
4248
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4249
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ModalBody, { className: "flex-1 p-4 min-h-0 overflow-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-4", children: [
4250
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { className: "bg-default-50", children: [
4251
+ /* @__PURE__ */ jsxRuntimeExports.jsx(CardHeader, { className: "flex gap-3 px-6 pt-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col flex-grow", children: [
4252
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-lg font-semibold", children: "基准语言" }),
4253
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-small text-default-500", children: "从已启用的语言中选择网站的基准语言,作为翻译的原稿,默认为英文" })
4254
+ ] }) }),
4255
+ /* @__PURE__ */ jsxRuntimeExports.jsx(CardBody, { className: "px-6 pb-6", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4256
+ Select,
4257
+ {
4258
+ label: "基准语言",
4259
+ labelPlacement: "outside",
4260
+ placeholder: "请选择网站基准的语言",
4261
+ className: "max-w-sm",
4262
+ selectedKeys: [((_a = website == null ? void 0 : website.baseLang) == null ? void 0 : _a.id) || ""],
4263
+ isDisabled: (isMutating || isCreating) && isChanginBaseLangRef.current,
4264
+ isLoading: (isMutating || isCreating) && isChanginBaseLangRef.current,
4265
+ renderValue: (langValues) => {
4266
+ return (langValues == null ? void 0 : langValues.map((langValue) => {
4267
+ var _a2, _b2;
4268
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
4269
+ "div",
4270
+ {
4271
+ className: "flex items-center gap-2",
4272
+ children: [
4273
+ (_a2 = langValue == null ? void 0 : langValue.props) == null ? void 0 : _a2.startContent,
4274
+ (_b2 = langValue == null ? void 0 : langValue.props) == null ? void 0 : _b2.children
4275
+ ]
4276
+ },
4277
+ langValue == null ? void 0 : langValue.key
4278
+ );
4279
+ })) || [];
4280
+ },
4281
+ onSelectionChange: handleBaseLangChange,
4282
+ children: ((_b = website == null ? void 0 : website.langs) == null ? void 0 : _b.map((lang) => /* @__PURE__ */ jsxRuntimeExports.jsx(
4283
+ SelectItem,
4406
4284
  {
4407
- name: ThemeConfigFields.websiteTitle,
4408
- label: "网站标题",
4409
- labelPlacement: "outside",
4410
- placeholder: "请输入网站标题"
4411
- }
4412
- ),
4413
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2 mt-2", children: [
4414
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-default-600", children: "联系人头像" }),
4285
+ startContent: lang.icon ? /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { icon: lang.icon, className: "text-xl" }) : null,
4286
+ textValue: lang.abbr,
4287
+ children: lang.cnName || lang.enName
4288
+ },
4289
+ lang.id
4290
+ ))) || []
4291
+ }
4292
+ ) })
4293
+ ] }),
4294
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { className: "bg-default-50", children: [
4295
+ /* @__PURE__ */ jsxRuntimeExports.jsx(CardHeader, { className: "flex gap-3 px-6 pt-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col flex-grow", children: [
4296
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-lg font-semibold", children: "已启用的语言" }),
4297
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-small text-default-500", children: "管理网站支持的语言" })
4298
+ ] }) }),
4299
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(CardBody, { className: "px-6 pb-6", children: [
4300
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid gap-4 md:grid-cols-2 ", children: [
4301
+ (_c = website == null ? void 0 : website.langs) == null ? void 0 : _c.map((lang) => {
4302
+ var _a2;
4303
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
4304
+ LangCard,
4305
+ {
4306
+ lang,
4307
+ isSelected: currentLang === lang.id,
4308
+ isBaseLang: ((_a2 = website == null ? void 0 : website.baseLang) == null ? void 0 : _a2.id) === lang.id,
4309
+ onSelect: handleLangSelect
4310
+ },
4311
+ lang.id
4312
+ );
4313
+ }),
4314
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Dropdown, { placement: "bottom-end", children: [
4315
+ /* @__PURE__ */ jsxRuntimeExports.jsx(DropdownTrigger, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4316
+ Button$1,
4317
+ {
4318
+ variant: "flat",
4319
+ className: "h-[88px] bg-default-100 hover:bg-default-200 w-full",
4320
+ startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(AddIcon, { className: "size-6 shrink-0" }),
4321
+ isLoading: allLangsLoading || isMutating && !isChanginBaseLangRef.current,
4322
+ children: "添加语言"
4323
+ }
4324
+ ) }),
4415
4325
  /* @__PURE__ */ jsxRuntimeExports.jsx(
4416
- MediaSingleSelectField,
4326
+ DropdownMenu,
4417
4327
  {
4418
- name: ThemeConfigAssciations.contactAvatar,
4419
- websiteId,
4420
- mediaTypes: [MediaType.image],
4421
- width: 120
4328
+ "aria-label": "全部语言列表",
4329
+ items: leftLangs,
4330
+ className: "max-h-[300px] overflow-y-auto",
4331
+ disallowEmptySelection: true,
4332
+ selectionMode: "single",
4333
+ onAction: handleAddLanguage,
4334
+ children: (item) => /* @__PURE__ */ jsxRuntimeExports.jsx(
4335
+ DropdownItem,
4336
+ {
4337
+ className: "gap-2",
4338
+ startContent: item.icon ? /* @__PURE__ */ jsxRuntimeExports.jsx(
4339
+ Icon,
4340
+ {
4341
+ icon: item.icon,
4342
+ className: "text-xl shrink-0"
4343
+ }
4344
+ ) : null,
4345
+ textValue: item.cnName || item.enName,
4346
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: item.cnName || item.enName })
4347
+ },
4348
+ item.id
4349
+ )
4422
4350
  }
4423
4351
  )
4424
- ] }),
4425
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
4426
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4427
- InputField,
4352
+ ] })
4353
+ ] }),
4354
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-6 flex items-center justify-between", children: [
4355
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-default-500", children: taskState == null ? void 0 : taskState.infoMessage }),
4356
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-end gap-2", children: [
4357
+ isRunning && /* @__PURE__ */ jsxRuntimeExports.jsx(
4358
+ Button$1,
4428
4359
  {
4429
- name: ThemeConfigFields.contact,
4430
- label: "联系人",
4431
- labelPlacement: "outside",
4432
- placeholder: "请输入联系人姓名"
4360
+ variant: "flat",
4361
+ startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(TaskStopIcon, { className: "size-5" }),
4362
+ onPress: handleStop,
4363
+ children: "停止"
4433
4364
  }
4434
4365
  ),
4435
4366
  /* @__PURE__ */ jsxRuntimeExports.jsx(
4436
- InputField,
4367
+ Button$1,
4437
4368
  {
4438
- name: ThemeConfigFields.tel,
4439
- label: "电话",
4440
- labelPlacement: "outside",
4441
- placeholder: "请输入联系电话"
4369
+ color: "primary",
4370
+ startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(AiStarIcon, { className: "size-5" }),
4371
+ isDisabled: currentLang === ((_d = website == null ? void 0 : website.baseLang) == null ? void 0 : _d.id),
4372
+ isLoading: isRunning,
4373
+ onPress: handleTranslate,
4374
+ children: "翻译 & 重置"
4442
4375
  }
4443
4376
  )
4444
4377
  ] })
4445
- ] }),
4446
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
4447
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4448
- InputField,
4449
- {
4450
- name: ThemeConfigFields.email,
4451
- label: "邮箱",
4452
- labelPlacement: "outside",
4453
- placeholder: "请输入联系邮箱"
4454
- }
4455
- ),
4456
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4457
- InputField,
4458
- {
4459
- name: ThemeConfigFields.mobile,
4460
- label: "手机",
4461
- labelPlacement: "outside",
4462
- placeholder: "请输入手机号码"
4463
- }
4464
- ),
4465
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4466
- InputField,
4467
- {
4468
- name: ThemeConfigFields.fax,
4469
- label: "传真",
4470
- labelPlacement: "outside",
4471
- placeholder: "请输入传真号码"
4472
- }
4473
- )
4474
- ] }),
4475
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4476
- TextareaField,
4378
+ ] })
4379
+ ] })
4380
+ ] }),
4381
+ !!((_e = website == null ? void 0 : website.langs) == null ? void 0 : _e.length) && ((_f = website == null ? void 0 : website.langs) == null ? void 0 : _f.length) > 1 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { className: "bg-default-50", children: [
4382
+ /* @__PURE__ */ jsxRuntimeExports.jsx(CardHeader, { className: "flex gap-3 px-6 pt-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col flex-grow", children: [
4383
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-lg font-semibold", children: "链接方式" }),
4384
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-small text-default-500", children: "选择多语言网站的访问方式" })
4385
+ ] }) }),
4386
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(CardBody, { className: "px-6 pb-6", children: [
4387
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid gap-4 md:grid-cols-2", children: linkTypes.map((type) => /* @__PURE__ */ jsxRuntimeExports.jsx(
4388
+ Card,
4477
4389
  {
4478
- name: ThemeConfigFields.address,
4479
- label: "地址",
4480
- labelPlacement: "outside",
4481
- placeholder: "请输入详细地址"
4482
- }
4483
- ) })
4484
- ] }),
4485
- /* @__PURE__ */ jsxRuntimeExports.jsx(Divider, { className: "mt-4" }),
4486
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end mt-4", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SubmitButton, { size: "sm", variant: "solid", color: "primary", children: "保存" }) })
4487
- ]
4488
- }
4489
- ) });
4490
- }
4491
- function EmialTemplatesPanel(props) {
4492
- const { onSuccess } = props;
4493
- const theme = useStudioTheme();
4494
- const { data: themeConfig2 } = useOneThemeConfig(newThemeConfigOptions(theme));
4495
- const [save, { isMutating }] = useUpsertOneThemeConfig({
4496
- onSuccess
4497
- });
4498
- const handleSave = useCallback(
4499
- (value) => {
4500
- if (!value)
4501
- return;
4502
- save(themeConfigToInput(value));
4503
- },
4504
- [save]
4505
- );
4506
- return /* @__PURE__ */ jsxRuntimeExports.jsx(ModalBody, { className: "flex-1 min-h-0 overflow-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
4507
- EntityForm,
4508
- {
4509
- entityName: ThemeConfigEntityName,
4510
- initialValue: themeConfig2 || {
4511
- [ThemeConfigAssciations.theme]: {
4512
- id: theme == null ? void 0 : theme.id
4513
- }
4514
- },
4515
- globalValidationErrorMessage: "部分输入项有错误,请检查",
4516
- isMutating,
4517
- onSubmit: handleSave,
4518
- children: [
4519
- /* @__PURE__ */ jsxRuntimeExports.jsxs(ObjectField, { name: ThemeConfigFields.emailTemplates, children: [
4520
- /* @__PURE__ */ jsxRuntimeExports.jsx(ObjectField, { name: "customerEmail", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { className: "mt-2", children: [
4521
- /* @__PURE__ */ jsxRuntimeExports.jsxs(CardHeader, { className: "flex gap-2", children: [
4522
- /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { children: "客户通知邮件" }),
4523
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-default-500", children: "变量:$name" })
4524
- ] }),
4525
- /* @__PURE__ */ jsxRuntimeExports.jsx(Divider, {}),
4526
- /* @__PURE__ */ jsxRuntimeExports.jsxs(CardBody, { className: "gap-4", children: [
4527
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4528
- InputField,
4529
- {
4530
- name: "subject",
4531
- label: "标题",
4532
- labelPlacement: "outside",
4533
- placeholder: "请输入标题"
4534
- }
4535
- ),
4536
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4537
- TextareaField,
4538
- {
4539
- name: "content",
4540
- label: "内容",
4541
- minRows: 5,
4542
- labelPlacement: "outside",
4543
- placeholder: "请输入内容"
4544
- }
4545
- )
4546
- ] })
4547
- ] }) }),
4548
- /* @__PURE__ */ jsxRuntimeExports.jsx(ObjectField, { name: "employeeEmail", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { className: "mt-4", children: [
4549
- /* @__PURE__ */ jsxRuntimeExports.jsxs(CardHeader, { className: "flex gap-2", children: [
4550
- /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { children: "业务员通知邮件" }),
4551
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-default-500", children: "变量:$content" })
4552
- ] }),
4553
- /* @__PURE__ */ jsxRuntimeExports.jsx(Divider, {}),
4554
- /* @__PURE__ */ jsxRuntimeExports.jsxs(CardBody, { className: "gap-4", children: [
4555
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4556
- InputField,
4557
- {
4558
- name: "subject",
4559
- label: "标题",
4560
- labelPlacement: "outside",
4561
- placeholder: "请输入标题"
4562
- }
4563
- ),
4564
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4565
- TextareaField,
4566
- {
4567
- name: "content",
4568
- label: "内容",
4569
- minRows: 5,
4570
- labelPlacement: "outside",
4571
- placeholder: "请输入内容"
4572
- }
4573
- )
4574
- ] })
4575
- ] }) })
4576
- ] }),
4577
- /* @__PURE__ */ jsxRuntimeExports.jsx(Divider, { className: "mt-4" }),
4578
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end mt-4", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SubmitButton, { size: "sm", variant: "solid", color: "primary", children: "保存" }) })
4579
- ]
4580
- }
4581
- ) });
4390
+ shadow: "sm",
4391
+ className: `bg-background cursor-pointer transition-colors ${linkType === type.key ? "border-2 border-primary" : "hover:bg-default-100"}`,
4392
+ isPressable: type.key !== "path",
4393
+ as: "div",
4394
+ isDisabled: type.key === "path",
4395
+ onPress: () => type.key !== "path" && setLinkType(type.key),
4396
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(CardBody, { className: "p-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
4397
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center size-10 rounded-lg bg-default-100", children: type.icon }),
4398
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1", children: [
4399
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "font-medium", children: type.label }),
4400
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-default-500", children: type.description })
4401
+ ] }),
4402
+ linkType === type.key && /* @__PURE__ */ jsxRuntimeExports.jsx(CheckCircleIcon, { className: "text-primary size-5" })
4403
+ ] }) })
4404
+ },
4405
+ type.key
4406
+ )) }),
4407
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-4", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-default-400", children: linkType === "subdomain" ? /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: "使用二级域名方式需要正确配置DNS解析,将所有二级域名指向网站服务器。 同时需要配置服务器支持泛域名解析。" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: "使用子网址方式无需额外的DNS配置,但URL会相对较长。 建议在无法使用二级域名时选择此方式。" }) }) })
4408
+ ] })
4409
+ ] })
4410
+ ] }) }),
4411
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4412
+ ConfirmDialog,
4413
+ {
4414
+ open: confirmOpen,
4415
+ onClose: handleCloseConfirm,
4416
+ onConfirm: handleConfirm,
4417
+ confirm: "翻译会重置并覆盖当前网站内容,不可撤销,您确定要翻译吗?"
4418
+ }
4419
+ )
4420
+ ] });
4582
4421
  }
4583
- function LangCard(props) {
4584
- var _a;
4585
- const { isSelected, isBaseLang, lang, onSelect } = props;
4586
- const website = useWebsite();
4587
- const [removing, setRemoving] = useState(false);
4588
- const [upsertWebsite, { isMutating }] = useUpsertOneWebsite();
4589
- const [currentLang, setCurrentLang] = useRecoilState(currentLangState);
4590
- const setSelectedContent = useSetRecoilState(selectedContentState);
4591
- const queryTheme = useLazyQueryOneEntity();
4592
- const [removeTheme] = useDeleteThemeById();
4593
- const handleDelete = useCallback(async () => {
4594
- var _a2, _b, _c;
4595
- try {
4596
- setRemoving(true);
4597
- if (((_a2 = website == null ? void 0 : website.baseLang) == null ? void 0 : _a2.id) === lang.id) {
4598
- return;
4422
+ const inputClassNames$1 = {
4423
+ label: "w-16 flex items-center ps-0 pe-0 shrink-0 justify-end pr-2 text-default-500",
4424
+ base: "flex items-center px-0",
4425
+ wrapper: "flex-1",
4426
+ mainWrapper: "flex-1 pr-4"
4427
+ };
4428
+ function ExtendsTable(props) {
4429
+ const { fields: fields2, onChange } = props;
4430
+ const handleAddField = useCallback(() => {
4431
+ onChange == null ? void 0 : onChange([...fields2 || [], {
4432
+ name: "newField",
4433
+ title: "新建字段",
4434
+ type: ExtendFieldType.String,
4435
+ component: ComponentType.Input
4436
+ }]);
4437
+ }, [fields2, onChange]);
4438
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4439
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4440
+ Accordion,
4441
+ {
4442
+ isCompact: true,
4443
+ children: (fields2 == null ? void 0 : fields2.map((field, index) => {
4444
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
4445
+ AccordionItem,
4446
+ {
4447
+ classNames: {
4448
+ title: "text-sm"
4449
+ },
4450
+ title: `#${index + 1} ${field.title || field.name}`,
4451
+ children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2 px-3", children: [
4452
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4453
+ Input$1,
4454
+ {
4455
+ variant: "flat",
4456
+ value: field.name,
4457
+ size: "sm",
4458
+ label: "名称",
4459
+ labelPlacement: "outside-left",
4460
+ classNames: inputClassNames$1,
4461
+ onChange: (e) => {
4462
+ const newName = e.target.value;
4463
+ onChange == null ? void 0 : onChange(fields2.map((field2, i2) => {
4464
+ if (i2 === index) {
4465
+ return {
4466
+ ...field2,
4467
+ name: newName
4468
+ };
4469
+ }
4470
+ return field2;
4471
+ }));
4472
+ }
4473
+ }
4474
+ ),
4475
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4476
+ Input$1,
4477
+ {
4478
+ label: "标题",
4479
+ size: "sm",
4480
+ variant: "flat",
4481
+ value: field.title,
4482
+ labelPlacement: "outside-left",
4483
+ classNames: inputClassNames$1,
4484
+ onChange: (e) => {
4485
+ const newTitle = e.target.value;
4486
+ onChange == null ? void 0 : onChange(fields2.map((field2, i2) => {
4487
+ if (i2 === index) {
4488
+ return {
4489
+ ...field2,
4490
+ title: newTitle
4491
+ };
4492
+ }
4493
+ return field2;
4494
+ }));
4495
+ }
4496
+ }
4497
+ ),
4498
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
4499
+ Select,
4500
+ {
4501
+ label: "类型",
4502
+ size: "sm",
4503
+ variant: "flat",
4504
+ selectedKeys: field.type ? [field.type] : [],
4505
+ labelPlacement: "outside-left",
4506
+ classNames: inputClassNames$1,
4507
+ onChange: (e) => {
4508
+ onChange == null ? void 0 : onChange(fields2.map((field2, i2) => {
4509
+ if (i2 === index) {
4510
+ return {
4511
+ ...field2,
4512
+ type: e.target.value || void 0
4513
+ };
4514
+ }
4515
+ return field2;
4516
+ }));
4517
+ },
4518
+ children: [
4519
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "文本" }, ExtendFieldType.String),
4520
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "数字" }, ExtendFieldType.Number),
4521
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "布尔" }, ExtendFieldType.Boolean),
4522
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "JSON" }, ExtendFieldType.Json),
4523
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "日期" }, ExtendFieldType.Date)
4524
+ ]
4525
+ }
4526
+ ),
4527
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
4528
+ Select,
4529
+ {
4530
+ label: "编辑组件",
4531
+ size: "sm",
4532
+ variant: "flat",
4533
+ selectedKeys: field.component ? [field.component] : [],
4534
+ labelPlacement: "outside-left",
4535
+ classNames: inputClassNames$1,
4536
+ onChange: (e) => {
4537
+ onChange == null ? void 0 : onChange(fields2.map((field2, i2) => {
4538
+ if (i2 === index) {
4539
+ return {
4540
+ ...field2,
4541
+ component: e.target.value || void 0
4542
+ };
4543
+ }
4544
+ return field2;
4545
+ }));
4546
+ },
4547
+ endContent: /* @__PURE__ */ jsxRuntimeExports.jsx(
4548
+ Button$1,
4549
+ {
4550
+ as: "div",
4551
+ size: "sm",
4552
+ variant: "light",
4553
+ isIconOnly: true,
4554
+ className: "flex items-center justify-center",
4555
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(SettingsIcon, { className: "size-4" })
4556
+ }
4557
+ ),
4558
+ children: [
4559
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "单行输入框" }, ComponentType.Input),
4560
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "数字入框" }, ComponentType.NumberInput),
4561
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "多行输入框" }, ComponentType.Textarea),
4562
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "开关" }, ComponentType.Switch),
4563
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "图片选择" }, ComponentType.ImageSelect),
4564
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "链接目标" }, ComponentType.LinkTarget)
4565
+ ]
4566
+ }
4567
+ ),
4568
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4569
+ Button$1,
4570
+ {
4571
+ size: "sm",
4572
+ variant: "light",
4573
+ color: "danger",
4574
+ onPress: () => {
4575
+ onChange == null ? void 0 : onChange(fields2.filter((_2, i2) => i2 !== index));
4576
+ },
4577
+ children: "删除字段"
4578
+ }
4579
+ )
4580
+ ] })
4581
+ },
4582
+ index
4583
+ );
4584
+ })) || []
4599
4585
  }
4600
- await upsertWebsite(
4601
- websiteToInput({
4602
- id: website == null ? void 0 : website.id,
4603
- langs: (_b = website == null ? void 0 : website.langs) == null ? void 0 : _b.filter((l2) => l2.id !== lang.id)
4604
- })
4605
- );
4606
- if (currentLang === lang.id) {
4607
- setCurrentLang((_c = website == null ? void 0 : website.baseLang) == null ? void 0 : _c.id);
4608
- setSelectedContent(void 0);
4586
+ ),
4587
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4588
+ Button$1,
4589
+ {
4590
+ variant: "flat",
4591
+ size: "sm",
4592
+ className: "mt-2",
4593
+ startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(AddIcon, { className: "size-5" }),
4594
+ onPress: handleAddField,
4595
+ children: "添加"
4609
4596
  }
4610
- const langTheme = await queryTheme(
4611
- new ThemeQueryOptions([ThemeFields.id], {
4612
- where: {
4613
- website: {
4614
- id: {
4615
- _eq: website == null ? void 0 : website.id
4616
- }
4617
- },
4618
- lang: {
4619
- id: {
4620
- _eq: lang.id
4621
- }
4622
- }
4597
+ )
4598
+ ] });
4599
+ }
4600
+ function PostPanel(props) {
4601
+ const { settings, onChange } = props;
4602
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
4603
+ "div",
4604
+ {
4605
+ className: "flex flex-col gap-4 overflow-x-hidden py-2",
4606
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col gap-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4607
+ ExtendsTable,
4608
+ {
4609
+ fields: settings == null ? void 0 : settings.fields,
4610
+ onChange: (fields2) => {
4611
+ onChange == null ? void 0 : onChange({
4612
+ ...settings,
4613
+ fields: fields2
4614
+ });
4623
4615
  }
4624
- }).toGqlOptions()
4625
- );
4626
- if (langTheme.id) {
4627
- removeTheme(langTheme.id);
4628
- }
4629
- } finally {
4630
- setRemoving(false);
4616
+ }
4617
+ ) })
4631
4618
  }
4632
- }, [
4633
- currentLang,
4634
- lang.id,
4635
- queryTheme,
4636
- removeTheme,
4637
- setCurrentLang,
4638
- setSelectedContent,
4639
- upsertWebsite,
4640
- (_a = website == null ? void 0 : website.baseLang) == null ? void 0 : _a.id,
4641
- website == null ? void 0 : website.id,
4642
- website == null ? void 0 : website.langs
4643
- ]);
4619
+ );
4620
+ }
4621
+ function ProductPanel(props) {
4622
+ const { settings, onChange } = props;
4644
4623
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
4645
- Card,
4624
+ "div",
4646
4625
  {
4647
- shadow: "sm",
4648
- className: "bg-background cursor-pointer transition-colors group relative",
4649
- classNames: {
4650
- base: isSelected ? "outline-2 outline-primary" : "hover:bg-default-100"
4651
- },
4652
- isPressable: !removing,
4653
- as: "div",
4654
- isDisabled: removing,
4655
- onPress: () => onSelect(lang.id),
4656
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(CardBody, { className: "p-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
4657
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
4658
- lang.icon && /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { icon: lang.icon, className: "text-2xl shrink-0" }),
4659
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
4660
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
4661
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "font-medium truncate", children: lang.cnName }),
4662
- isBaseLang && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "shrink-0 inline-flex items-center px-1.5 py-0.5 rounded-full bg-success/10 border border-primary/20", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-primary font-medium leading-none", children: "基准语言" }) })
4663
- ] }),
4664
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-default-500 truncate", children: lang.abbr })
4665
- ] })
4666
- ] }),
4667
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
4668
- isSelected && /* @__PURE__ */ jsxRuntimeExports.jsx(CheckCircleIcon, { className: "text-primary size-5 shrink-0" }),
4669
- !isBaseLang && !isMutating && /* @__PURE__ */ jsxRuntimeExports.jsx(
4670
- Button$1,
4671
- {
4672
- isIconOnly: true,
4673
- size: "sm",
4674
- variant: "light",
4675
- className: "absolute top-1 right-1 w-6 h-6 min-w-6 min-h-6 rounded-full text-default-400 hover:text-default-500 group-hover:opacity-100 opacity-0 transition-opacity duration-300",
4676
- onPress: handleDelete,
4677
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(CloseIcon, { className: "size-4" })
4678
- }
4679
- ),
4680
- isMutating && /* @__PURE__ */ jsxRuntimeExports.jsx(
4681
- CircularProgress,
4682
- {
4683
- "aria-label": "Loading...",
4684
- size: "sm",
4685
- className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2"
4686
- }
4687
- )
4688
- ] })
4689
- ] }) })
4626
+ className: "flex flex-col gap-4 overflow-x-hidden py-2",
4627
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col gap-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4628
+ ExtendsTable,
4629
+ {
4630
+ fields: settings == null ? void 0 : settings.fields,
4631
+ onChange: (fields2) => {
4632
+ onChange == null ? void 0 : onChange({
4633
+ ...settings,
4634
+ fields: fields2
4635
+ });
4636
+ }
4637
+ }
4638
+ ) })
4690
4639
  }
4691
4640
  );
4692
4641
  }
4693
- const TRANSLATE_THEME_KEY = "translate-theme";
4694
- function useTranslateThemeTask() {
4695
- const theme = useStudioTheme();
4696
- const lang = useCurrentLang();
4697
- const baseThemeId = useBaseLangThemeId();
4698
- const appKey = (theme == null ? void 0 : theme.id) || "";
4699
- const taskState = useInprogressTaskByKey(TRANSLATE_THEME_KEY, appKey);
4700
- const setTask = useUpdateTask(appKey);
4701
- const entifyClient = useCreateEntityClient();
4702
- const task = taskState && taskState.status !== "done" ? taskPool[taskState.taskId] : void 0;
4703
- const aiUrl = useAiUrl();
4704
- const handleTaskChange = useCallback(
4705
- (data) => {
4706
- setTask(data);
4707
- },
4708
- [setTask]
4709
- );
4710
- const translateAndReset = useCallback(() => {
4711
- if (!(theme == null ? void 0 : theme.id)) {
4712
- console.error("没设置Theme");
4713
- return;
4714
- }
4715
- if (!entifyClient) {
4716
- console.error("entifyClient 创建失败");
4717
- return;
4718
- }
4719
- if (!aiUrl) {
4720
- console.error("没设置aiUrl");
4721
- return;
4722
- }
4723
- if (!baseThemeId) {
4724
- console.error("没设置baseThemeId");
4725
- return;
4726
- }
4727
- const task2 = new TranslateThemeTask({
4728
- key: TRANSLATE_THEME_KEY,
4729
- entifyClient,
4730
- baseThemeId,
4731
- themeId: theme == null ? void 0 : theme.id,
4732
- lang,
4733
- aiUrl
4642
+ function ExtendsPanel() {
4643
+ const [themeSettings, setThemeSettings] = useState();
4644
+ const initialSettings = useThemeSettings();
4645
+ const webTheme = useStudioTheme();
4646
+ const [save, { isMutating }] = useUpsertOneTheme();
4647
+ const changed = useMemo(() => {
4648
+ return JSON.stringify(themeSettings || {}) !== JSON.stringify(initialSettings || {});
4649
+ }, [themeSettings, initialSettings]);
4650
+ const handleReset = useCallback(() => {
4651
+ setThemeSettings(initialSettings);
4652
+ }, [initialSettings]);
4653
+ const handleSave = useCallback(() => {
4654
+ save({
4655
+ id: webTheme == null ? void 0 : webTheme.id,
4656
+ settings: themeSettings || void 0
4734
4657
  });
4735
- taskPool[task2.id] = task2;
4736
- task2.onDataChange(handleTaskChange);
4737
- task2.start();
4738
- }, [aiUrl, baseThemeId, entifyClient, handleTaskChange, lang, theme == null ? void 0 : theme.id]);
4739
- return { taskState, translateAndReset, task };
4740
- }
4741
- const linkTypes = [
4742
- {
4743
- key: "path",
4744
- label: "子网址",
4745
- description: "例如:example.com/en",
4746
- icon: /* @__PURE__ */ jsxRuntimeExports.jsx(
4747
- "svg",
4658
+ }, [save, themeSettings, webTheme == null ? void 0 : webTheme.id]);
4659
+ useEffect(() => {
4660
+ setThemeSettings(initialSettings);
4661
+ }, [initialSettings]);
4662
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4663
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ModalBody, { className: "flex-1 min-h-0 overflow-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
4664
+ Tabs,
4748
4665
  {
4749
- xmlns: "http://www.w3.org/2000/svg",
4750
- className: "size-5 text-default-500",
4751
- viewBox: "0 0 24 24",
4752
- children: /* @__PURE__ */ jsxRuntimeExports.jsxs("g", { fill: "none", children: [
4753
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4754
- "path",
4755
- {
4756
- stroke: "currentColor",
4757
- strokeWidth: 1.5,
4758
- d: "M2 12c0-4.714 0-7.071 1.464-8.536C4.93 2 7.286 2 12 2s7.071 0 8.535 1.464C22 4.93 22 7.286 22 12s0 7.071-1.465 8.535C19.072 22 16.714 22 12 22s-7.071 0-8.536-1.465C2 19.072 2 16.714 2 12Z"
4759
- }
4760
- ),
4761
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4762
- "path",
4666
+ "aria-label": "extends",
4667
+ className: "mt-2",
4668
+ size: "sm",
4669
+ children: [
4670
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Tab, { title: "产品", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4671
+ ProductPanel,
4763
4672
  {
4764
- fill: "currentColor",
4765
- d: "M11.25 18a.75.75 0 0 0 1.5 0zM18 8l.53.53a.75.75 0 0 0 0-1.06zm-.97-2.03a.75.75 0 1 0-1.06 1.06zm-1.06 3a.75.75 0 1 0 1.06 1.06zM12.75 18v-6h-1.5v6zM16 8.75h2v-1.5h-2zm2.53-1.28l-1.5-1.5l-1.06 1.06l1.5 1.5zm-1.06 0l-1.5 1.5l1.06 1.06l1.5-1.5zM12.75 12A3.25 3.25 0 0 1 16 8.75v-1.5A4.75 4.75 0 0 0 11.25 12z"
4673
+ settings: themeSettings == null ? void 0 : themeSettings.product,
4674
+ onChange: (settings) => {
4675
+ setThemeSettings({
4676
+ ...themeSettings,
4677
+ product: settings
4678
+ });
4679
+ }
4766
4680
  }
4767
- ),
4768
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4769
- "path",
4681
+ ) }, "product"),
4682
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Tab, { title: "文章", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4683
+ PostPanel,
4770
4684
  {
4771
- fill: "currentColor",
4772
- d: "M11.25 18a.75.75 0 0 0 1.5 0zM6 8l-.53-.53a.75.75 0 0 0 0 1.06zm2.03-.97a.75.75 0 0 0-1.06-1.06zm-1.06 3a.75.75 0 1 0 1.06-1.06zM12.75 18v-6h-1.5v6zM8 7.25H6v1.5h2zM6.53 8.53l1.5-1.5l-1.06-1.06l-1.5 1.5zm-1.06 0l1.5 1.5l1.06-1.06l-1.5-1.5zM12.75 12A4.75 4.75 0 0 0 8 7.25v1.5A3.25 3.25 0 0 1 11.25 12z"
4685
+ settings: themeSettings == null ? void 0 : themeSettings.post,
4686
+ onChange: (settings) => {
4687
+ setThemeSettings({
4688
+ ...themeSettings,
4689
+ post: settings
4690
+ });
4691
+ }
4773
4692
  }
4774
- )
4775
- ] })
4776
- }
4777
- )
4778
- },
4779
- {
4780
- key: "subdomain",
4781
- label: "二级域名",
4782
- description: "例如:en.example.com",
4783
- icon: /* @__PURE__ */ jsxRuntimeExports.jsx(
4784
- "svg",
4785
- {
4786
- xmlns: "http://www.w3.org/2000/svg",
4787
- className: "size-5 text-default-500",
4788
- viewBox: "0 0 24 24",
4789
- children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
4790
- "g",
4791
- {
4792
- fill: "none",
4793
- stroke: "currentColor",
4794
- strokeLinecap: "round",
4795
- strokeWidth: 1.5,
4796
- children: [
4797
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M14 12a6 6 0 1 1-6-6" }),
4798
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M10 12a6 6 0 1 1 6 6" })
4799
- ]
4800
- }
4801
- )
4802
- }
4803
- )
4804
- }
4805
- ];
4806
- function MultiLangPanel() {
4807
- var _a, _b, _c, _d, _e, _f;
4808
- const [linkType, setLinkType] = useState("subdomain");
4809
- const [confirmOpen, setConfirmOpen] = useState(false);
4810
- const [currentLang, setCurrentLang] = useRecoilState(currentLangState);
4811
- const [selectedContent, setSelectedContent] = useRecoilState(selectedContentState);
4812
- const website = useWebsite();
4813
- const isChanginBaseLangRef = useRef(false);
4814
- const [upsertTheme, { isMutating: isCreating }] = useUpsertOneTheme();
4815
- const { taskState, task, translateAndReset } = useTranslateThemeTask();
4816
- useEffect(() => {
4817
- var _a2;
4818
- if (website && !currentLang) {
4819
- setCurrentLang((_a2 = website.baseLang) == null ? void 0 : _a2.id);
4820
- }
4821
- }, [currentLang, setCurrentLang, website]);
4822
- const { data: allLangs, isLoading: allLangsLoading } = useLangList(
4823
- new LangQueryOptions([
4824
- LangFields.id,
4825
- LangFields.abbr,
4826
- LangFields.enName,
4827
- LangFields.cnName,
4828
- LangFields.localName,
4829
- LangFields.description,
4830
- LangFields.circleIcon,
4831
- LangFields.icon
4832
- ])
4833
- );
4834
- const [upsertWebsite, { isMutating }] = useUpsertOneWebsite();
4835
- useEffect(() => {
4836
- if (!isMutating) {
4837
- isChanginBaseLangRef.current = false;
4838
- }
4839
- }, [isMutating]);
4840
- const handleBaseLangChange = useCallback(
4841
- (selection) => {
4842
- isChanginBaseLangRef.current = true;
4843
- upsertWebsite(
4844
- websiteToInput({
4845
- id: website == null ? void 0 : website.id,
4846
- [WebsiteAssciations.baseLang]: { id: selection.currentKey }
4847
- })
4848
- );
4849
- },
4850
- [upsertWebsite, website == null ? void 0 : website.id]
4851
- );
4852
- const handleLangSelect = useCallback(
4853
- (langId) => {
4854
- setCurrentLang(langId);
4855
- if ((selectedContent == null ? void 0 : selectedContent.id) && langId !== currentLang) {
4856
- setSelectedContent(void 0);
4693
+ ) }, "post")
4694
+ ]
4857
4695
  }
4858
- },
4859
- [selectedContent == null ? void 0 : selectedContent.id, setCurrentLang, setSelectedContent, currentLang]
4860
- );
4861
- const leftLangs = useMemo(() => {
4862
- var _a2;
4863
- return (_a2 = allLangs == null ? void 0 : allLangs.items) == null ? void 0 : _a2.filter(
4864
- (lang) => {
4865
- var _a3;
4866
- return !((_a3 = website == null ? void 0 : website.langs) == null ? void 0 : _a3.some((l2) => l2.id === lang.id));
4696
+ ) }),
4697
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(ModalFooter, { children: [
4698
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4699
+ Button$1,
4700
+ {
4701
+ size: "sm",
4702
+ isDisabled: !changed,
4703
+ onPress: handleReset,
4704
+ children: "重置"
4705
+ }
4706
+ ),
4707
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4708
+ Button$1,
4709
+ {
4710
+ size: "sm",
4711
+ isDisabled: !changed,
4712
+ isLoading: isMutating,
4713
+ color: "primary",
4714
+ onPress: handleSave,
4715
+ children: "保存"
4716
+ }
4717
+ )
4718
+ ] })
4719
+ ] });
4720
+ }
4721
+ function newThemeConfigOptions(theme) {
4722
+ return new ThemeConfigQueryOptions(
4723
+ [
4724
+ ThemeConfigFields.id,
4725
+ ThemeConfigFields.emailTemplates,
4726
+ ThemeConfigFields.address,
4727
+ ThemeConfigFields.contact,
4728
+ ThemeConfigFields.email,
4729
+ ThemeConfigFields.tel,
4730
+ ThemeConfigFields.fax,
4731
+ ThemeConfigFields.mobile,
4732
+ ThemeConfigFields.wechat,
4733
+ ThemeConfigFields.websiteTitle,
4734
+ ThemeConfigFields.domain
4735
+ ],
4736
+ {
4737
+ where: {
4738
+ [ThemeConfigAssciations.theme]: {
4739
+ id: {
4740
+ _eq: theme == null ? void 0 : theme.id
4741
+ }
4742
+ }
4867
4743
  }
4868
- );
4869
- }, [allLangs, website]);
4870
- const handleAddLanguage = useCallback(
4871
- async (langId) => {
4872
- var _a2;
4873
- await upsertWebsite(
4874
- websiteToInput({
4875
- id: website == null ? void 0 : website.id,
4876
- [WebsiteAssciations.langs]: [
4877
- ...((_a2 = website == null ? void 0 : website.langs) == null ? void 0 : _a2.map((lang) => ({
4878
- id: lang.id
4879
- }))) || [],
4880
- { id: langId }
4881
- ]
4882
- })
4883
- );
4884
- if ((website == null ? void 0 : website.id) && langId) {
4885
- console.log("create theme");
4886
- await upsertTheme({
4887
- name: (website.name || "") + (langId || "") + "主题",
4888
- lang: {
4889
- sync: { id: langId }
4890
- },
4891
- website: {
4892
- sync: { id: website.id }
4744
+ }
4745
+ ).contactAvatar(new MediaQueryOptions().file(["thumbnail", "url"])).setNoQuery(!(theme == null ? void 0 : theme.id));
4746
+ }
4747
+ function newThemeIconConfigOptions(theme) {
4748
+ return new ThemeConfigQueryOptions(
4749
+ [
4750
+ ThemeConfigFields.id,
4751
+ ThemeConfigFields.svgIcon,
4752
+ ThemeConfigFields.themeColor,
4753
+ ThemeConfigFields.pngIcon,
4754
+ ThemeConfigFields.appleTouchIcon,
4755
+ ThemeConfigFields.icoIcon
4756
+ ],
4757
+ {
4758
+ where: {
4759
+ [ThemeConfigAssciations.theme]: {
4760
+ id: {
4761
+ _eq: theme == null ? void 0 : theme.id
4893
4762
  }
4894
- });
4763
+ }
4895
4764
  }
4765
+ }
4766
+ ).setNoQuery(!(theme == null ? void 0 : theme.id));
4767
+ }
4768
+ function WebsiteInfoPanel(props) {
4769
+ const { onSuccess } = props;
4770
+ const theme = useStudioTheme();
4771
+ const website = useWebsite();
4772
+ const websiteId = website == null ? void 0 : website.id;
4773
+ const { data: themeConfig2 } = useOneThemeConfig(newThemeConfigOptions(theme));
4774
+ const [save, { isMutating }] = useUpsertOneThemeConfig({
4775
+ onSuccess
4776
+ });
4777
+ const handleSave = useCallback(
4778
+ (value) => {
4779
+ if (!value)
4780
+ return;
4781
+ save(themeConfigToInputCascade(value));
4896
4782
  },
4897
- [upsertTheme, upsertWebsite, website == null ? void 0 : website.id, website == null ? void 0 : website.langs, website == null ? void 0 : website.name]
4783
+ [save]
4898
4784
  );
4899
- const handleTranslate = useCallback(() => {
4900
- setConfirmOpen(true);
4901
- }, []);
4902
- const handleStop = useCallback(() => {
4903
- task == null ? void 0 : task.stop();
4904
- }, [task]);
4905
- const handleCloseConfirm = useCallback(() => {
4906
- setConfirmOpen(false);
4907
- }, []);
4908
- const handleConfirm = useCallback(() => {
4909
- translateAndReset();
4910
- }, [translateAndReset]);
4911
- const isRunning = (taskState == null ? void 0 : taskState.status) === "in-progress";
4912
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4913
- /* @__PURE__ */ jsxRuntimeExports.jsx(ModalBody, { className: "flex-1 p-4 min-h-0 overflow-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-4", children: [
4914
- /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { className: "bg-default-50", children: [
4915
- /* @__PURE__ */ jsxRuntimeExports.jsx(CardHeader, { className: "flex gap-3 px-6 pt-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col flex-grow", children: [
4916
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-lg font-semibold", children: "基准语言" }),
4917
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-small text-default-500", children: "从已启用的语言中选择网站的基准语言,作为翻译的原稿,默认为英文" })
4918
- ] }) }),
4919
- /* @__PURE__ */ jsxRuntimeExports.jsx(CardBody, { className: "px-6 pb-6", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4920
- Select,
4921
- {
4922
- label: "基准语言",
4923
- labelPlacement: "outside",
4924
- placeholder: "请选择网站基准的语言",
4925
- className: "max-w-sm",
4926
- selectedKeys: [((_a = website == null ? void 0 : website.baseLang) == null ? void 0 : _a.id) || ""],
4927
- isDisabled: (isMutating || isCreating) && isChanginBaseLangRef.current,
4928
- isLoading: (isMutating || isCreating) && isChanginBaseLangRef.current,
4929
- renderValue: (langValues) => {
4930
- return (langValues == null ? void 0 : langValues.map((langValue) => {
4931
- var _a2, _b2;
4932
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(
4933
- "div",
4934
- {
4935
- className: "flex items-center gap-2",
4936
- children: [
4937
- (_a2 = langValue == null ? void 0 : langValue.props) == null ? void 0 : _a2.startContent,
4938
- (_b2 = langValue == null ? void 0 : langValue.props) == null ? void 0 : _b2.children
4939
- ]
4940
- },
4941
- langValue == null ? void 0 : langValue.key
4942
- );
4943
- })) || [];
4944
- },
4945
- onSelectionChange: handleBaseLangChange,
4946
- children: ((_b = website == null ? void 0 : website.langs) == null ? void 0 : _b.map((lang) => /* @__PURE__ */ jsxRuntimeExports.jsx(
4947
- SelectItem,
4785
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(ModalBody, { className: "flex-1 min-h-0 flex flex-col p-0", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
4786
+ EntityForm,
4787
+ {
4788
+ className: "flex-1 min-h-0 flex flex-col ",
4789
+ entityName: ThemeConfigEntityName,
4790
+ initialValue: themeConfig2 || {
4791
+ [ThemeConfigAssciations.theme]: {
4792
+ id: theme == null ? void 0 : theme.id
4793
+ }
4794
+ },
4795
+ globalValidationErrorMessage: "部分输入项有错误,请检查",
4796
+ isMutating,
4797
+ onSubmit: handleSave,
4798
+ children: [
4799
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col gap-4 min-h-0 overflow-auto p-4 px-6", children: [
4800
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-4", children: [
4801
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4802
+ InputField,
4948
4803
  {
4949
- startContent: lang.icon ? /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { icon: lang.icon, className: "text-xl" }) : null,
4950
- textValue: lang.abbr,
4951
- children: lang.cnName || lang.enName
4952
- },
4953
- lang.id
4954
- ))) || []
4955
- }
4956
- ) })
4957
- ] }),
4958
- /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { className: "bg-default-50", children: [
4959
- /* @__PURE__ */ jsxRuntimeExports.jsx(CardHeader, { className: "flex gap-3 px-6 pt-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col flex-grow", children: [
4960
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-lg font-semibold", children: "已启用的语言" }),
4961
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-small text-default-500", children: "管理网站支持的语言" })
4962
- ] }) }),
4963
- /* @__PURE__ */ jsxRuntimeExports.jsxs(CardBody, { className: "px-6 pb-6", children: [
4964
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid gap-4 md:grid-cols-2 ", children: [
4965
- (_c = website == null ? void 0 : website.langs) == null ? void 0 : _c.map((lang) => {
4966
- var _a2;
4967
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
4968
- LangCard,
4804
+ name: ThemeConfigFields.domain,
4805
+ label: "网站域名",
4806
+ labelPlacement: "outside",
4807
+ placeholder: "请输入网站域名",
4808
+ description: "包含二级域名,不含http(s)://"
4809
+ }
4810
+ ),
4811
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4812
+ InputField,
4813
+ {
4814
+ name: ThemeConfigFields.websiteTitle,
4815
+ label: "网站标题",
4816
+ labelPlacement: "outside",
4817
+ placeholder: "请输入网站标题",
4818
+ description: "社媒分享用"
4819
+ }
4820
+ ),
4821
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2 mt-2", children: [
4822
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-default-600", children: "联系人头像" }),
4823
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4824
+ MediaSingleSelectField,
4969
4825
  {
4970
- lang,
4971
- isSelected: currentLang === lang.id,
4972
- isBaseLang: ((_a2 = website == null ? void 0 : website.baseLang) == null ? void 0 : _a2.id) === lang.id,
4973
- onSelect: handleLangSelect
4974
- },
4975
- lang.id
4976
- );
4977
- }),
4978
- /* @__PURE__ */ jsxRuntimeExports.jsxs(Dropdown, { placement: "bottom-end", children: [
4979
- /* @__PURE__ */ jsxRuntimeExports.jsx(DropdownTrigger, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4980
- Button$1,
4826
+ name: ThemeConfigAssciations.contactAvatar,
4827
+ websiteId,
4828
+ mediaTypes: [MediaType.image],
4829
+ width: 120
4830
+ }
4831
+ )
4832
+ ] }),
4833
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
4834
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4835
+ InputField,
4836
+ {
4837
+ name: ThemeConfigFields.contact,
4838
+ label: "联系人",
4839
+ labelPlacement: "outside",
4840
+ placeholder: "请输入联系人姓名"
4841
+ }
4842
+ ),
4843
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4844
+ InputField,
4845
+ {
4846
+ name: ThemeConfigFields.tel,
4847
+ label: "电话",
4848
+ labelPlacement: "outside",
4849
+ placeholder: "请输入联系电话"
4850
+ }
4851
+ )
4852
+ ] })
4853
+ ] }),
4854
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
4855
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4856
+ InputField,
4857
+ {
4858
+ name: ThemeConfigFields.email,
4859
+ label: "邮箱",
4860
+ labelPlacement: "outside",
4861
+ placeholder: "请输入联系邮箱"
4862
+ }
4863
+ ),
4864
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4865
+ InputField,
4866
+ {
4867
+ name: ThemeConfigFields.mobile,
4868
+ label: "手机",
4869
+ labelPlacement: "outside",
4870
+ placeholder: "请输入手机号码"
4871
+ }
4872
+ ),
4873
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4874
+ InputField,
4875
+ {
4876
+ name: ThemeConfigFields.fax,
4877
+ label: "传真",
4878
+ labelPlacement: "outside",
4879
+ placeholder: "请输入传真号码"
4880
+ }
4881
+ )
4882
+ ] }),
4883
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4884
+ TextareaField,
4885
+ {
4886
+ name: ThemeConfigFields.address,
4887
+ label: "地址",
4888
+ labelPlacement: "outside",
4889
+ placeholder: "请输入详细地址"
4890
+ }
4891
+ ) })
4892
+ ] }),
4893
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Divider, { className: "mt-4" }),
4894
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end p-4 px-6", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SubmitButton, { size: "sm", variant: "solid", color: "primary", children: "保存" }) })
4895
+ ]
4896
+ }
4897
+ ) });
4898
+ }
4899
+ function EmialTemplatesPanel(props) {
4900
+ const { onSuccess } = props;
4901
+ const theme = useStudioTheme();
4902
+ const { data: themeConfig2 } = useOneThemeConfig(newThemeConfigOptions(theme));
4903
+ const [save, { isMutating }] = useUpsertOneThemeConfig({
4904
+ onSuccess
4905
+ });
4906
+ const handleSave = useCallback(
4907
+ (value) => {
4908
+ if (!value)
4909
+ return;
4910
+ save(themeConfigToInput(value));
4911
+ },
4912
+ [save]
4913
+ );
4914
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(ModalBody, { className: "flex-1 min-h-0 overflow-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
4915
+ EntityForm,
4916
+ {
4917
+ entityName: ThemeConfigEntityName,
4918
+ initialValue: themeConfig2 || {
4919
+ [ThemeConfigAssciations.theme]: {
4920
+ id: theme == null ? void 0 : theme.id
4921
+ }
4922
+ },
4923
+ globalValidationErrorMessage: "部分输入项有错误,请检查",
4924
+ isMutating,
4925
+ onSubmit: handleSave,
4926
+ children: [
4927
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(ObjectField, { name: ThemeConfigFields.emailTemplates, children: [
4928
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ObjectField, { name: "customerEmail", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { className: "mt-2", children: [
4929
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(CardHeader, { className: "flex gap-2", children: [
4930
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { children: "客户通知邮件" }),
4931
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-default-500", children: "变量:$name" })
4932
+ ] }),
4933
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Divider, {}),
4934
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(CardBody, { className: "gap-4", children: [
4935
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4936
+ InputField,
4981
4937
  {
4982
- variant: "flat",
4983
- className: "h-[88px] bg-default-100 hover:bg-default-200 w-full",
4984
- startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(AddIcon, { className: "size-6 shrink-0" }),
4985
- isLoading: allLangsLoading || isMutating && !isChanginBaseLangRef.current,
4986
- children: "添加语言"
4938
+ name: "subject",
4939
+ label: "标题",
4940
+ labelPlacement: "outside",
4941
+ placeholder: "请输入标题"
4987
4942
  }
4988
- ) }),
4943
+ ),
4989
4944
  /* @__PURE__ */ jsxRuntimeExports.jsx(
4990
- DropdownMenu,
4945
+ TextareaField,
4991
4946
  {
4992
- "aria-label": "全部语言列表",
4993
- items: leftLangs,
4994
- className: "max-h-[300px] overflow-y-auto",
4995
- disallowEmptySelection: true,
4996
- selectionMode: "single",
4997
- onAction: handleAddLanguage,
4998
- children: (item) => /* @__PURE__ */ jsxRuntimeExports.jsx(
4999
- DropdownItem,
5000
- {
5001
- className: "gap-2",
5002
- startContent: item.icon ? /* @__PURE__ */ jsxRuntimeExports.jsx(
5003
- Icon,
5004
- {
5005
- icon: item.icon,
5006
- className: "text-xl shrink-0"
5007
- }
5008
- ) : null,
5009
- textValue: item.cnName || item.enName,
5010
- children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: item.cnName || item.enName })
5011
- },
5012
- item.id
5013
- )
4947
+ name: "content",
4948
+ label: "内容",
4949
+ minRows: 5,
4950
+ labelPlacement: "outside",
4951
+ placeholder: "请输入内容"
5014
4952
  }
5015
4953
  )
5016
4954
  ] })
5017
- ] }),
5018
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-6 flex items-center justify-between", children: [
5019
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-default-500", children: taskState == null ? void 0 : taskState.infoMessage }),
5020
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-end gap-2", children: [
5021
- isRunning && /* @__PURE__ */ jsxRuntimeExports.jsx(
5022
- Button$1,
4955
+ ] }) }),
4956
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ObjectField, { name: "employeeEmail", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { className: "mt-4", children: [
4957
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(CardHeader, { className: "flex gap-2", children: [
4958
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { children: "业务员通知邮件" }),
4959
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-default-500", children: "变量:$content" })
4960
+ ] }),
4961
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Divider, {}),
4962
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(CardBody, { className: "gap-4", children: [
4963
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4964
+ InputField,
5023
4965
  {
5024
- variant: "flat",
5025
- startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(TaskStopIcon, { className: "size-5" }),
5026
- onPress: handleStop,
5027
- children: "停止"
4966
+ name: "subject",
4967
+ label: "标题",
4968
+ labelPlacement: "outside",
4969
+ placeholder: "请输入标题"
5028
4970
  }
5029
4971
  ),
5030
4972
  /* @__PURE__ */ jsxRuntimeExports.jsx(
5031
- Button$1,
4973
+ TextareaField,
5032
4974
  {
5033
- color: "primary",
5034
- startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(AiStarIcon, { className: "size-5" }),
5035
- isDisabled: currentLang === ((_d = website == null ? void 0 : website.baseLang) == null ? void 0 : _d.id),
5036
- isLoading: isRunning,
5037
- onPress: handleTranslate,
5038
- children: "翻译 & 重置"
4975
+ name: "content",
4976
+ label: "内容",
4977
+ minRows: 5,
4978
+ labelPlacement: "outside",
4979
+ placeholder: "请输入内容"
5039
4980
  }
5040
4981
  )
5041
4982
  ] })
5042
- ] })
5043
- ] })
5044
- ] }),
5045
- !!((_e = website == null ? void 0 : website.langs) == null ? void 0 : _e.length) && ((_f = website == null ? void 0 : website.langs) == null ? void 0 : _f.length) > 1 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { className: "bg-default-50", children: [
5046
- /* @__PURE__ */ jsxRuntimeExports.jsx(CardHeader, { className: "flex gap-3 px-6 pt-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col flex-grow", children: [
5047
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-lg font-semibold", children: "链接方式" }),
5048
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-small text-default-500", children: "选择多语言网站的访问方式" })
5049
- ] }) }),
5050
- /* @__PURE__ */ jsxRuntimeExports.jsxs(CardBody, { className: "px-6 pb-6", children: [
5051
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid gap-4 md:grid-cols-2", children: linkTypes.map((type) => /* @__PURE__ */ jsxRuntimeExports.jsx(
5052
- Card,
5053
- {
5054
- shadow: "sm",
5055
- className: `bg-background cursor-pointer transition-colors ${linkType === type.key ? "border-2 border-primary" : "hover:bg-default-100"}`,
5056
- isPressable: type.key !== "path",
5057
- as: "div",
5058
- isDisabled: type.key === "path",
5059
- onPress: () => type.key !== "path" && setLinkType(type.key),
5060
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(CardBody, { className: "p-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
5061
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center size-10 rounded-lg bg-default-100", children: type.icon }),
5062
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1", children: [
5063
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "font-medium", children: type.label }),
5064
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-default-500", children: type.description })
4983
+ ] }) })
4984
+ ] }),
4985
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Divider, { className: "mt-4" }),
4986
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end mt-4", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SubmitButton, { size: "sm", variant: "solid", color: "primary", children: "保存" }) })
4987
+ ]
4988
+ }
4989
+ ) });
4990
+ }
4991
+ function FaviconCell({
4992
+ type,
4993
+ svgIcon,
4994
+ themeColor,
4995
+ isDark
4996
+ }) {
4997
+ const getBgColor = () => {
4998
+ if (type === "tab")
4999
+ return themeColor;
5000
+ if (type === "browser")
5001
+ return isDark ? "#333" : "#f3f4f6";
5002
+ return isDark ? "#222" : "white";
5003
+ };
5004
+ const getIconColor = () => {
5005
+ if (type === "tab")
5006
+ return "white";
5007
+ return isDark ? "white" : "black";
5008
+ };
5009
+ const getBorderColor = () => {
5010
+ if (type === "bookmark")
5011
+ return isDark ? "#555" : "#e5e7eb";
5012
+ return "transparent";
5013
+ };
5014
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center", children: [
5015
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
5016
+ "div",
5017
+ {
5018
+ className: `w-10 h-10 flex items-center justify-center rounded-md border`,
5019
+ style: {
5020
+ backgroundColor: getBgColor(),
5021
+ borderColor: getBorderColor()
5022
+ },
5023
+ children: svgIcon ? /* @__PURE__ */ jsxRuntimeExports.jsx(
5024
+ "div",
5025
+ {
5026
+ className: "w-6 h-6",
5027
+ dangerouslySetInnerHTML: {
5028
+ __html: svgIcon.replace(/currentColor/g, getIconColor()).replace(
5029
+ /fill="([^"]*)"/g,
5030
+ (match, color) => color === "currentColor" ? `fill="${getIconColor()}"` : match
5031
+ )
5032
+ }
5033
+ }
5034
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsx(
5035
+ FavouriteIcon,
5036
+ {
5037
+ className: "w-6 h-6",
5038
+ style: { color: getIconColor() }
5039
+ }
5040
+ )
5041
+ }
5042
+ ),
5043
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs mt-1", children: [
5044
+ type === "browser" && "浏览器",
5045
+ type === "tab" && "标签页",
5046
+ type === "bookmark" && "书签"
5047
+ ] })
5048
+ ] });
5049
+ }
5050
+ function FaviconPreview(props) {
5051
+ const { isDark } = props;
5052
+ const formValue = useFormValue();
5053
+ const themeColor = formValue == null ? void 0 : formValue.themeColor;
5054
+ const svgIcon = formValue == null ? void 0 : formValue.svgIcon;
5055
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
5056
+ "div",
5057
+ {
5058
+ className: "flex items-center gap-8 justify-center p-4",
5059
+ style: { borderRadius: "0.375rem" },
5060
+ children: [
5061
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
5062
+ FaviconCell,
5063
+ {
5064
+ type: "browser",
5065
+ svgIcon,
5066
+ themeColor,
5067
+ isDark
5068
+ }
5069
+ ),
5070
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
5071
+ FaviconCell,
5072
+ {
5073
+ type: "tab",
5074
+ svgIcon,
5075
+ themeColor,
5076
+ isDark
5077
+ }
5078
+ ),
5079
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
5080
+ FaviconCell,
5081
+ {
5082
+ type: "bookmark",
5083
+ svgIcon,
5084
+ themeColor,
5085
+ isDark
5086
+ }
5087
+ )
5088
+ ]
5089
+ }
5090
+ );
5091
+ }
5092
+ const FaviconPreviewField = toField(
5093
+ FaviconPreview,
5094
+ {
5095
+ defaultValue: ""
5096
+ }
5097
+ );
5098
+ function ResetButton() {
5099
+ const parentTheme = useParentTheme();
5100
+ const form = useForm();
5101
+ const handleReset = useCallback(() => {
5102
+ var _a, _b, _c, _d, _e;
5103
+ const formValue = form == null ? void 0 : form.getValue();
5104
+ form == null ? void 0 : form.setValue({
5105
+ ...formValue,
5106
+ [ThemeConfigFields.svgIcon]: (_a = parentTheme == null ? void 0 : parentTheme.config) == null ? void 0 : _a.svgIcon,
5107
+ [ThemeConfigFields.themeColor]: (_b = parentTheme == null ? void 0 : parentTheme.config) == null ? void 0 : _b.themeColor,
5108
+ [ThemeConfigFields.pngIcon]: (_c = parentTheme == null ? void 0 : parentTheme.config) == null ? void 0 : _c.pngIcon,
5109
+ [ThemeConfigFields.icoIcon]: (_d = parentTheme == null ? void 0 : parentTheme.config) == null ? void 0 : _d.icoIcon,
5110
+ [ThemeConfigFields.appleTouchIcon]: (_e = parentTheme == null ? void 0 : parentTheme.config) == null ? void 0 : _e.appleTouchIcon
5111
+ });
5112
+ }, [form, parentTheme == null ? void 0 : parentTheme.config]);
5113
+ return parentTheme ? /* @__PURE__ */ jsxRuntimeExports.jsx(Button$1, { variant: "flat", size: "sm", onPress: handleReset, children: "重置" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, {});
5114
+ }
5115
+ function FaviconPanel(props) {
5116
+ const { onSuccess } = props;
5117
+ const [isDarkPreview, setIsDarkPreview] = useState(false);
5118
+ const theme = useStudioTheme();
5119
+ const { data: themeConfig2 } = useOneThemeConfig(
5120
+ newThemeIconConfigOptions(theme)
5121
+ );
5122
+ const [save, { isMutating }] = useUpsertOneThemeConfig({
5123
+ onSuccess
5124
+ });
5125
+ const handleSave = useCallback(
5126
+ (value) => {
5127
+ if (!value)
5128
+ return;
5129
+ save(themeConfigToInput(value));
5130
+ },
5131
+ [save]
5132
+ );
5133
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(ModalBody, { className: "flex-1 p-0 min-h-0 flex flex-col", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
5134
+ EntityForm,
5135
+ {
5136
+ className: "flex-1 min-h-0 flex flex-col ",
5137
+ entityName: ThemeConfigEntityName,
5138
+ initialValue: themeConfig2 || {
5139
+ [ThemeConfigAssciations.theme]: {
5140
+ id: theme == null ? void 0 : theme.id
5141
+ }
5142
+ },
5143
+ globalValidationErrorMessage: "部分输入项有错误,请检查",
5144
+ isMutating,
5145
+ onSubmit: handleSave,
5146
+ children: [
5147
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col gap-4 min-h-0 overflow-auto p-4", children: [
5148
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { className: "bg-default-50 overflow-visible", children: [
5149
+ /* @__PURE__ */ jsxRuntimeExports.jsx(CardHeader, { className: "flex gap-3 px-6 pt-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col flex-grow", children: [
5150
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-lg font-semibold", children: "首选图标设置" }) }),
5151
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-small text-default-500", children: "SVG图标与浏览器主题色(Theme color)" })
5152
+ ] }) }),
5153
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(CardBody, { className: "px-6 pb-6 overflow-visible", children: [
5154
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mb-6", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
5155
+ TextareaField,
5156
+ {
5157
+ name: ThemeConfigFields.svgIcon,
5158
+ label: "SVG 图标",
5159
+ labelPlacement: "outside",
5160
+ placeholder: "请输入 SVG 图标代码",
5161
+ description: "推荐使用 SVG 格式,支持缩放且文件小"
5162
+ }
5163
+ ) }),
5164
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-6", children: [
5165
+ /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-sm font-medium mb-1.5", children: "浏览器主题色" }),
5166
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ColorField, { name: ThemeConfigFields.themeColor }),
5167
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-default-400 mt-1", children: "用于浏览器标签栏等显示" })
5168
+ ] }),
5169
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 border border-dashed border-default-200 rounded-lg bg-default-50", children: [
5170
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center mb-2", children: [
5171
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-medium", children: "预览效果" }),
5172
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
5173
+ Button$1,
5174
+ {
5175
+ size: "sm",
5176
+ variant: "light",
5177
+ isIconOnly: true,
5178
+ className: "text-default-600",
5179
+ onPress: () => setIsDarkPreview(!isDarkPreview),
5180
+ children: isDarkPreview ? /* @__PURE__ */ jsxRuntimeExports.jsx(LightIcon, { className: "size-4" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(DarkIcon, { className: "size-4" })
5181
+ }
5182
+ )
5065
5183
  ] }),
5066
- linkType === type.key && /* @__PURE__ */ jsxRuntimeExports.jsx(CheckCircleIcon, { className: "text-primary size-5" })
5067
- ] }) })
5068
- },
5069
- type.key
5070
- )) }),
5071
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-4", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-default-400", children: linkType === "subdomain" ? /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: "使用二级域名方式需要正确配置DNS解析,将所有二级域名指向网站服务器。 同时需要配置服务器支持泛域名解析。" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: "使用子网址方式无需额外的DNS配置,但URL会相对较长。 建议在无法使用二级域名时选择此方式。" }) }) })
5184
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
5185
+ FaviconPreviewField,
5186
+ {
5187
+ name: ThemeConfigFields.themeColor,
5188
+ isDark: isDarkPreview
5189
+ }
5190
+ )
5191
+ ] })
5192
+ ] })
5193
+ ] }),
5194
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { className: "bg-default-50 overflow-visible", children: [
5195
+ /* @__PURE__ */ jsxRuntimeExports.jsx(CardHeader, { className: "flex gap-3 px-6 pt-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col flex-grow", children: [
5196
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-lg font-semibold", children: "备选图标格式" }),
5197
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-small text-default-500", children: "为不同设备和浏览器提供多种图标格式,提高兼容性" })
5198
+ ] }) }),
5199
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(CardBody, { className: "px-6 pb-6 space-y-5 overflow-visible", children: [
5200
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
5201
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
5202
+ FullImageSelectField,
5203
+ {
5204
+ name: ThemeConfigFields.pngIcon,
5205
+ label: "PNG 图标",
5206
+ classNames: {
5207
+ base: "flex-col",
5208
+ label: "text-sm"
5209
+ },
5210
+ width: 80,
5211
+ height: 80
5212
+ }
5213
+ ),
5214
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-default-400 mt-1", children: "建议尺寸 512×512 像素,用于不支持 SVG 的场景" })
5215
+ ] }),
5216
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
5217
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
5218
+ FullImageSelectField,
5219
+ {
5220
+ name: ThemeConfigFields.icoIcon,
5221
+ label: "ICO 图标",
5222
+ classNames: {
5223
+ base: "flex-col",
5224
+ label: "text-sm"
5225
+ },
5226
+ width: 80,
5227
+ height: 80
5228
+ }
5229
+ ),
5230
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-default-400 mt-1", children: "传统格式,确保最大兼容性" })
5231
+ ] }),
5232
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
5233
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
5234
+ FullImageSelectField,
5235
+ {
5236
+ name: ThemeConfigFields.appleTouchIcon,
5237
+ label: "Apple Touch 图标",
5238
+ classNames: {
5239
+ base: "flex-col",
5240
+ label: "text-sm"
5241
+ },
5242
+ width: 80,
5243
+ height: 80
5244
+ }
5245
+ ),
5246
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-default-400 mt-1", children: "用于 iOS 设备,建议尺寸 180×180 像素的png图片" })
5247
+ ] })
5248
+ ] })
5249
+ ] })
5250
+ ] }),
5251
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Divider, {}),
5252
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-end p-4 px-6 gap-2", children: [
5253
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ResetButton, {}),
5254
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SubmitButton, { size: "sm", variant: "solid", color: "primary", children: "保存" })
5072
5255
  ] })
5073
- ] })
5074
- ] }) }),
5075
- /* @__PURE__ */ jsxRuntimeExports.jsx(
5076
- ConfirmDialog,
5077
- {
5078
- open: confirmOpen,
5079
- onClose: handleCloseConfirm,
5080
- onConfirm: handleConfirm,
5081
- confirm: "翻译会重置并覆盖当前网站内容,不可撤销,您确定要翻译吗?"
5082
- }
5083
- )
5084
- ] });
5256
+ ]
5257
+ }
5258
+ ) }) });
5085
5259
  }
5086
5260
  function ConfigDrawer() {
5087
5261
  const [openSettingsType, setOpenSettingsType] = useRecoilState(configTypeState);
@@ -5096,6 +5270,7 @@ function ConfigDrawer() {
5096
5270
  onClose: () => setOpenSettingsType(void 0),
5097
5271
  children: [
5098
5272
  /* @__PURE__ */ jsxRuntimeExports.jsxs(ModalHeader, { className: "pr-2 h-12", children: [
5273
+ openSettingsType === ThemeConfigType.Favicon && "网站图标",
5099
5274
  openSettingsType === ThemeConfigType.MultiLang && "多语言配置",
5100
5275
  openSettingsType === ThemeConfigType.Tailwind && "Tailwind 配置",
5101
5276
  openSettingsType === ThemeConfigType.CSS && "自定义CSS",
@@ -5106,6 +5281,7 @@ function ConfigDrawer() {
5106
5281
  /* @__PURE__ */ jsxRuntimeExports.jsx(ModalClose, {})
5107
5282
  ] }),
5108
5283
  /* @__PURE__ */ jsxRuntimeExports.jsx(Divider, {}),
5284
+ openSettingsType === ThemeConfigType.Favicon && /* @__PURE__ */ jsxRuntimeExports.jsx(FaviconPanel, { onSuccess: () => setOpenSettingsType(void 0) }),
5109
5285
  openSettingsType === ThemeConfigType.MultiLang && /* @__PURE__ */ jsxRuntimeExports.jsx(MultiLangPanel, {}),
5110
5286
  openSettingsType === ThemeConfigType.Extends && /* @__PURE__ */ jsxRuntimeExports.jsx(ExtendsPanel, {}),
5111
5287
  openSettingsType === ThemeConfigType.WebsiteInfo && /* @__PURE__ */ jsxRuntimeExports.jsx(WebsiteInfoPanel, { onSuccess: () => setOpenSettingsType(void 0) }),
@@ -5213,7 +5389,7 @@ const ThemeSelectionStep = (props) => {
5213
5389
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm", children: "当前父主题:" }),
5214
5390
  parentTheme == null ? void 0 : parentTheme.name
5215
5391
  ] }),
5216
- (parentTheme == null ? void 0 : parentTheme.id) === selectedThemeId && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-warning", children: "选中的主题与父主题相同" })
5392
+ (parentTheme == null ? void 0 : parentTheme.id) && (parentTheme == null ? void 0 : parentTheme.id) === selectedThemeId && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-warning", children: "选中的主题与父主题相同" })
5217
5393
  ] }),
5218
5394
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
5219
5395
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -6425,6 +6601,94 @@ const ThemeIcon = (props) => {
6425
6601
  }
6426
6602
  ) });
6427
6603
  };
6604
+ const defaultSchema = {
6605
+ componentName: "Root"
6606
+ };
6607
+ const emptyValue = { schema: void 0, config: void 0 };
6608
+ function useSchema(selectedContent) {
6609
+ const [schema, setSchema] = useState(emptyValue);
6610
+ const components = useFrontComponents();
6611
+ const pages = usePages();
6612
+ const componentsRef = useRef(components);
6613
+ const pagesRef = useRef(pages);
6614
+ componentsRef.current = components;
6615
+ pagesRef.current = pages;
6616
+ const templates = useTemplates();
6617
+ const templatesRef = useRef(templates);
6618
+ templatesRef.current = templates;
6619
+ useEffect(() => {
6620
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
6621
+ let code;
6622
+ let hasContent = false;
6623
+ let defaultConfig;
6624
+ if ((selectedContent == null ? void 0 : selectedContent.type) === ContentType.Component) {
6625
+ const component = (_a = componentsRef.current) == null ? void 0 : _a.find(
6626
+ (component2) => component2.id === selectedContent.id
6627
+ );
6628
+ if (component) {
6629
+ code = component.code;
6630
+ hasContent = true;
6631
+ }
6632
+ } else if ((selectedContent == null ? void 0 : selectedContent.type) === ContentType.PredefinedPage || (selectedContent == null ? void 0 : selectedContent.type) === ContentType.Page) {
6633
+ const page = (_b = pagesRef.current) == null ? void 0 : _b.find(
6634
+ (item) => item.id === selectedContent.id
6635
+ );
6636
+ defaultConfig = {
6637
+ pageMeta: {
6638
+ seoTitle: (_c = page == null ? void 0 : page.meta) == null ? void 0 : _c.seoTitle,
6639
+ seoDescription: (_d = page == null ? void 0 : page.meta) == null ? void 0 : _d.seoDescription,
6640
+ seoKeywords: (_e = page == null ? void 0 : page.meta) == null ? void 0 : _e.seoKeywords,
6641
+ ogTitle: (_f = page == null ? void 0 : page.meta) == null ? void 0 : _f.ogTitle,
6642
+ ogDescription: (_g = page == null ? void 0 : page.meta) == null ? void 0 : _g.ogDescription,
6643
+ ogType: (_h = page == null ? void 0 : page.meta) == null ? void 0 : _h.ogType,
6644
+ ogImage: (_i = page == null ? void 0 : page.meta) == null ? void 0 : _i.ogImage
6645
+ }
6646
+ };
6647
+ if (page) {
6648
+ code = page.code;
6649
+ hasContent = true;
6650
+ }
6651
+ } else if ((selectedContent == null ? void 0 : selectedContent.type) === ContentType.Template) {
6652
+ const template = (_j = templatesRef.current) == null ? void 0 : _j.find(
6653
+ (template2) => template2.id === selectedContent.id
6654
+ );
6655
+ if (template) {
6656
+ code = template.code;
6657
+ hasContent = true;
6658
+ }
6659
+ }
6660
+ if (code) {
6661
+ transformCodeToSchema(code).then((value) => {
6662
+ setSchema({
6663
+ schema: { ...defaultSchema, children: (value == null ? void 0 : value.template) || [] },
6664
+ config: { ...defaultConfig, ...value.resources }
6665
+ });
6666
+ });
6667
+ } else if (hasContent) {
6668
+ setSchema({
6669
+ schema: { ...defaultSchema, children: [] }
6670
+ });
6671
+ }
6672
+ }, [selectedContent == null ? void 0 : selectedContent.id, selectedContent == null ? void 0 : selectedContent.type]);
6673
+ console.log("===>schema", schema);
6674
+ return schema;
6675
+ }
6676
+ function useCloseDrawer() {
6677
+ const setDrawerType = useSetRecoilState(drawerTypeState);
6678
+ const drawerDocked = useRecoilValue(drawerDockedState);
6679
+ const close = useCallback(() => {
6680
+ if (!drawerDocked) {
6681
+ setDrawerType(void 0);
6682
+ }
6683
+ }, [drawerDocked, setDrawerType]);
6684
+ return close;
6685
+ }
6686
+ function useIsBaseLangTheme() {
6687
+ var _a, _b;
6688
+ const theme = useStudioTheme();
6689
+ const website = useWebsite();
6690
+ return ((_a = theme == null ? void 0 : theme.lang) == null ? void 0 : _a.id) === ((_b = website == null ? void 0 : website.baseLang) == null ? void 0 : _b.id);
6691
+ }
6428
6692
  function MoreActions$1() {
6429
6693
  const {
6430
6694
  isOpen: isParentThemeOpen,
@@ -6474,6 +6738,15 @@ function MoreActions$1() {
6474
6738
  },
6475
6739
  ThemeConfigType.WebsiteInfo
6476
6740
  ),
6741
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
6742
+ DropdownItem,
6743
+ {
6744
+ startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(FavouriteIcon, { className: "size-5" }),
6745
+ onPress: () => setConfigType(ThemeConfigType.Favicon),
6746
+ children: "站点图标"
6747
+ },
6748
+ "favicon"
6749
+ ),
6477
6750
  /* @__PURE__ */ jsxRuntimeExports.jsx(
6478
6751
  DropdownItem,
6479
6752
  {
@@ -12555,7 +12828,7 @@ function ViewModeButtons() {
12555
12828
  select: viewMode === ViewMode.Preview,
12556
12829
  isDisabled: !selectedContent,
12557
12830
  onPress: () => handleSetViewMode(ViewMode.Preview),
12558
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(PlayIcon, { className: "size-5" })
12831
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(PlayIcon, { className: "size-4" })
12559
12832
  }
12560
12833
  )
12561
12834
  ] });
@@ -12773,7 +13046,7 @@ const WebsiteToolbar = memo(() => {
12773
13046
  {
12774
13047
  className: `h-12 w-full flex px-0 justify-between items-center border-b border-divider`,
12775
13048
  children: [
12776
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center shrink-0 gap-2 pl-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Logo, { subtitle: "网站设计器 - " + (website == null ? void 0 : website.name) }) }),
13049
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center shrink-0 gap-2 pl-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Logo, { subtitle: "网站设计器 - " + ((website == null ? void 0 : website.title) || (website == null ? void 0 : website.name)) }) }),
12777
13050
  /* @__PURE__ */ jsxRuntimeExports.jsx(DeviceTabs, {}),
12778
13051
  /* @__PURE__ */ jsxRuntimeExports.jsxs(
12779
13052
  "div",
@@ -12881,10 +13154,129 @@ const SettingsForm = memo(() => {
12881
13154
  );
12882
13155
  });
12883
13156
  function MetaInfo() {
12884
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-2 px-4 text-sm text-default-500", children: [
12885
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "搜索引擎预览" }),
12886
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "社媒分享预览" }),
12887
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm", children: "SEO建议" })
13157
+ var _a, _b, _c, _d, _e, _f, _g, _h;
13158
+ const theme = useStudioTheme();
13159
+ const editingPage = useRecoilValue(editingPageState);
13160
+ const doc = useDocument();
13161
+ const pageConfig = doc == null ? void 0 : doc.getConfig();
13162
+ const pageMeta = pageConfig == null ? void 0 : pageConfig.pageMeta;
13163
+ const keywords = ((_a = pageMeta == null ? void 0 : pageMeta.seoKeywords) == null ? void 0 : _a.split(",")) || [];
13164
+ const ogImageUrl = ((_c = (_b = pageMeta == null ? void 0 : pageMeta.ogImage) == null ? void 0 : _b.file) == null ? void 0 : _c.resize) || ((_e = (_d = pageMeta == null ? void 0 : pageMeta.ogImage) == null ? void 0 : _d.file) == null ? void 0 : _e.thumbnail);
13165
+ const subUrl = useMemo(() => {
13166
+ if ((editingPage == null ? void 0 : editingPage.pageType) === PageType.Customized) {
13167
+ return "/" + (editingPage.slug || "");
13168
+ }
13169
+ if ((editingPage == null ? void 0 : editingPage.pageType) === PageType.Product) {
13170
+ return "/products/product-slug";
13171
+ }
13172
+ if ((editingPage == null ? void 0 : editingPage.pageType) === PageType.ProductList) {
13173
+ return "/products/page/1";
13174
+ }
13175
+ if ((editingPage == null ? void 0 : editingPage.pageType) === PageType.ProductCategory) {
13176
+ return "/products/category/page/1";
13177
+ }
13178
+ if ((editingPage == null ? void 0 : editingPage.pageType) === PageType.Post) {
13179
+ return "/posts/post-slug";
13180
+ }
13181
+ if ((editingPage == null ? void 0 : editingPage.pageType) === PageType.PostList) {
13182
+ return "/posts/page/1";
13183
+ }
13184
+ if ((editingPage == null ? void 0 : editingPage.pageType) === PageType.PostCategory) {
13185
+ return "/posts/category/page/1";
13186
+ }
13187
+ if ((editingPage == null ? void 0 : editingPage.pageType) === PageType.SearchList) {
13188
+ return "/search";
13189
+ }
13190
+ if ((editingPage == null ? void 0 : editingPage.pageType) === PageType.Profile) {
13191
+ return "/profile/userid";
13192
+ }
13193
+ if ((editingPage == null ? void 0 : editingPage.pageType) === PageType.Page404) {
13194
+ return "/404";
13195
+ }
13196
+ if ((editingPage == null ? void 0 : editingPage.pageType) === PageType.Thanks) {
13197
+ return "/thanks";
13198
+ }
13199
+ if ((editingPage == null ? void 0 : editingPage.pageType) === PageType.PageError) {
13200
+ return "/error";
13201
+ }
13202
+ return "";
13203
+ }, [editingPage == null ? void 0 : editingPage.pageType, editingPage == null ? void 0 : editingPage.slug]);
13204
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-2 flex flex-col gap-4 h-full overflow-y-auto text-sm", children: [
13205
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
13206
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "font-medium flex items-center gap-1", children: [
13207
+ /* @__PURE__ */ jsxRuntimeExports.jsx(GlobalIcon, { className: "text-primary-500 size-4" }),
13208
+ "搜索引擎预览"
13209
+ ] }) }),
13210
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-zinc-200 dark:border-zinc-700 rounded p-3 bg-white dark:bg-zinc-900", children: [
13211
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-blue-600 dark:text-blue-400 font-medium text-sm truncate", children: (pageMeta == null ? void 0 : pageMeta.seoTitle) || "未设置SEO标题" }),
13212
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-green-700 dark:text-green-500 text-xs mt-1 truncate", children: [
13213
+ "https://",
13214
+ ((_f = theme == null ? void 0 : theme.config) == null ? void 0 : _f.domain) || "未设置网站域名",
13215
+ subUrl
13216
+ ] }),
13217
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-zinc-600 dark:text-zinc-400 text-xs mt-1 line-clamp-2", children: (pageMeta == null ? void 0 : pageMeta.seoDescription) || "未设置SEO描述" })
13218
+ ] }),
13219
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap gap-1", children: [
13220
+ (_g = pageMeta == null ? void 0 : pageMeta.seoKeywords) == null ? void 0 : _g.split(",").slice(0, 3).map((keyword, index) => /* @__PURE__ */ jsxRuntimeExports.jsx(
13221
+ Chip,
13222
+ {
13223
+ color: "primary",
13224
+ variant: "flat",
13225
+ size: "sm",
13226
+ className: "text-xs",
13227
+ children: keyword.trim()
13228
+ },
13229
+ index
13230
+ )),
13231
+ keywords.length > 3 && /* @__PURE__ */ jsxRuntimeExports.jsxs(Chip, { color: "primary", variant: "flat", size: "sm", className: "text-xs", children: [
13232
+ "+",
13233
+ keywords.length - 3
13234
+ ] })
13235
+ ] })
13236
+ ] }),
13237
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3 mt-2", children: [
13238
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "font-medium flex items-center gap-1", children: [
13239
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SnsIcon, { className: "text-primary-500 size-4" }),
13240
+ "社媒预览"
13241
+ ] }),
13242
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-zinc-200 dark:border-zinc-700 rounded overflow-hidden bg-white dark:bg-zinc-900", children: [
13243
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "aspect-[1200/630] relative bg-zinc-100 dark:bg-zinc-800 overflow-hidden", children: ogImageUrl ? /* @__PURE__ */ jsxRuntimeExports.jsx(
13244
+ "img",
13245
+ {
13246
+ src: ogImageUrl,
13247
+ alt: "Social preview image",
13248
+ className: "w-full h-full object-cover"
13249
+ }
13250
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "p-2 text-xs text-default-500", children: "未设置社媒分享图片" }) }),
13251
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-2", children: [
13252
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 mb-1", children: [
13253
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-4 h-4 rounded-full bg-blue-500 flex items-center justify-center text-white", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { icon: "mdi:facebook", className: "text-xs" }) }),
13254
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs", children: ((_h = theme == null ? void 0 : theme.config) == null ? void 0 : _h.websiteTitle) || "没有设置网站标题" })
13255
+ ] }),
13256
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-xs font-medium mb-1 line-clamp-1", children: (pageMeta == null ? void 0 : pageMeta.ogTitle) || "未设置社媒标题" }),
13257
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-600 dark:text-zinc-400 line-clamp-2", children: (pageMeta == null ? void 0 : pageMeta.ogDescription) || "未设置社媒描述" })
13258
+ ] })
13259
+ ] })
13260
+ ] }),
13261
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3 mt-2", children: [
13262
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
13263
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "font-medium flex items-center gap-1", children: [
13264
+ /* @__PURE__ */ jsxRuntimeExports.jsx(LightBoltIcon, { className: "text-primary-500 size-4" }),
13265
+ "SEO优化建议"
13266
+ ] }),
13267
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
13268
+ Button$1,
13269
+ {
13270
+ size: "sm",
13271
+ variant: "solid",
13272
+ color: "primary",
13273
+ startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(AiStarIcon, { className: "size-4" }),
13274
+ children: "SEO评估"
13275
+ }
13276
+ )
13277
+ ] }),
13278
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border border-zinc-200 dark:border-zinc-700 rounded-lg bg-white dark:bg-zinc-900 p-3 overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-default-500", children: "请点击“SEO评估”按钮,通过AI进行SEO评估并获取优化建议" }) })
13279
+ ] })
12888
13280
  ] });
12889
13281
  }
12890
13282
  const rightPanelWidth = "w-[22rem]";
@@ -15673,137 +16065,137 @@ function PagesPanel(props) {
15673
16065
  }
15674
16066
  function SEOPanel(props) {
15675
16067
  const { hidden } = props;
15676
- const [page, setEditingPage] = useRecoilState(editingPageState);
15677
- const setChanged = useSetRecoilState(contentChangedState);
16068
+ const doc = useDocument();
16069
+ const pageConfig = doc == null ? void 0 : doc.getConfig();
16070
+ const pageMeta = pageConfig == null ? void 0 : pageConfig.pageMeta;
15678
16071
  const handleValueChange = useCallback(
15679
16072
  (values) => {
15680
- setEditingPage((page2) => ({
15681
- ...page2,
15682
- meta: {
15683
- ...page2 == null ? void 0 : page2.meta,
15684
- ...values
15685
- }
15686
- }));
15687
- setChanged(true);
16073
+ doc.setConfig({
16074
+ ...pageConfig || {},
16075
+ pageMeta: { ...pageConfig == null ? void 0 : pageConfig.pageMeta, ...values }
16076
+ });
15688
16077
  },
15689
- [setChanged, setEditingPage]
16078
+ [doc, pageConfig]
15690
16079
  );
15691
16080
  const initialValue = useMemo(
15692
- () => {
15693
- var _a, _b, _c;
15694
- return {
15695
- [PageMetaFields.seoTitle]: ((_a = page == null ? void 0 : page.meta) == null ? void 0 : _a.seoTitle) || "",
15696
- [PageMetaFields.seoKeywords]: ((_b = page == null ? void 0 : page.meta) == null ? void 0 : _b.seoKeywords) || "",
15697
- [PageMetaFields.seoDescription]: ((_c = page == null ? void 0 : page.meta) == null ? void 0 : _c.seoDescription) || ""
15698
- };
15699
- },
15700
- [page]
16081
+ () => ({
16082
+ [PageMetaFields.seoTitle]: (pageMeta == null ? void 0 : pageMeta.seoTitle) || "",
16083
+ [PageMetaFields.seoKeywords]: (pageMeta == null ? void 0 : pageMeta.seoKeywords) || "",
16084
+ [PageMetaFields.seoDescription]: (pageMeta == null ? void 0 : pageMeta.seoDescription) || ""
16085
+ }),
16086
+ [pageMeta == null ? void 0 : pageMeta.seoDescription, pageMeta == null ? void 0 : pageMeta.seoKeywords, pageMeta == null ? void 0 : pageMeta.seoTitle]
15701
16087
  );
15702
- return /* @__PURE__ */ jsxRuntimeExports.jsx(Form, { initialValue, onValueChange: handleValueChange, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(LeftPanel, { className: "p-4", hidden, children: [
15703
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1", children: [
15704
- /* @__PURE__ */ jsxRuntimeExports.jsx(TitleViewField, { name: PageMetaFields.seoTitle }),
15705
- /* @__PURE__ */ jsxRuntimeExports.jsx(DescriptionViewField, { name: PageMetaFields.seoDescription })
15706
- ] }),
15707
- /* @__PURE__ */ jsxRuntimeExports.jsx(
15708
- InputField,
15709
- {
15710
- name: PageMetaFields.seoTitle,
15711
- label: "标题",
15712
- labelPlacement: "outside",
15713
- placeholder: "请输入SEO标题"
15714
- }
15715
- ),
15716
- /* @__PURE__ */ jsxRuntimeExports.jsx(
15717
- TextareaField,
15718
- {
15719
- name: PageMetaFields.seoKeywords,
15720
- label: "关键词",
15721
- minRows: 2,
15722
- labelPlacement: "outside",
15723
- placeholder: "请输入SEO关键词"
15724
- }
15725
- ),
15726
- /* @__PURE__ */ jsxRuntimeExports.jsx(
15727
- TextareaField,
15728
- {
15729
- name: PageMetaFields.seoDescription,
15730
- label: "描述",
15731
- labelPlacement: "outside",
15732
- placeholder: "请输入SEO描述",
15733
- minRows: 3
15734
- }
15735
- )
15736
- ] }) });
16088
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(LeftPanel, { className: "px-4", hidden, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
16089
+ Form,
16090
+ {
16091
+ className: "flex-1 flex flex-col gap-4",
16092
+ initialValue,
16093
+ onValueChange: handleValueChange,
16094
+ children: [
16095
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1", children: [
16096
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TitleViewField, { name: PageMetaFields.seoTitle }),
16097
+ /* @__PURE__ */ jsxRuntimeExports.jsx(DescriptionViewField, { name: PageMetaFields.seoDescription })
16098
+ ] }),
16099
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
16100
+ InputField,
16101
+ {
16102
+ name: PageMetaFields.seoTitle,
16103
+ label: "标题",
16104
+ labelPlacement: "outside",
16105
+ placeholder: "请输入SEO标题"
16106
+ }
16107
+ ),
16108
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
16109
+ TextareaField,
16110
+ {
16111
+ name: PageMetaFields.seoKeywords,
16112
+ label: "关键词",
16113
+ minRows: 2,
16114
+ labelPlacement: "outside",
16115
+ placeholder: "请输入SEO关键词"
16116
+ }
16117
+ ),
16118
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
16119
+ TextareaField,
16120
+ {
16121
+ name: PageMetaFields.seoDescription,
16122
+ label: "描述",
16123
+ labelPlacement: "outside",
16124
+ placeholder: "请输入SEO描述",
16125
+ minRows: 3
16126
+ }
16127
+ )
16128
+ ]
16129
+ }
16130
+ ) });
15737
16131
  }
15738
16132
  function SNSPanel(props) {
15739
16133
  const { hidden } = props;
15740
16134
  const webSite = useWebsite();
15741
- const [page, setEditingPage] = useRecoilState(editingPageState);
15742
- const setChanged = useSetRecoilState(contentChangedState);
15743
- const handleValueChange = useCallback((values) => {
15744
- setEditingPage(
15745
- (page2) => ({
15746
- ...page2,
15747
- ...values
15748
- })
15749
- );
15750
- setChanged(true);
15751
- }, [setChanged, setEditingPage]);
15752
- const initialValue = useMemo(() => ({
15753
- [PageAssciations.ogImage]: page == null ? void 0 : page.ogImage,
15754
- [PageFields.ogTitle]: (page == null ? void 0 : page.ogTitle) || "",
15755
- [PageFields.ogDescription]: (page == null ? void 0 : page.ogDescription) || ""
15756
- }), [page]);
15757
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
16135
+ const doc = useDocument();
16136
+ const pageConfig = doc == null ? void 0 : doc.getConfig();
16137
+ const pageMeta = pageConfig == null ? void 0 : pageConfig.pageMeta;
16138
+ const handleValueChange = useCallback(
16139
+ (values) => {
16140
+ doc.setConfig({
16141
+ ...pageConfig || {},
16142
+ pageMeta: { ...pageConfig == null ? void 0 : pageConfig.pageMeta, ...values }
16143
+ });
16144
+ },
16145
+ [doc, pageConfig]
16146
+ );
16147
+ const initialValue = useMemo(
16148
+ () => ({
16149
+ [PageMetaAssciations.ogImage]: pageMeta == null ? void 0 : pageMeta.ogImage,
16150
+ [PageMetaFields.ogTitle]: (pageMeta == null ? void 0 : pageMeta.ogTitle) || "",
16151
+ [PageMetaFields.ogDescription]: (pageMeta == null ? void 0 : pageMeta.ogDescription) || ""
16152
+ }),
16153
+ [pageMeta == null ? void 0 : pageMeta.ogDescription, pageMeta == null ? void 0 : pageMeta.ogImage, pageMeta == null ? void 0 : pageMeta.ogTitle]
16154
+ );
16155
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(LeftPanel, { className: "p-4", hidden, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
15758
16156
  Form,
15759
16157
  {
16158
+ className: "flex-1 flex flex-col gap-4",
15760
16159
  initialValue,
15761
16160
  onValueChange: handleValueChange,
15762
- children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
15763
- LeftPanel,
15764
- {
15765
- className: "p-4",
15766
- hidden,
15767
- children: [
15768
- /* @__PURE__ */ jsxRuntimeExports.jsx(
15769
- MediaSingleSelectField,
15770
- {
15771
- name: PageAssciations.ogImage,
15772
- label: "图片",
15773
- websiteId: webSite == null ? void 0 : webSite.id,
15774
- className: "aspect-[16/6]",
15775
- classNames: {
15776
- base: "flex-col"
15777
- },
15778
- width: "1200",
15779
- height: "630",
15780
- mediaTypes: [MediaType.image]
15781
- }
15782
- ),
15783
- /* @__PURE__ */ jsxRuntimeExports.jsx(
15784
- InputField,
15785
- {
15786
- name: PageFields.ogTitle,
15787
- label: "标题",
15788
- labelPlacement: "outside",
15789
- placeholder: "请输入社媒标题"
15790
- }
15791
- ),
15792
- /* @__PURE__ */ jsxRuntimeExports.jsx(
15793
- TextareaField,
15794
- {
15795
- name: PageFields.ogDescription,
15796
- label: "描述",
15797
- minRows: 3,
15798
- labelPlacement: "outside",
15799
- placeholder: "请输入社媒描述"
15800
- }
15801
- )
15802
- ]
15803
- }
15804
- )
16161
+ children: [
16162
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
16163
+ MediaSingleSelectField,
16164
+ {
16165
+ name: PageMetaAssciations.ogImage,
16166
+ label: "图片",
16167
+ websiteId: webSite == null ? void 0 : webSite.id,
16168
+ className: "aspect-[16/6]",
16169
+ classNames: {
16170
+ base: "flex-col"
16171
+ },
16172
+ width: "1200",
16173
+ height: "630",
16174
+ mediaTypes: [MediaType.image]
16175
+ }
16176
+ ),
16177
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
16178
+ InputField,
16179
+ {
16180
+ name: PageMetaFields.ogTitle,
16181
+ label: "标题",
16182
+ labelPlacement: "outside",
16183
+ placeholder: "请输入社媒标题"
16184
+ }
16185
+ ),
16186
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
16187
+ TextareaField,
16188
+ {
16189
+ name: PageMetaFields.ogDescription,
16190
+ label: "描述",
16191
+ minRows: 3,
16192
+ labelPlacement: "outside",
16193
+ placeholder: "请输入社媒描述"
16194
+ }
16195
+ )
16196
+ ]
15805
16197
  }
15806
- );
16198
+ ) });
15807
16199
  }
15808
16200
  function LeftDrawerPannels() {
15809
16201
  const drawerType = useRecoilValue(drawerTypeState);
@@ -15925,436 +16317,172 @@ function ComponentModal(props) {
15925
16317
  labelPlacement: "outside",
15926
16318
  placeholder: "请输入顺序"
15927
16319
  }
15928
- )
15929
- ] })
15930
- }
15931
- );
15932
- }
15933
- function useRegisterComponent(component) {
15934
- const [rxProps, setRxProps] = React__default.useState();
15935
- const engine = useDesignerEngine();
15936
- const editingComponent = useRecoilValue(editingComponentState);
15937
- useEffect(() => {
15938
- var _a;
15939
- if (engine && (editingComponent == null ? void 0 : editingComponent.id) !== component.id && component.name) {
15940
- const newSlots = {};
15941
- const { children: childrenSlotNode, ...namedSlots } = component.slots || {};
15942
- for (const key in namedSlots) {
15943
- newSlots[key] = { ...namedSlots[key], componentName: slotContentName };
15944
- }
15945
- engine.getResourceManager().registerResources({
15946
- name: component.name,
15947
- title: component.title,
15948
- elements: [
15949
- {
15950
- componentName: component.name,
15951
- props: {
15952
- //默认属性配置
15953
- ...component.testConfig
15954
- },
15955
- //默认slots
15956
- slots: newSlots,
15957
- children: childrenSlotNode == null ? void 0 : childrenSlotNode.children
15958
- }
15959
- ]
15960
- });
15961
- const props = (_a = engine.getResourceManager().getResourceByName(component.name)) == null ? void 0 : _a.rxProps;
15962
- if (props) {
15963
- setRxProps(props);
15964
- }
15965
- return () => {
15966
- if (component.name) {
15967
- engine.getResourceManager().unregisterResources(component.name);
15968
- }
15969
- };
15970
- }
15971
- }, [component, editingComponent == null ? void 0 : editingComponent.id, engine]);
15972
- return rxProps;
15973
- }
15974
- function ComponentNode(props) {
15975
- const { component, readonly, selectedId, onSelect } = props;
15976
- const [open, setOpen] = React__default.useState(false);
15977
- const [remove, { isMutating }] = useRemoveRow();
15978
- const edit = useEditRow();
15979
- const rxProps = useRegisterComponent(component);
15980
- const handleOpenChange = React__default.useCallback((open2) => {
15981
- setOpen(open2);
15982
- }, []);
15983
- const handleDesign = React__default.useCallback(() => {
15984
- onSelect == null ? void 0 : onSelect(component.id || null);
15985
- }, [onSelect, component.id]);
15986
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
15987
- LeafNode,
15988
- {
15989
- fiexdAction: open || isMutating,
15990
- hover: open || isMutating,
15991
- icon: /* @__PURE__ */ jsxRuntimeExports.jsx(AstroIcon, { className: "size-4 mt-1" }),
15992
- className: "text-sm",
15993
- selected: selectedId === component.id,
15994
- actions: !readonly && /* @__PURE__ */ jsxRuntimeExports.jsxs(Dropdown, { onOpenChange: handleOpenChange, children: [
15995
- /* @__PURE__ */ jsxRuntimeExports.jsx(DropdownTrigger, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
15996
- Button$1,
15997
- {
15998
- isLoading: isMutating,
15999
- isIconOnly: true,
16000
- variant: "light",
16001
- size: "sm",
16002
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(
16003
- Icon,
16004
- {
16005
- icon: "mdi:more-horiz",
16006
- className: "size-5 text-default-600"
16007
- }
16008
- )
16009
- }
16010
- ) }),
16011
- /* @__PURE__ */ jsxRuntimeExports.jsxs(DropdownMenu, { "aria-label": "Actions", children: [
16012
- /* @__PURE__ */ jsxRuntimeExports.jsx(
16013
- DropdownItem,
16014
- {
16015
- onPress: handleDesign,
16016
- startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(DesignIcon, { className: "size-4" }),
16017
- children: "设计"
16018
- },
16019
- "design"
16020
- ),
16021
- /* @__PURE__ */ jsxRuntimeExports.jsx(
16022
- DropdownItem,
16023
- {
16024
- startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(EditIcon, { className: "size-4" }),
16025
- showDivider: true,
16026
- onPress: edit,
16027
- children: "编辑"
16028
- },
16029
- "edit"
16030
- ),
16031
- /* @__PURE__ */ jsxRuntimeExports.jsx(
16032
- DropdownItem,
16033
- {
16034
- color: "danger",
16035
- startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(RemoveIcon, { className: "size-4" }),
16036
- onPress: () => remove(),
16037
- children: "删除"
16038
- },
16039
- "remove"
16040
- )
16041
- ] })
16042
- ] }),
16043
- ...rxProps,
16044
- children: component.title || component.name
16045
- }
16046
- );
16047
- }
16048
- function ComponentList(props) {
16049
- var _a;
16050
- const { themeId, readonly, list, category, newComponent, noCagegory, selectedId, onSelect, onClearNewComponent } = props;
16051
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(
16052
- EntityListScope,
16053
- {
16054
- entityName: FrontComponentEntityName,
16055
- data: list,
16056
- children: [
16057
- (_a = list == null ? void 0 : list.items) == null ? void 0 : _a.map((item) => {
16058
- return /* @__PURE__ */ jsxRuntimeExports.jsx(EntityRowScope, { row: item, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
16059
- ComponentNode,
16060
- {
16061
- component: item,
16062
- readonly,
16063
- selectedId,
16064
- categoryId: category == null ? void 0 : category.id,
16065
- onSelect
16066
- }
16067
- ) }, item.id);
16068
- }),
16069
- !readonly && /* @__PURE__ */ jsxRuntimeExports.jsx(
16070
- ComponentModal,
16071
- {
16072
- themeId,
16073
- value: newComponent,
16074
- noCagegory,
16075
- onClose: onClearNewComponent,
16076
- categoryId: category == null ? void 0 : category.id
16077
- }
16078
- )
16079
- ]
16080
- }
16081
- );
16082
- }
16083
- function ComponentsSkeletons() {
16084
- return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full p-4", children: /* @__PURE__ */ jsxRuntimeExports.jsx("ul", { className: "space-y-4", children: Array.from({ length: 6 }).map((_2, index) => /* @__PURE__ */ jsxRuntimeExports.jsx("li", { className: "flex items-center py-0.5", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "w-full h-12 rounded-md" }) }, index)) }) });
16085
- }
16086
- const IMPORT_COMPONENTS_KEY = "import-components";
16087
- function useComponentsImportTask(categoryId) {
16088
- const theme = useStudioTheme();
16089
- const lang = useCurrentLang();
16090
- const components = useFrontComponents();
16091
- const appKey = (theme == null ? void 0 : theme.id) || "";
16092
- const taskState = useInprogressTaskByKey(
16093
- IMPORT_COMPONENTS_KEY + (categoryId || ""),
16094
- appKey
16095
- );
16096
- const setTask = useUpdateTask(appKey);
16097
- const setTaskRef = useRef(setTask);
16098
- setTaskRef.current = setTask;
16099
- const entifyClient = useCreateEntityClient();
16100
- const task = taskState && taskState.status !== "done" ? taskPool[taskState.taskId] : void 0;
16101
- const aiUrl = useAiUrl();
16102
- const handleTaskChange = useCallback((data) => {
16103
- setTaskRef.current(data);
16104
- }, []);
16105
- const importComponents = useCallback(
16106
- (ids, categoryId2, needTranslate) => {
16107
- if (!(theme == null ? void 0 : theme.id)) {
16108
- console.error("没设置Theme");
16109
- return;
16110
- }
16111
- if (!entifyClient) {
16112
- console.error("entifyClient 创建失败");
16113
- return;
16114
- }
16115
- if (!aiUrl) {
16116
- console.error("没设置aiUrl");
16117
- return;
16118
- }
16119
- const task2 = new ImportComponentsTask(
16120
- {
16121
- key: IMPORT_COMPONENTS_KEY + (categoryId2 || ""),
16122
- ids,
16123
- entifyClient,
16124
- needTranslate,
16125
- themeId: theme == null ? void 0 : theme.id,
16126
- lang,
16127
- aiUrl,
16128
- categoryId: categoryId2
16129
- },
16130
- components || []
16131
- );
16132
- taskPool[task2.id] = task2;
16133
- task2.onDataChange(handleTaskChange);
16134
- task2.start();
16135
- },
16136
- [aiUrl, entifyClient, handleTaskChange, lang, components, theme == null ? void 0 : theme.id]
16137
- );
16138
- return { taskState, importComponents, task };
16139
- }
16140
- function ImportComponentModal({
16141
- categoryId,
16142
- open,
16143
- onClose
16144
- }) {
16145
- const [selection, setSelections] = useState([]);
16146
- const [confirmTitle, setConfirmTitle] = useState(
16147
- void 0
16148
- );
16149
- const baseThemeId = useBaseLangThemeId();
16150
- const isBaseTheme = useIsBaseLangTheme();
16151
- const parentTheme = useParentTheme();
16152
- const themeComs = useFrontComponents();
16153
- const { taskState, importComponents, task } = useComponentsImportTask(
16154
- categoryId || ""
16155
- );
16156
- useEffect(() => {
16157
- var _a;
16158
- setSelections == null ? void 0 : setSelections(((_a = taskState == null ? void 0 : taskState.data) == null ? void 0 : _a.ids) || []);
16159
- }, [setSelections, taskState == null ? void 0 : taskState.data]);
16160
- useEffect(() => {
16161
- if ((taskState == null ? void 0 : taskState.status) === "done") {
16162
- setSelections == null ? void 0 : setSelections([]);
16163
- }
16164
- }, [setSelections, taskState]);
16165
- const confirmResolveRef = useRef();
16166
- const { data: baseTheme, isLoading } = useOneThemeById(
16167
- baseThemeId || void 0,
16168
- new ThemeQueryOptions([ThemeFields.id, ThemeFields.name]).componentCategories([
16169
- ComponentCategoryFields.id,
16170
- ComponentCategoryFields.name
16171
- ]).components(
16172
- new FrontComponentQueryOptions([
16173
- FrontComponentFields.id,
16174
- FrontComponentFields.name,
16175
- FrontComponentFields.title,
16176
- FrontComponentFields.code,
16177
- FrontComponentFields.props,
16178
- FrontComponentFields.testConfig
16179
- ]).category()
16180
- )
16320
+ )
16321
+ ] })
16322
+ }
16181
16323
  );
16182
- const categories = useMemo(() => {
16183
- return !isBaseTheme ? (baseTheme == null ? void 0 : baseTheme.componentCategories) || [] : (parentTheme == null ? void 0 : parentTheme.componentCategories) || [];
16184
- }, [
16185
- baseTheme == null ? void 0 : baseTheme.componentCategories,
16186
- parentTheme == null ? void 0 : parentTheme.componentCategories,
16187
- isBaseTheme
16188
- ]);
16189
- const components = useMemo(() => {
16190
- return !isBaseTheme ? (baseTheme == null ? void 0 : baseTheme.components) || [] : (parentTheme == null ? void 0 : parentTheme.components) || [];
16191
- }, [baseTheme == null ? void 0 : baseTheme.components, parentTheme == null ? void 0 : parentTheme.components, isBaseTheme]);
16192
- const noCategoryComponents = useMemo(() => {
16193
- return components.filter((component) => {
16194
- var _a;
16195
- return !((_a = component.category) == null ? void 0 : _a.id);
16196
- });
16197
- }, [components]);
16198
- const handleToggleSelect = React__default.useCallback((id) => {
16199
- setSelections((prev) => {
16200
- if (prev.includes(id)) {
16201
- return prev.filter((item) => item !== id);
16202
- } else {
16203
- return [...prev, id];
16324
+ }
16325
+ function useRegisterComponent(component) {
16326
+ const [rxProps, setRxProps] = React__default.useState();
16327
+ const engine = useDesignerEngine();
16328
+ const editingComponent = useRecoilValue(editingComponentState);
16329
+ useEffect(() => {
16330
+ var _a;
16331
+ if (engine && (editingComponent == null ? void 0 : editingComponent.id) !== component.id && component.name) {
16332
+ const newSlots = {};
16333
+ const { children: childrenSlotNode, ...namedSlots } = component.slots || {};
16334
+ for (const key in namedSlots) {
16335
+ newSlots[key] = { ...namedSlots[key], componentName: slotContentName };
16204
16336
  }
16205
- });
16206
- }, []);
16207
- const handleConfirm = useCallback(() => {
16208
- setConfirmTitle(void 0);
16209
- if (confirmResolveRef.current) {
16210
- confirmResolveRef.current(true);
16211
- confirmResolveRef.current = void 0;
16212
- }
16213
- }, []);
16214
- const confirmOverride = useCallback(async (count) => {
16215
- setConfirmTitle(`${count} 个组件已存在,要全部覆盖吗?`);
16216
- return new Promise((resolve) => {
16217
- confirmResolveRef.current = resolve;
16218
- });
16219
- }, []);
16220
- const handleImport = useCallback(async () => {
16221
- const comsToImport = components.filter(
16222
- (c) => selection.includes(c.id || "")
16223
- );
16224
- const existings = themeComs == null ? void 0 : themeComs.filter(
16225
- (c) => comsToImport == null ? void 0 : comsToImport.find((com) => c.name === com.name)
16226
- );
16227
- if (existings == null ? void 0 : existings.length) {
16228
- const result = await confirmOverride(existings.length);
16229
- if (!result) {
16230
- return;
16337
+ engine.getResourceManager().registerResources({
16338
+ name: component.name,
16339
+ title: component.title,
16340
+ elements: [
16341
+ {
16342
+ componentName: component.name,
16343
+ props: {
16344
+ //默认属性配置
16345
+ ...component.testConfig
16346
+ },
16347
+ //默认slots
16348
+ slots: newSlots,
16349
+ children: childrenSlotNode == null ? void 0 : childrenSlotNode.children
16350
+ }
16351
+ ]
16352
+ });
16353
+ const props = (_a = engine.getResourceManager().getResourceByName(component.name)) == null ? void 0 : _a.rxProps;
16354
+ if (props) {
16355
+ setRxProps(props);
16231
16356
  }
16357
+ return () => {
16358
+ if (component.name) {
16359
+ engine.getResourceManager().unregisterResources(component.name);
16360
+ }
16361
+ };
16232
16362
  }
16233
- importComponents(selection, categoryId || void 0, !isBaseTheme);
16234
- }, [
16235
- categoryId,
16236
- components,
16237
- confirmOverride,
16238
- importComponents,
16239
- isBaseTheme,
16240
- selection,
16241
- themeComs
16242
- ]);
16243
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(Modal, { isOpen: open, onClose, children: [
16244
- /* @__PURE__ */ jsxRuntimeExports.jsx(ModalOverlay, { className: "z-10" }),
16245
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
16246
- ModalContent,
16247
- {
16248
- className: "h-[80vh] shadow-lg border border-divider z-10",
16249
- width: 600,
16250
- children: [
16251
- /* @__PURE__ */ jsxRuntimeExports.jsxs(ModalHeader, { className: "pr-3", children: [
16252
- "转入组件",
16253
- /* @__PURE__ */ jsxRuntimeExports.jsx(ModalClose, {})
16254
- ] }),
16255
- /* @__PURE__ */ jsxRuntimeExports.jsx(Divider, {}),
16256
- /* @__PURE__ */ jsxRuntimeExports.jsx(ModalBody, { className: "flex-1 overflow-y-auto min-h-0 p-2", children: isLoading ? /* @__PURE__ */ jsxRuntimeExports.jsx(ComponentsSkeletons, {}) : /* @__PURE__ */ jsxRuntimeExports.jsxs(TreeView, { children: [
16257
- categories == null ? void 0 : categories.map((category) => /* @__PURE__ */ jsxRuntimeExports.jsx(GroupNode, { title: category.name, icon: false, children: components.filter(
16258
- (component) => {
16259
- var _a;
16260
- return ((_a = component.category) == null ? void 0 : _a.id) === category.id;
16261
- }
16262
- ).map((component) => /* @__PURE__ */ jsxRuntimeExports.jsx(
16263
- LeafNode,
16264
- {
16265
- icon: /* @__PURE__ */ jsxRuntimeExports.jsx(
16266
- Checkbox,
16267
- {
16268
- isSelected: selection.includes(component.id || ""),
16269
- onValueChange: () => handleToggleSelect(component.id || "")
16270
- }
16271
- ),
16272
- onClick: () => handleToggleSelect(component.id || ""),
16273
- children: component.title || component.name
16274
- },
16275
- component.id
16276
- )) }, category.id)),
16277
- noCategoryComponents.map((component) => /* @__PURE__ */ jsxRuntimeExports.jsx(
16278
- LeafNode,
16363
+ }, [component, editingComponent == null ? void 0 : editingComponent.id, engine]);
16364
+ return rxProps;
16365
+ }
16366
+ function ComponentNode(props) {
16367
+ const { component, readonly, selectedId, onSelect } = props;
16368
+ const [open, setOpen] = React__default.useState(false);
16369
+ const [remove, { isMutating }] = useRemoveRow();
16370
+ const edit = useEditRow();
16371
+ const rxProps = useRegisterComponent(component);
16372
+ const handleOpenChange = React__default.useCallback((open2) => {
16373
+ setOpen(open2);
16374
+ }, []);
16375
+ const handleDesign = React__default.useCallback(() => {
16376
+ onSelect == null ? void 0 : onSelect(component.id || null);
16377
+ }, [onSelect, component.id]);
16378
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
16379
+ LeafNode,
16380
+ {
16381
+ fiexdAction: open || isMutating,
16382
+ hover: open || isMutating,
16383
+ icon: /* @__PURE__ */ jsxRuntimeExports.jsx(AstroIcon, { className: "size-4 mt-1" }),
16384
+ className: "text-sm",
16385
+ selected: selectedId === component.id,
16386
+ actions: !readonly && /* @__PURE__ */ jsxRuntimeExports.jsxs(Dropdown, { onOpenChange: handleOpenChange, children: [
16387
+ /* @__PURE__ */ jsxRuntimeExports.jsx(DropdownTrigger, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
16388
+ Button$1,
16389
+ {
16390
+ isLoading: isMutating,
16391
+ isIconOnly: true,
16392
+ variant: "light",
16393
+ size: "sm",
16394
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
16395
+ Icon,
16279
16396
  {
16280
- icon: /* @__PURE__ */ jsxRuntimeExports.jsx(
16281
- Checkbox,
16282
- {
16283
- isSelected: selection.includes(component.id || ""),
16284
- onValueChange: () => handleToggleSelect(component.id || "")
16285
- }
16286
- ),
16287
- onClick: () => handleToggleSelect(component.id || ""),
16288
- children: component.title || component.name
16289
- },
16290
- component.id
16291
- ))
16292
- ] }) }),
16293
- /* @__PURE__ */ jsxRuntimeExports.jsx(Divider, {}),
16294
- /* @__PURE__ */ jsxRuntimeExports.jsxs(ModalFooter, { className: "justify-between", children: [
16295
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-default-500 flex items-center gap-2", children: [
16296
- selection.length > 0 && (taskState == null ? void 0 : taskState.status) !== "in-progress" ? `${selection.length}个组件选中` : "",
16297
- taskState == null ? void 0 : taskState.infoMessage,
16298
- (taskState == null ? void 0 : taskState.status) === "in-progress" && /* @__PURE__ */ jsxRuntimeExports.jsx(
16299
- Button$1,
16300
- {
16301
- variant: "light",
16302
- size: "sm",
16303
- isIconOnly: true,
16304
- onPress: () => {
16305
- task == null ? void 0 : task.stop();
16306
- },
16307
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(TaskStopIcon, { className: "size-9 text-primary" })
16308
- }
16309
- )
16310
- ] }),
16311
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
16312
- /* @__PURE__ */ jsxRuntimeExports.jsx(Button$1, { variant: "light", onPress: onClose, children: "关闭" }),
16313
- /* @__PURE__ */ jsxRuntimeExports.jsx(
16314
- Button$1,
16315
- {
16316
- variant: "solid",
16317
- color: "primary",
16318
- onPress: handleImport,
16319
- isLoading: (taskState == null ? void 0 : taskState.status) === "in-progress",
16320
- children: "转入"
16321
- }
16322
- )
16323
- ] })
16324
- ] }),
16397
+ icon: "mdi:more-horiz",
16398
+ className: "size-5 text-default-600"
16399
+ }
16400
+ )
16401
+ }
16402
+ ) }),
16403
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(DropdownMenu, { "aria-label": "Actions", children: [
16325
16404
  /* @__PURE__ */ jsxRuntimeExports.jsx(
16326
- ConfirmDialog,
16405
+ DropdownItem,
16406
+ {
16407
+ onPress: handleDesign,
16408
+ startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(DesignIcon, { className: "size-4" }),
16409
+ children: "设计"
16410
+ },
16411
+ "design"
16412
+ ),
16413
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
16414
+ DropdownItem,
16415
+ {
16416
+ startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(EditIcon, { className: "size-4" }),
16417
+ showDivider: true,
16418
+ onPress: edit,
16419
+ children: "编辑"
16420
+ },
16421
+ "edit"
16422
+ ),
16423
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
16424
+ DropdownItem,
16425
+ {
16426
+ color: "danger",
16427
+ startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(RemoveIcon, { className: "size-4" }),
16428
+ onPress: () => remove(),
16429
+ children: "删除"
16430
+ },
16431
+ "remove"
16432
+ )
16433
+ ] })
16434
+ ] }),
16435
+ ...rxProps,
16436
+ children: component.title || component.name
16437
+ }
16438
+ );
16439
+ }
16440
+ function ComponentList(props) {
16441
+ var _a;
16442
+ const { themeId, readonly, list, category, newComponent, noCagegory, selectedId, onSelect, onClearNewComponent } = props;
16443
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
16444
+ EntityListScope,
16445
+ {
16446
+ entityName: FrontComponentEntityName,
16447
+ data: list,
16448
+ children: [
16449
+ (_a = list == null ? void 0 : list.items) == null ? void 0 : _a.map((item) => {
16450
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(EntityRowScope, { row: item, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
16451
+ ComponentNode,
16327
16452
  {
16328
- open: !!confirmTitle,
16329
- onClose: () => {
16330
- setConfirmTitle(void 0);
16331
- if (confirmResolveRef.current) {
16332
- confirmResolveRef.current(false);
16333
- confirmResolveRef.current = void 0;
16334
- }
16335
- },
16336
- onConfirm: handleConfirm,
16337
- confirm: confirmTitle
16453
+ component: item,
16454
+ readonly,
16455
+ selectedId,
16456
+ categoryId: category == null ? void 0 : category.id,
16457
+ onSelect
16338
16458
  }
16339
- )
16340
- ]
16341
- }
16342
- )
16343
- ] });
16459
+ ) }, item.id);
16460
+ }),
16461
+ !readonly && /* @__PURE__ */ jsxRuntimeExports.jsx(
16462
+ ComponentModal,
16463
+ {
16464
+ themeId,
16465
+ value: newComponent,
16466
+ noCagegory,
16467
+ onClose: onClearNewComponent,
16468
+ categoryId: category == null ? void 0 : category.id
16469
+ }
16470
+ )
16471
+ ]
16472
+ }
16473
+ );
16344
16474
  }
16345
16475
  const ComponentCategoryNode = memo(
16346
16476
  (props) => {
16347
16477
  var _a;
16348
16478
  const { category, themeId, readonly, selectedId, onSelect } = props;
16349
16479
  const [open, setOpen] = React__default.useState(false);
16350
- const [comModalOpen, setComModalOpen] = React__default.useState(false);
16351
16480
  const website = useWebsite();
16352
16481
  const [remove, { isMutating }] = useRemoveRow({
16353
16482
  onSuccess: () => {
16354
16483
  emitEntityChange(FrontComponentEntityName);
16355
16484
  }
16356
16485
  });
16357
- const { taskState } = useComponentsImportTask((category == null ? void 0 : category.id) || "");
16358
16486
  const [newComponent, setNewComponent] = React__default.useState();
16359
16487
  const edit = useEditRow();
16360
16488
  const components = useFrontComponents();
@@ -16384,107 +16512,87 @@ const ComponentCategoryNode = memo(
16384
16512
  items: componentsInCategory
16385
16513
  };
16386
16514
  }, [componentsInCategory]);
16387
- const running = (taskState == null ? void 0 : taskState.status) === "in-progress";
16388
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
16389
- /* @__PURE__ */ jsxRuntimeExports.jsx(
16390
- GroupNode,
16391
- {
16392
- title: category.name,
16393
- fiexdAction: open || isMutating || running,
16394
- icon: null,
16395
- classNames: {
16396
- title: "text-sm"
16397
- },
16398
- defaultExpanded: !!((_a = data.items) == null ? void 0 : _a.find((item) => item.id === selectedId)),
16399
- action: !readonly && /* @__PURE__ */ jsxRuntimeExports.jsxs(Dropdown, { onOpenChange: handleOpenChange, children: [
16400
- /* @__PURE__ */ jsxRuntimeExports.jsx(DropdownTrigger, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
16401
- Button$1,
16402
- {
16403
- isLoading: isMutating || running,
16404
- isIconOnly: true,
16405
- variant: "light",
16406
- size: "sm",
16407
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(
16408
- Icon,
16515
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
16516
+ GroupNode,
16517
+ {
16518
+ title: category.name,
16519
+ fiexdAction: open || isMutating,
16520
+ icon: null,
16521
+ classNames: {
16522
+ title: "text-sm"
16523
+ },
16524
+ defaultExpanded: !!((_a = data.items) == null ? void 0 : _a.find((item) => item.id === selectedId)),
16525
+ action: !readonly && /* @__PURE__ */ jsxRuntimeExports.jsxs(Dropdown, { onOpenChange: handleOpenChange, children: [
16526
+ /* @__PURE__ */ jsxRuntimeExports.jsx(DropdownTrigger, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
16527
+ Button$1,
16528
+ {
16529
+ isLoading: isMutating,
16530
+ isIconOnly: true,
16531
+ variant: "light",
16532
+ size: "sm",
16533
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
16534
+ Icon,
16535
+ {
16536
+ icon: "mdi:more-horiz",
16537
+ className: "size-5 text-default-600"
16538
+ }
16539
+ )
16540
+ }
16541
+ ) }),
16542
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
16543
+ DropdownMenu,
16544
+ {
16545
+ "aria-label": "Actions",
16546
+ disabledKeys: (website == null ? void 0 : website.id) ? void 0 : ["import"],
16547
+ children: [
16548
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
16549
+ DropdownItem,
16409
16550
  {
16410
- icon: "mdi:more-horiz",
16411
- className: "size-5 text-default-600"
16412
- }
16551
+ startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(AddIcon, { className: "size-4" }),
16552
+ onPress: handleNewComponent,
16553
+ children: "添加组件"
16554
+ },
16555
+ "add"
16556
+ ),
16557
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
16558
+ DropdownItem,
16559
+ {
16560
+ startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(EditIcon, { className: "size-4" }),
16561
+ showDivider: true,
16562
+ onPress: handleEdit,
16563
+ children: "编辑"
16564
+ },
16565
+ "edit"
16566
+ ),
16567
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
16568
+ DropdownItem,
16569
+ {
16570
+ color: "danger",
16571
+ startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(RemoveIcon, { className: "size-4" }),
16572
+ onPress: () => remove(),
16573
+ children: "删除"
16574
+ },
16575
+ "remove"
16413
16576
  )
16414
- }
16415
- ) }),
16416
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
16417
- DropdownMenu,
16418
- {
16419
- "aria-label": "Actions",
16420
- disabledKeys: (website == null ? void 0 : website.id) ? void 0 : ["import"],
16421
- children: [
16422
- /* @__PURE__ */ jsxRuntimeExports.jsx(
16423
- DropdownItem,
16424
- {
16425
- startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(AddIcon, { className: "size-4" }),
16426
- onPress: handleNewComponent,
16427
- children: "添加组件"
16428
- },
16429
- "add"
16430
- ),
16431
- /* @__PURE__ */ jsxRuntimeExports.jsx(
16432
- DropdownItem,
16433
- {
16434
- startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(ImportIcon, { className: "size-4" }),
16435
- onPress: () => setComModalOpen(true),
16436
- children: "转入组件"
16437
- },
16438
- "import"
16439
- ),
16440
- /* @__PURE__ */ jsxRuntimeExports.jsx(
16441
- DropdownItem,
16442
- {
16443
- startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(EditIcon, { className: "size-4" }),
16444
- showDivider: true,
16445
- onPress: handleEdit,
16446
- children: "编辑"
16447
- },
16448
- "edit"
16449
- ),
16450
- /* @__PURE__ */ jsxRuntimeExports.jsx(
16451
- DropdownItem,
16452
- {
16453
- color: "danger",
16454
- startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(RemoveIcon, { className: "size-4" }),
16455
- onPress: () => remove(),
16456
- children: "删除"
16457
- },
16458
- "remove"
16459
- )
16460
- ]
16461
- }
16462
- )
16463
- ] }),
16464
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(
16465
- ComponentList,
16466
- {
16467
- category,
16468
- themeId,
16469
- readonly,
16470
- list: data,
16471
- newComponent,
16472
- selectedId,
16473
- onSelect,
16474
- onClearNewComponent: () => setNewComponent(void 0)
16577
+ ]
16475
16578
  }
16476
16579
  )
16477
- }
16478
- ),
16479
- /* @__PURE__ */ jsxRuntimeExports.jsx(
16480
- ImportComponentModal,
16481
- {
16482
- open: comModalOpen,
16483
- categoryId: category.id,
16484
- onClose: () => setComModalOpen(false)
16485
- }
16486
- )
16487
- ] });
16580
+ ] }),
16581
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
16582
+ ComponentList,
16583
+ {
16584
+ category,
16585
+ themeId,
16586
+ readonly,
16587
+ list: data,
16588
+ newComponent,
16589
+ selectedId,
16590
+ onSelect,
16591
+ onClearNewComponent: () => setNewComponent(void 0)
16592
+ }
16593
+ )
16594
+ }
16595
+ ) });
16488
16596
  }
16489
16597
  );
16490
16598
  function ComponentCategoryList(props) {
@@ -16948,53 +17056,318 @@ function MaterialNodeView(props) {
16948
17056
  }
16949
17057
  );
16950
17058
  }
16951
- function WebComponents() {
16952
- return /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: resourceTreeNodes.map((node) => {
16953
- return /* @__PURE__ */ jsxRuntimeExports.jsx(MaterialNodeView, { node }, node.title);
16954
- }) });
16955
- }
16956
- function ComponentCategoryModal(props) {
16957
- const { themeId, onClose } = props;
16958
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
16959
- EntityEditModal,
16960
- {
16961
- entityName: ComponentCategoryEntityName,
16962
- entityLabel: "组件分类",
16963
- initialValue: {
16964
- theme: { id: themeId }
16965
- },
16966
- classNames: {
16967
- content: "max-w-sm"
16968
- },
16969
- entityToInput: componentCategoryToInput,
16970
- onClose,
16971
- children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-4", children: [
16972
- /* @__PURE__ */ jsxRuntimeExports.jsx(
16973
- InputField,
16974
- {
16975
- name: "name",
16976
- label: "名称",
16977
- validateSchema: {
16978
- type: "string",
16979
- required: true
16980
- },
16981
- labelPlacement: "outside",
16982
- placeholder: "请输入名称"
16983
- }
16984
- ),
16985
- /* @__PURE__ */ jsxRuntimeExports.jsx(
16986
- InputField,
16987
- {
16988
- name: "seqValue",
16989
- label: "顺序",
16990
- type: "number",
16991
- labelPlacement: "outside",
16992
- placeholder: "请输入顺序"
16993
- }
16994
- )
16995
- ] })
17059
+ function WebComponents() {
17060
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: resourceTreeNodes.map((node) => {
17061
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(MaterialNodeView, { node }, node.title);
17062
+ }) });
17063
+ }
17064
+ function ComponentCategoryModal(props) {
17065
+ const { themeId, onClose } = props;
17066
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
17067
+ EntityEditModal,
17068
+ {
17069
+ entityName: ComponentCategoryEntityName,
17070
+ entityLabel: "组件分类",
17071
+ initialValue: {
17072
+ theme: { id: themeId }
17073
+ },
17074
+ classNames: {
17075
+ content: "max-w-sm"
17076
+ },
17077
+ entityToInput: componentCategoryToInput,
17078
+ onClose,
17079
+ children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-4", children: [
17080
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
17081
+ InputField,
17082
+ {
17083
+ name: "name",
17084
+ label: "名称",
17085
+ validateSchema: {
17086
+ type: "string",
17087
+ required: true
17088
+ },
17089
+ labelPlacement: "outside",
17090
+ placeholder: "请输入名称"
17091
+ }
17092
+ ),
17093
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
17094
+ InputField,
17095
+ {
17096
+ name: "seqValue",
17097
+ label: "顺序",
17098
+ type: "number",
17099
+ labelPlacement: "outside",
17100
+ placeholder: "请输入顺序"
17101
+ }
17102
+ )
17103
+ ] })
17104
+ }
17105
+ );
17106
+ }
17107
+ function ComponentsSkeletons() {
17108
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full p-4", children: /* @__PURE__ */ jsxRuntimeExports.jsx("ul", { className: "space-y-4", children: Array.from({ length: 6 }).map((_2, index) => /* @__PURE__ */ jsxRuntimeExports.jsx("li", { className: "flex items-center py-0.5", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Skeleton, { className: "w-full h-12 rounded-md" }) }, index)) }) });
17109
+ }
17110
+ const IMPORT_COMPONENTS_KEY = "import-components";
17111
+ function useComponentsImportTask() {
17112
+ const theme = useStudioTheme();
17113
+ const lang = useCurrentLang();
17114
+ const components = useFrontComponents();
17115
+ const appKey = (theme == null ? void 0 : theme.id) || "";
17116
+ const taskState = useInprogressTaskByKey(IMPORT_COMPONENTS_KEY, appKey);
17117
+ const setTask = useUpdateTask(appKey);
17118
+ const setTaskRef = useRef(setTask);
17119
+ setTaskRef.current = setTask;
17120
+ const entifyClient = useCreateEntityClient();
17121
+ const task = taskState && taskState.status !== "done" ? taskPool[taskState.taskId] : void 0;
17122
+ const aiUrl = useAiUrl();
17123
+ const componentCategories = useComponentCategories();
17124
+ const handleTaskChange = useCallback((data) => {
17125
+ setTaskRef.current(data);
17126
+ }, []);
17127
+ const importComponents = useCallback(
17128
+ (ids, needTranslate) => {
17129
+ if (!(theme == null ? void 0 : theme.id)) {
17130
+ console.error("没设置Theme");
17131
+ return;
17132
+ }
17133
+ if (!entifyClient) {
17134
+ console.error("entifyClient 创建失败");
17135
+ return;
17136
+ }
17137
+ if (!aiUrl) {
17138
+ console.error("没设置aiUrl");
17139
+ return;
17140
+ }
17141
+ const task2 = new ImportComponentsTask(
17142
+ {
17143
+ key: IMPORT_COMPONENTS_KEY,
17144
+ ids,
17145
+ entifyClient,
17146
+ needTranslate,
17147
+ themeId: theme == null ? void 0 : theme.id,
17148
+ lang,
17149
+ aiUrl
17150
+ //categoryId,
17151
+ },
17152
+ components || [],
17153
+ (componentCategories == null ? void 0 : componentCategories.items) || []
17154
+ );
17155
+ taskPool[task2.id] = task2;
17156
+ task2.onDataChange(handleTaskChange);
17157
+ task2.start();
17158
+ },
17159
+ [
17160
+ theme == null ? void 0 : theme.id,
17161
+ entifyClient,
17162
+ aiUrl,
17163
+ lang,
17164
+ components,
17165
+ componentCategories,
17166
+ handleTaskChange
17167
+ ]
17168
+ );
17169
+ return { taskState, importComponents, task };
17170
+ }
17171
+ function ImportComponentModal({
17172
+ open,
17173
+ onClose
17174
+ }) {
17175
+ const [selection, setSelections] = useState([]);
17176
+ const [confirmTitle, setConfirmTitle] = useState(
17177
+ void 0
17178
+ );
17179
+ const baseThemeId = useBaseLangThemeId();
17180
+ const isBaseTheme = useIsBaseLangTheme();
17181
+ const parentTheme = useParentTheme();
17182
+ const themeComs = useFrontComponents();
17183
+ const { taskState, importComponents, task } = useComponentsImportTask();
17184
+ useEffect(() => {
17185
+ var _a;
17186
+ setSelections == null ? void 0 : setSelections(((_a = taskState == null ? void 0 : taskState.data) == null ? void 0 : _a.ids) || []);
17187
+ }, [setSelections, taskState == null ? void 0 : taskState.data]);
17188
+ useEffect(() => {
17189
+ if ((taskState == null ? void 0 : taskState.status) === "done") {
17190
+ setSelections == null ? void 0 : setSelections([]);
16996
17191
  }
17192
+ }, [setSelections, taskState]);
17193
+ const confirmResolveRef = useRef();
17194
+ const { data: baseTheme, isLoading } = useOneThemeById(
17195
+ baseThemeId || void 0,
17196
+ new ThemeQueryOptions([ThemeFields.id, ThemeFields.name]).componentCategories([
17197
+ ComponentCategoryFields.id,
17198
+ ComponentCategoryFields.name
17199
+ ]).components(
17200
+ new FrontComponentQueryOptions([
17201
+ FrontComponentFields.id,
17202
+ FrontComponentFields.name,
17203
+ FrontComponentFields.title,
17204
+ FrontComponentFields.code,
17205
+ FrontComponentFields.props,
17206
+ FrontComponentFields.testConfig
17207
+ ]).category()
17208
+ )
16997
17209
  );
17210
+ const categories = useMemo(() => {
17211
+ return !isBaseTheme ? (baseTheme == null ? void 0 : baseTheme.componentCategories) || [] : (parentTheme == null ? void 0 : parentTheme.componentCategories) || [];
17212
+ }, [
17213
+ baseTheme == null ? void 0 : baseTheme.componentCategories,
17214
+ parentTheme == null ? void 0 : parentTheme.componentCategories,
17215
+ isBaseTheme
17216
+ ]);
17217
+ const components = useMemo(() => {
17218
+ return !isBaseTheme ? (baseTheme == null ? void 0 : baseTheme.components) || [] : (parentTheme == null ? void 0 : parentTheme.components) || [];
17219
+ }, [baseTheme == null ? void 0 : baseTheme.components, parentTheme == null ? void 0 : parentTheme.components, isBaseTheme]);
17220
+ const noCategoryComponents = useMemo(() => {
17221
+ return components.filter((component) => {
17222
+ var _a;
17223
+ return !((_a = component.category) == null ? void 0 : _a.id);
17224
+ });
17225
+ }, [components]);
17226
+ const handleToggleSelect = React__default.useCallback((id) => {
17227
+ setSelections((prev) => {
17228
+ if (prev.includes(id)) {
17229
+ return prev.filter((item) => item !== id);
17230
+ } else {
17231
+ return [...prev, id];
17232
+ }
17233
+ });
17234
+ }, []);
17235
+ const handleConfirm = useCallback(() => {
17236
+ setConfirmTitle(void 0);
17237
+ if (confirmResolveRef.current) {
17238
+ confirmResolveRef.current(true);
17239
+ confirmResolveRef.current = void 0;
17240
+ }
17241
+ }, []);
17242
+ const confirmOverride = useCallback(async (count) => {
17243
+ setConfirmTitle(`${count} 个组件已存在,要全部覆盖吗?`);
17244
+ return new Promise((resolve) => {
17245
+ confirmResolveRef.current = resolve;
17246
+ });
17247
+ }, []);
17248
+ const handleImport = useCallback(async () => {
17249
+ const comsToImport = components.filter(
17250
+ (c) => selection.includes(c.id || "")
17251
+ );
17252
+ const existings = themeComs == null ? void 0 : themeComs.filter(
17253
+ (c) => comsToImport == null ? void 0 : comsToImport.find((com) => c.name === com.name)
17254
+ );
17255
+ if (existings == null ? void 0 : existings.length) {
17256
+ const result = await confirmOverride(existings.length);
17257
+ if (!result) {
17258
+ return;
17259
+ }
17260
+ }
17261
+ importComponents(selection, !isBaseTheme);
17262
+ }, [
17263
+ components,
17264
+ confirmOverride,
17265
+ importComponents,
17266
+ isBaseTheme,
17267
+ selection,
17268
+ themeComs
17269
+ ]);
17270
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(Modal, { isOpen: open, onClose, children: [
17271
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ModalOverlay, { className: "z-10" }),
17272
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
17273
+ ModalContent,
17274
+ {
17275
+ className: "h-[80vh] shadow-lg border border-divider z-10",
17276
+ width: 600,
17277
+ children: [
17278
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(ModalHeader, { className: "pr-3", children: [
17279
+ "转入组件",
17280
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ModalClose, {})
17281
+ ] }),
17282
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Divider, {}),
17283
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ModalBody, { className: "flex-1 overflow-y-auto min-h-0 p-2", children: isLoading ? /* @__PURE__ */ jsxRuntimeExports.jsx(ComponentsSkeletons, {}) : /* @__PURE__ */ jsxRuntimeExports.jsxs(TreeView, { children: [
17284
+ categories == null ? void 0 : categories.map((category) => /* @__PURE__ */ jsxRuntimeExports.jsx(GroupNode, { title: category.name, icon: false, children: components.filter(
17285
+ (component) => {
17286
+ var _a;
17287
+ return ((_a = component.category) == null ? void 0 : _a.id) === category.id;
17288
+ }
17289
+ ).map((component) => /* @__PURE__ */ jsxRuntimeExports.jsx(
17290
+ LeafNode,
17291
+ {
17292
+ icon: /* @__PURE__ */ jsxRuntimeExports.jsx(
17293
+ Checkbox,
17294
+ {
17295
+ isSelected: selection.includes(component.id || ""),
17296
+ onValueChange: () => handleToggleSelect(component.id || "")
17297
+ }
17298
+ ),
17299
+ onClick: () => handleToggleSelect(component.id || ""),
17300
+ children: component.title || component.name
17301
+ },
17302
+ component.id
17303
+ )) }, category.id)),
17304
+ noCategoryComponents.map((component) => /* @__PURE__ */ jsxRuntimeExports.jsx(
17305
+ LeafNode,
17306
+ {
17307
+ icon: /* @__PURE__ */ jsxRuntimeExports.jsx(
17308
+ Checkbox,
17309
+ {
17310
+ isSelected: selection.includes(component.id || ""),
17311
+ onValueChange: () => handleToggleSelect(component.id || "")
17312
+ }
17313
+ ),
17314
+ onClick: () => handleToggleSelect(component.id || ""),
17315
+ children: component.title || component.name
17316
+ },
17317
+ component.id
17318
+ ))
17319
+ ] }) }),
17320
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Divider, {}),
17321
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(ModalFooter, { className: "justify-between", children: [
17322
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-default-500 flex items-center gap-2", children: [
17323
+ selection.length > 0 && (taskState == null ? void 0 : taskState.status) !== "in-progress" ? `${selection.length}个组件选中` : "",
17324
+ taskState == null ? void 0 : taskState.infoMessage,
17325
+ (taskState == null ? void 0 : taskState.status) === "in-progress" && /* @__PURE__ */ jsxRuntimeExports.jsx(
17326
+ Button$1,
17327
+ {
17328
+ variant: "light",
17329
+ size: "sm",
17330
+ isIconOnly: true,
17331
+ onPress: () => {
17332
+ task == null ? void 0 : task.stop();
17333
+ },
17334
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(TaskStopIcon, { className: "size-9 text-primary" })
17335
+ }
17336
+ )
17337
+ ] }),
17338
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
17339
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Button$1, { variant: "light", onPress: onClose, children: "关闭" }),
17340
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
17341
+ Button$1,
17342
+ {
17343
+ variant: "solid",
17344
+ color: "primary",
17345
+ onPress: handleImport,
17346
+ isLoading: (taskState == null ? void 0 : taskState.status) === "in-progress",
17347
+ children: "转入"
17348
+ }
17349
+ )
17350
+ ] })
17351
+ ] }),
17352
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
17353
+ ConfirmDialog,
17354
+ {
17355
+ open: !!confirmTitle,
17356
+ onClose: () => {
17357
+ setConfirmTitle(void 0);
17358
+ if (confirmResolveRef.current) {
17359
+ confirmResolveRef.current(false);
17360
+ confirmResolveRef.current = void 0;
17361
+ }
17362
+ },
17363
+ onConfirm: handleConfirm,
17364
+ confirm: confirmTitle
17365
+ }
17366
+ )
17367
+ ]
17368
+ }
17369
+ )
17370
+ ] });
16998
17371
  }
16999
17372
  function ComponentsRootNode(props) {
17000
17373
  const { themeId, readonly, selectedContent, onSelectContent } = props;
@@ -17805,6 +18178,15 @@ function MoreActions() {
17805
18178
  },
17806
18179
  ThemeConfigType.WebsiteInfo
17807
18180
  ),
18181
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
18182
+ DropdownItem,
18183
+ {
18184
+ startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(FavouriteIcon, { className: "size-5" }),
18185
+ onPress: () => setConfigType(ThemeConfigType.Favicon),
18186
+ children: "站点图标"
18187
+ },
18188
+ "favicon"
18189
+ ),
17808
18190
  /* @__PURE__ */ jsxRuntimeExports.jsx(
17809
18191
  DropdownItem,
17810
18192
  {