@rxdrag/website-studio 0.0.19 → 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
  }
@@ -2477,7 +2500,8 @@ function useImportVariables() {
2477
2500
  PublishableStatus,
2478
2501
  getEnvVariables: () => envs,
2479
2502
  dayjs,
2480
- rxPage: mockRxPage
2503
+ rxPage: mockRxPage,
2504
+ FORM_SALT: "form_salt"
2481
2505
  };
2482
2506
  }, [endpoint, lang == null ? void 0 : lang.abbr, token, website == null ? void 0 : website.id]);
2483
2507
  return variables;
@@ -3089,8 +3113,6 @@ const createEnv = (theme) => {
3089
3113
  #nodejs服务地址
3090
3114
  #PUBLIC_WEBSITE_ID = 4299262263296
3091
3115
  PUBLIC_ENTIFY_GUEST_TOKEN = "17bD#4!fG8^2wS*0z"
3092
- #表单加密盐
3093
- PUBLIC_FORM_SALT = "yizhanfeinb"
3094
3116
  `;
3095
3117
  };
3096
3118
  const gitignoreCode = `# build output
@@ -3130,11 +3152,12 @@ const faviconCode = `<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox
3130
3152
  </defs>
3131
3153
  </svg>`;
3132
3154
  const createBaseCssCode = (theme) => {
3155
+ var _a;
3133
3156
  return `@tailwind base;
3134
3157
  @tailwind components;
3135
3158
  @tailwind utilities;
3136
3159
 
3137
- ${theme.css || ""}
3160
+ ${((_a = theme.styleConfig) == null ? void 0 : _a.css) || ""}
3138
3161
 
3139
3162
  `;
3140
3163
  };
@@ -3182,7 +3205,7 @@ const libCode = `import {
3182
3205
  export const rx = Entify.getInstance(getEnvVariables()) as IEntify;
3183
3206
  `;
3184
3207
  const layoutCode = `---
3185
- import "../base.css";
3208
+ import "../style.css";
3186
3209
  import { ClientRouter } from "astro:transitions";
3187
3210
  ---
3188
3211
 
@@ -3475,34 +3498,6 @@ const askForQuoteCode = `import type { APIRoute } from "astro";
3475
3498
  }
3476
3499
  };
3477
3500
  `;
3478
- const settingsCode = `{
3479
- "css.validate": true,
3480
- "less.validate": true,
3481
- "scss.validate": true,
3482
- "stylelint.validate": ["css", "scss"],
3483
- "editor.quickSuggestions": {
3484
- "strings": true
3485
- },
3486
- "css.lint.unknownAtRules": "ignore"
3487
- }
3488
- `;
3489
- const extensionsCode = `{
3490
- "recommendations": ["astro-build.astro-vscode"],
3491
- "unwantedRecommendations": []
3492
- }
3493
- `;
3494
- const launchCode = `{
3495
- "version": "0.2.0",
3496
- "configurations": [
3497
- {
3498
- "command": "./node_modules/.bin/astro dev",
3499
- "name": "Development server",
3500
- "request": "launch",
3501
- "type": "node-terminal"
3502
- }
3503
- ]
3504
- }
3505
- `;
3506
3501
  const createBaseFiles = (theme) => {
3507
3502
  return {
3508
3503
  "package.json": {
@@ -3535,25 +3530,6 @@ const createBaseFiles = (theme) => {
3535
3530
  contents: tailwindConfigCode
3536
3531
  }
3537
3532
  },
3538
- ".vscode": {
3539
- directory: {
3540
- "settings.json": {
3541
- file: {
3542
- contents: settingsCode
3543
- }
3544
- },
3545
- "extensions.json": {
3546
- file: {
3547
- contents: extensionsCode
3548
- }
3549
- },
3550
- "launch.json": {
3551
- file: {
3552
- contents: launchCode
3553
- }
3554
- }
3555
- }
3556
- },
3557
3533
  src: {
3558
3534
  directory: {
3559
3535
  layouts: {
@@ -3590,7 +3566,7 @@ const createBaseFiles = (theme) => {
3590
3566
  }
3591
3567
  }
3592
3568
  },
3593
- "base.css": {
3569
+ "style.css": {
3594
3570
  file: {
3595
3571
  contents: createBaseCssCode(theme)
3596
3572
  }
@@ -3772,20 +3748,57 @@ function useGetFiles() {
3772
3748
  );
3773
3749
  return getFiles;
3774
3750
  }
3775
- function useSave(onSaved) {
3776
- const save = useCallback(
3777
- (name, content) => {
3778
- saveFile(name, content).then(
3779
- (savedName) => {
3780
- if (savedName) {
3781
- 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);
3782
3776
  }
3783
3777
  }
3784
- );
3778
+ }
3785
3779
  },
3786
- [onSaved]
3780
+ []
3787
3781
  );
3788
- 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 };
3789
3802
  }
3790
3803
  var ContentType = /* @__PURE__ */ ((ContentType2) => {
3791
3804
  ContentType2["Page"] = "page";
@@ -3816,78 +3829,6 @@ var ViewMode = /* @__PURE__ */ ((ViewMode2) => {
3816
3829
  ViewMode2["Code"] = "code";
3817
3830
  return ViewMode2;
3818
3831
  })(ViewMode || {});
3819
- const defaultSchema = {
3820
- componentName: "Root"
3821
- };
3822
- const emptyValue = { schema: void 0, config: void 0 };
3823
- function useSchema(selectedContent) {
3824
- const [schema, setSchema] = useState(emptyValue);
3825
- const components = useFrontComponents();
3826
- const pages = usePages();
3827
- const componentsRef = useRef(components);
3828
- const pagesRef = useRef(pages);
3829
- componentsRef.current = components;
3830
- pagesRef.current = pages;
3831
- const templates = useTemplates();
3832
- const templatesRef = useRef(templates);
3833
- templatesRef.current = templates;
3834
- useEffect(() => {
3835
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
3836
- let code;
3837
- let hasContent = false;
3838
- let defaultConfig;
3839
- if ((selectedContent == null ? void 0 : selectedContent.type) === ContentType.Component) {
3840
- const component = (_a = componentsRef.current) == null ? void 0 : _a.find(
3841
- (component2) => component2.id === selectedContent.id
3842
- );
3843
- if (component) {
3844
- code = component.code;
3845
- hasContent = true;
3846
- }
3847
- } else if ((selectedContent == null ? void 0 : selectedContent.type) === ContentType.PredefinedPage || (selectedContent == null ? void 0 : selectedContent.type) === ContentType.Page) {
3848
- const page = (_b = pagesRef.current) == null ? void 0 : _b.find(
3849
- (item) => item.id === selectedContent.id
3850
- );
3851
- defaultConfig = {
3852
- pageMeta: {
3853
- seoTitle: (_c = page == null ? void 0 : page.meta) == null ? void 0 : _c.seoTitle,
3854
- seoDescription: (_d = page == null ? void 0 : page.meta) == null ? void 0 : _d.seoDescription,
3855
- seoKeywords: (_e = page == null ? void 0 : page.meta) == null ? void 0 : _e.seoKeywords,
3856
- ogTitle: (_f = page == null ? void 0 : page.meta) == null ? void 0 : _f.ogTitle,
3857
- ogDescription: (_g = page == null ? void 0 : page.meta) == null ? void 0 : _g.ogDescription,
3858
- ogType: (_h = page == null ? void 0 : page.meta) == null ? void 0 : _h.ogType,
3859
- ogImage: (_i = page == null ? void 0 : page.meta) == null ? void 0 : _i.ogImage
3860
- }
3861
- };
3862
- if (page) {
3863
- code = page.code;
3864
- hasContent = true;
3865
- }
3866
- } else if ((selectedContent == null ? void 0 : selectedContent.type) === ContentType.Template) {
3867
- const template = (_j = templatesRef.current) == null ? void 0 : _j.find(
3868
- (template2) => template2.id === selectedContent.id
3869
- );
3870
- if (template) {
3871
- code = template.code;
3872
- hasContent = true;
3873
- }
3874
- }
3875
- if (code) {
3876
- transformCodeToSchema(code).then((value) => {
3877
- setSchema({
3878
- schema: { ...defaultSchema, children: (value == null ? void 0 : value.template) || [] },
3879
- config: { ...defaultConfig, ...value.resources }
3880
- });
3881
- });
3882
- } else if (hasContent) {
3883
- setSchema({
3884
- schema: { ...defaultSchema, children: [] }
3885
- });
3886
- }
3887
- }, [selectedContent == null ? void 0 : selectedContent.id, selectedContent == null ? void 0 : selectedContent.type]);
3888
- console.log("===>schema", schema);
3889
- return schema;
3890
- }
3891
3832
  const defaultDesktopWidth = 1280;
3892
3833
  const defaultTabletWidth = 800;
3893
3834
  const defaultMobileWidth = 480;
@@ -3963,74 +3904,6 @@ const bgColorState = atom({
3963
3904
  key: "studio.bgColor",
3964
3905
  default: "#ffffff"
3965
3906
  });
3966
- function useCloseDrawer() {
3967
- const setDrawerType = useSetRecoilState(drawerTypeState);
3968
- const drawerDocked = useRecoilValue(drawerDockedState);
3969
- const close = useCallback(() => {
3970
- if (!drawerDocked) {
3971
- setDrawerType(void 0);
3972
- }
3973
- }, [drawerDocked, setDrawerType]);
3974
- return close;
3975
- }
3976
- function useIsBaseLangTheme() {
3977
- var _a, _b;
3978
- const theme = useStudioTheme();
3979
- const website = useWebsite();
3980
- 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);
3981
- }
3982
- function useExportWebsite() {
3983
- const [isExporting, setIsExporting] = useState(false);
3984
- const setError = useSetRecoilState(globalErrorState);
3985
- const theme = useStudioTheme();
3986
- const save = useSave();
3987
- const getFiles = useGetFiles();
3988
- const addFilesToZip = useCallback(
3989
- (zip, files, currentPath = "") => {
3990
- for (const [name, content] of Object.entries(files)) {
3991
- const path = currentPath ? `${currentPath}/${name}` : name;
3992
- if (content.file && content.file.contents) {
3993
- zip.file(path, content.file.contents);
3994
- } else if (content.directory) {
3995
- const folder = zip.folder(path);
3996
- if (folder) {
3997
- addFilesToZip(folder, content.directory, "");
3998
- }
3999
- } else if (typeof content === "object" && content !== null) {
4000
- if (name === "src" || name === "public" || name === "components" || name === "pages") {
4001
- const folder = zip.folder(path);
4002
- if (folder) {
4003
- addFilesToZip(folder, content, "");
4004
- }
4005
- } else {
4006
- addFilesToZip(zip, content, path);
4007
- }
4008
- }
4009
- }
4010
- },
4011
- []
4012
- );
4013
- const exportWebsite = useCallback(async () => {
4014
- try {
4015
- if (theme == null ? void 0 : theme.id) {
4016
- setIsExporting(true);
4017
- const files = await getFiles(theme);
4018
- const zip = new JSZip();
4019
- console.log("开始导出文件...");
4020
- addFilesToZip(zip, files);
4021
- const content = await zip.generateAsync({ type: "blob" });
4022
- const fileName = `website-${theme.name || theme.id}-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`;
4023
- save(fileName, content);
4024
- }
4025
- } catch (e) {
4026
- console.error(e);
4027
- setError(e == null ? void 0 : e.message);
4028
- } finally {
4029
- setIsExporting(false);
4030
- }
4031
- }, [getFiles, save, setError, theme, addFilesToZip]);
4032
- return { exportWebsite, isExporting };
4033
- }
4034
3907
  var ThemeConfigType = /* @__PURE__ */ ((ThemeConfigType2) => {
4035
3908
  ThemeConfigType2["MultiLang"] = "multi-Lang";
4036
3909
  ThemeConfigType2["Tailwind"] = "tailwind";
@@ -4040,1045 +3913,1349 @@ var ThemeConfigType = /* @__PURE__ */ ((ThemeConfigType2) => {
4040
3913
  ThemeConfigType2["WebsiteInfo"] = "websiteInfo";
4041
3914
  ThemeConfigType2["EmailTemplates"] = "emailTemplates";
4042
3915
  ThemeConfigType2["Fonts"] = "fonts";
3916
+ ThemeConfigType2["Favicon"] = "favicon";
4043
3917
  return ThemeConfigType2;
4044
3918
  })(ThemeConfigType || {});
4045
- const inputClassNames$1 = {
4046
- label: "w-16 flex items-center ps-0 pe-0 shrink-0 justify-end pr-2 text-default-500",
4047
- base: "flex items-center px-0",
4048
- wrapper: "flex-1",
4049
- mainWrapper: "flex-1 pr-4"
4050
- };
4051
- function ExtendsTable(props) {
4052
- const { fields: fields2, onChange } = props;
4053
- const handleAddField = useCallback(() => {
4054
- onChange == null ? void 0 : onChange([...fields2 || [], {
4055
- name: "newField",
4056
- title: "新建字段",
4057
- type: ExtendFieldType.String,
4058
- component: ComponentType.Input
4059
- }]);
4060
- }, [fields2, onChange]);
4061
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4062
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4063
- Accordion,
4064
- {
4065
- isCompact: true,
4066
- children: (fields2 == null ? void 0 : fields2.map((field, index) => {
4067
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
4068
- AccordionItem,
4069
- {
4070
- classNames: {
4071
- title: "text-sm"
4072
- },
4073
- title: `#${index + 1} ${field.title || field.name}`,
4074
- children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2 px-3", children: [
4075
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4076
- Input$1,
4077
- {
4078
- variant: "flat",
4079
- value: field.name,
4080
- size: "sm",
4081
- label: "名称",
4082
- labelPlacement: "outside-left",
4083
- classNames: inputClassNames$1,
4084
- onChange: (e) => {
4085
- const newName = e.target.value;
4086
- onChange == null ? void 0 : onChange(fields2.map((field2, i2) => {
4087
- if (i2 === index) {
4088
- return {
4089
- ...field2,
4090
- name: newName
4091
- };
4092
- }
4093
- return field2;
4094
- }));
4095
- }
4096
- }
4097
- ),
4098
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4099
- Input$1,
4100
- {
4101
- label: "标题",
4102
- size: "sm",
4103
- variant: "flat",
4104
- value: field.title,
4105
- labelPlacement: "outside-left",
4106
- classNames: inputClassNames$1,
4107
- onChange: (e) => {
4108
- const newTitle = e.target.value;
4109
- onChange == null ? void 0 : onChange(fields2.map((field2, i2) => {
4110
- if (i2 === index) {
4111
- return {
4112
- ...field2,
4113
- title: newTitle
4114
- };
4115
- }
4116
- return field2;
4117
- }));
4118
- }
4119
- }
4120
- ),
4121
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
4122
- Select,
4123
- {
4124
- label: "类型",
4125
- size: "sm",
4126
- variant: "flat",
4127
- selectedKeys: field.type ? [field.type] : [],
4128
- labelPlacement: "outside-left",
4129
- classNames: inputClassNames$1,
4130
- onChange: (e) => {
4131
- onChange == null ? void 0 : onChange(fields2.map((field2, i2) => {
4132
- if (i2 === index) {
4133
- return {
4134
- ...field2,
4135
- type: e.target.value || void 0
4136
- };
4137
- }
4138
- return field2;
4139
- }));
4140
- },
4141
- children: [
4142
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "文本" }, ExtendFieldType.String),
4143
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "数字" }, ExtendFieldType.Number),
4144
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "布尔" }, ExtendFieldType.Boolean),
4145
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "JSON" }, ExtendFieldType.Json),
4146
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "日期" }, ExtendFieldType.Date)
4147
- ]
4148
- }
4149
- ),
4150
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
4151
- Select,
4152
- {
4153
- label: "编辑组件",
4154
- size: "sm",
4155
- variant: "flat",
4156
- selectedKeys: field.component ? [field.component] : [],
4157
- labelPlacement: "outside-left",
4158
- classNames: inputClassNames$1,
4159
- onChange: (e) => {
4160
- onChange == null ? void 0 : onChange(fields2.map((field2, i2) => {
4161
- if (i2 === index) {
4162
- return {
4163
- ...field2,
4164
- component: e.target.value || void 0
4165
- };
4166
- }
4167
- return field2;
4168
- }));
4169
- },
4170
- endContent: /* @__PURE__ */ jsxRuntimeExports.jsx(
4171
- Button$1,
4172
- {
4173
- as: "div",
4174
- size: "sm",
4175
- variant: "light",
4176
- isIconOnly: true,
4177
- className: "flex items-center justify-center",
4178
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(SettingsIcon, { className: "size-4" })
4179
- }
4180
- ),
4181
- children: [
4182
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "单行输入框" }, ComponentType.Input),
4183
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "数字入框" }, ComponentType.NumberInput),
4184
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "多行输入框" }, ComponentType.Textarea),
4185
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "开关" }, ComponentType.Switch),
4186
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "图片选择" }, ComponentType.ImageSelect),
4187
- /* @__PURE__ */ jsxRuntimeExports.jsx(SelectItem, { children: "链接目标" }, ComponentType.LinkTarget)
4188
- ]
4189
- }
4190
- ),
4191
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4192
- Button$1,
4193
- {
4194
- size: "sm",
4195
- variant: "light",
4196
- color: "danger",
4197
- onPress: () => {
4198
- onChange == null ? void 0 : onChange(fields2.filter((_2, i2) => i2 !== index));
4199
- },
4200
- children: "删除字段"
4201
- }
4202
- )
4203
- ] })
4204
- },
4205
- index
4206
- );
4207
- })) || []
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;
4208
3935
  }
4209
- ),
4210
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4211
- Button$1,
4212
- {
4213
- variant: "flat",
4214
- size: "sm",
4215
- className: "mt-2",
4216
- startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(AddIcon, { className: "size-5" }),
4217
- onPress: handleAddField,
4218
- 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);
4219
3945
  }
4220
- )
4221
- ] });
4222
- }
4223
- function PostPanel(props) {
4224
- 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
+ ]);
4225
3980
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
4226
- "div",
3981
+ Card,
4227
3982
  {
4228
- className: "flex flex-col gap-4 overflow-x-hidden py-2",
4229
- children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col gap-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4230
- ExtendsTable,
4231
- {
4232
- fields: settings == null ? void 0 : settings.fields,
4233
- onChange: (fields2) => {
4234
- onChange == null ? void 0 : onChange({
4235
- ...settings,
4236
- fields: fields2
4237
- });
4238
- }
4239
- }
4240
- ) })
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
+ ] }) })
4241
4026
  }
4242
4027
  );
4243
4028
  }
4244
- function ProductPanel(props) {
4245
- const { settings, onChange } = props;
4246
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
4247
- "div",
4248
- {
4249
- className: "flex flex-col gap-4 overflow-x-hidden py-2",
4250
- children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col gap-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4251
- ExtendsTable,
4252
- {
4253
- fields: settings == null ? void 0 : settings.fields,
4254
- onChange: (fields2) => {
4255
- onChange == null ? void 0 : onChange({
4256
- ...settings,
4257
- fields: fields2
4258
- });
4259
- }
4260
- }
4261
- ) })
4262
- }
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]
4263
4045
  );
4264
- }
4265
- function ExtendsPanel() {
4266
- const [themeSettings, setThemeSettings] = useState();
4267
- const initialSettings = useThemeSettings();
4268
- const webTheme = useStudioTheme();
4269
- const [save, { isMutating }] = useUpsertOneTheme();
4270
- const changed = useMemo(() => {
4271
- return JSON.stringify(themeSettings || {}) !== JSON.stringify(initialSettings || {});
4272
- }, [themeSettings, initialSettings]);
4273
- const handleReset = useCallback(() => {
4274
- setThemeSettings(initialSettings);
4275
- }, [initialSettings]);
4276
- const handleSave = useCallback(() => {
4277
- save({
4278
- id: webTheme == null ? void 0 : webTheme.id,
4279
- 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
4280
4070
  });
4281
- }, [save, themeSettings, webTheme == null ? void 0 : webTheme.id]);
4282
- useEffect(() => {
4283
- setThemeSettings(initialSettings);
4284
- }, [initialSettings]);
4285
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4286
- /* @__PURE__ */ jsxRuntimeExports.jsx(ModalBody, { className: "flex-1 min-h-0 overflow-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
4287
- 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",
4288
4084
  {
4289
- "aria-label": "extends",
4290
- className: "mt-2",
4291
- size: "sm",
4292
- children: [
4293
- /* @__PURE__ */ jsxRuntimeExports.jsx(Tab, { title: "产品", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4294
- 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",
4295
4091
  {
4296
- settings: themeSettings == null ? void 0 : themeSettings.product,
4297
- onChange: (settings) => {
4298
- setThemeSettings({
4299
- ...themeSettings,
4300
- product: settings
4301
- });
4302
- }
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"
4303
4095
  }
4304
- ) }, "product"),
4305
- /* @__PURE__ */ jsxRuntimeExports.jsx(Tab, { title: "文章", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4306
- PostPanel,
4096
+ ),
4097
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
4098
+ "path",
4307
4099
  {
4308
- settings: themeSettings == null ? void 0 : themeSettings.post,
4309
- onChange: (settings) => {
4310
- setThemeSettings({
4311
- ...themeSettings,
4312
- post: settings
4313
- });
4314
- }
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"
4315
4102
  }
4316
- ) }, "post")
4317
- ]
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
+ ] })
4318
4112
  }
4319
- ) }),
4320
- /* @__PURE__ */ jsxRuntimeExports.jsxs(ModalFooter, { children: [
4321
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4322
- Button$1,
4323
- {
4324
- size: "sm",
4325
- isDisabled: !changed,
4326
- onPress: handleReset,
4327
- children: "重置"
4328
- }
4329
- ),
4330
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4331
- Button$1,
4332
- {
4333
- size: "sm",
4334
- isDisabled: !changed,
4335
- isLoading: isMutating,
4336
- color: "primary",
4337
- onPress: handleSave,
4338
- children: "保存"
4339
- }
4340
- )
4341
- ] })
4342
- ] });
4343
- }
4344
- function newThemeConfigOptions(theme) {
4345
- return new ThemeConfigQueryOptions(
4346
- [
4347
- ThemeConfigFields.id,
4348
- ThemeConfigFields.emailTemplates,
4349
- ThemeConfigFields.address,
4350
- ThemeConfigFields.contact,
4351
- ThemeConfigFields.email,
4352
- ThemeConfigFields.tel,
4353
- ThemeConfigFields.fax,
4354
- ThemeConfigFields.mobile,
4355
- ThemeConfigFields.wechat,
4356
- ThemeConfigFields.websiteTitle
4357
- ],
4358
- {
4359
- where: {
4360
- [ThemeConfigAssciations.theme]: {
4361
- id: {
4362
- _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
+ ]
4363
4136
  }
4364
- }
4137
+ )
4365
4138
  }
4366
- }
4367
- ).contactAvatar(new MediaQueryOptions().file(["thumbnail", "url"])).setNoQuery(!(theme == null ? void 0 : theme.id));
4368
- }
4369
- function WebsiteInfoPanel(props) {
4370
- const { onSuccess } = props;
4371
- 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);
4372
4148
  const website = useWebsite();
4373
- const websiteId = website == null ? void 0 : website.id;
4374
- const { data: themeConfig2 } = useOneThemeConfig(newThemeConfigOptions(theme));
4375
- const [save, { isMutating }] = useUpsertOneThemeConfig({
4376
- onSuccess
4377
- });
4378
- const handleSave = useCallback(
4379
- (value) => {
4380
- if (!value)
4381
- return;
4382
- save(themeConfigToInputCascade(value));
4383
- },
4384
- [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
+ ])
4385
4169
  );
4386
- return /* @__PURE__ */ jsxRuntimeExports.jsx(ModalBody, { className: "flex-1 min-h-0 overflow-auto p-4 px-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
4387
- EntityForm,
4388
- {
4389
- entityName: ThemeConfigEntityName,
4390
- initialValue: themeConfig2 || {
4391
- [ThemeConfigAssciations.theme]: {
4392
- id: theme == null ? void 0 : theme.id
4393
- }
4394
- },
4395
- globalValidationErrorMessage: "部分输入项有错误,请检查",
4396
- isMutating,
4397
- onSubmit: handleSave,
4398
- children: [
4399
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-4", children: [
4400
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-4", children: [
4401
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4402
- 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,
4403
4284
  {
4404
- name: ThemeConfigFields.websiteTitle,
4405
- label: "网站标题",
4406
- labelPlacement: "outside",
4407
- placeholder: "请输入网站标题"
4408
- }
4409
- ),
4410
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2 mt-2", children: [
4411
- /* @__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
+ ) }),
4412
4325
  /* @__PURE__ */ jsxRuntimeExports.jsx(
4413
- MediaSingleSelectField,
4326
+ DropdownMenu,
4414
4327
  {
4415
- name: ThemeConfigAssciations.contactAvatar,
4416
- websiteId,
4417
- mediaTypes: [MediaType.image],
4418
- 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
+ )
4419
4350
  }
4420
4351
  )
4421
- ] }),
4422
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
4423
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4424
- 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,
4425
4359
  {
4426
- name: ThemeConfigFields.contact,
4427
- label: "联系人",
4428
- labelPlacement: "outside",
4429
- placeholder: "请输入联系人姓名"
4360
+ variant: "flat",
4361
+ startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(TaskStopIcon, { className: "size-5" }),
4362
+ onPress: handleStop,
4363
+ children: "停止"
4430
4364
  }
4431
4365
  ),
4432
4366
  /* @__PURE__ */ jsxRuntimeExports.jsx(
4433
- InputField,
4367
+ Button$1,
4434
4368
  {
4435
- name: ThemeConfigFields.tel,
4436
- label: "电话",
4437
- labelPlacement: "outside",
4438
- 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: "翻译 & 重置"
4439
4375
  }
4440
4376
  )
4441
4377
  ] })
4442
- ] }),
4443
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
4444
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4445
- InputField,
4446
- {
4447
- name: ThemeConfigFields.email,
4448
- label: "邮箱",
4449
- labelPlacement: "outside",
4450
- placeholder: "请输入联系邮箱"
4451
- }
4452
- ),
4453
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4454
- InputField,
4455
- {
4456
- name: ThemeConfigFields.mobile,
4457
- label: "手机",
4458
- labelPlacement: "outside",
4459
- placeholder: "请输入手机号码"
4460
- }
4461
- ),
4462
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4463
- InputField,
4464
- {
4465
- name: ThemeConfigFields.fax,
4466
- label: "传真",
4467
- labelPlacement: "outside",
4468
- placeholder: "请输入传真号码"
4469
- }
4470
- )
4471
- ] }),
4472
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4473
- 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,
4474
4389
  {
4475
- name: ThemeConfigFields.address,
4476
- label: "地址",
4477
- labelPlacement: "outside",
4478
- placeholder: "请输入详细地址"
4479
- }
4480
- ) })
4481
- ] }),
4482
- /* @__PURE__ */ jsxRuntimeExports.jsx(Divider, { className: "mt-4" }),
4483
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end mt-4", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SubmitButton, { size: "sm", variant: "solid", color: "primary", children: "保存" }) })
4484
- ]
4485
- }
4486
- ) });
4487
- }
4488
- function EmialTemplatesPanel(props) {
4489
- const { onSuccess } = props;
4490
- const theme = useStudioTheme();
4491
- const { data: themeConfig2 } = useOneThemeConfig(newThemeConfigOptions(theme));
4492
- const [save, { isMutating }] = useUpsertOneThemeConfig({
4493
- onSuccess
4494
- });
4495
- const handleSave = useCallback(
4496
- (value) => {
4497
- if (!value)
4498
- return;
4499
- save(themeConfigToInput(value));
4500
- },
4501
- [save]
4502
- );
4503
- return /* @__PURE__ */ jsxRuntimeExports.jsx(ModalBody, { className: "flex-1 min-h-0 overflow-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
4504
- EntityForm,
4505
- {
4506
- entityName: ThemeConfigEntityName,
4507
- initialValue: themeConfig2 || {
4508
- [ThemeConfigAssciations.theme]: {
4509
- id: theme == null ? void 0 : theme.id
4510
- }
4511
- },
4512
- globalValidationErrorMessage: "部分输入项有错误,请检查",
4513
- isMutating,
4514
- onSubmit: handleSave,
4515
- children: [
4516
- /* @__PURE__ */ jsxRuntimeExports.jsxs(ObjectField, { name: ThemeConfigFields.emailTemplates, children: [
4517
- /* @__PURE__ */ jsxRuntimeExports.jsx(ObjectField, { name: "customerEmail", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { className: "mt-2", children: [
4518
- /* @__PURE__ */ jsxRuntimeExports.jsxs(CardHeader, { className: "flex gap-2", children: [
4519
- /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { children: "客户通知邮件" }),
4520
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-default-500", children: "变量:$name" })
4521
- ] }),
4522
- /* @__PURE__ */ jsxRuntimeExports.jsx(Divider, {}),
4523
- /* @__PURE__ */ jsxRuntimeExports.jsxs(CardBody, { className: "gap-4", children: [
4524
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4525
- InputField,
4526
- {
4527
- name: "subject",
4528
- label: "标题",
4529
- labelPlacement: "outside",
4530
- placeholder: "请输入标题"
4531
- }
4532
- ),
4533
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4534
- TextareaField,
4535
- {
4536
- name: "content",
4537
- label: "内容",
4538
- minRows: 5,
4539
- labelPlacement: "outside",
4540
- placeholder: "请输入内容"
4541
- }
4542
- )
4543
- ] })
4544
- ] }) }),
4545
- /* @__PURE__ */ jsxRuntimeExports.jsx(ObjectField, { name: "employeeEmail", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { className: "mt-4", children: [
4546
- /* @__PURE__ */ jsxRuntimeExports.jsxs(CardHeader, { className: "flex gap-2", children: [
4547
- /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { children: "业务员通知邮件" }),
4548
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-default-500", children: "变量:$content" })
4549
- ] }),
4550
- /* @__PURE__ */ jsxRuntimeExports.jsx(Divider, {}),
4551
- /* @__PURE__ */ jsxRuntimeExports.jsxs(CardBody, { className: "gap-4", children: [
4552
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4553
- InputField,
4554
- {
4555
- name: "subject",
4556
- label: "标题",
4557
- labelPlacement: "outside",
4558
- placeholder: "请输入标题"
4559
- }
4560
- ),
4561
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4562
- TextareaField,
4563
- {
4564
- name: "content",
4565
- label: "内容",
4566
- minRows: 5,
4567
- labelPlacement: "outside",
4568
- placeholder: "请输入内容"
4569
- }
4570
- )
4571
- ] })
4572
- ] }) })
4573
- ] }),
4574
- /* @__PURE__ */ jsxRuntimeExports.jsx(Divider, { className: "mt-4" }),
4575
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end mt-4", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SubmitButton, { size: "sm", variant: "solid", color: "primary", children: "保存" }) })
4576
- ]
4577
- }
4578
- ) });
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
+ ] });
4579
4421
  }
4580
- function LangCard(props) {
4581
- var _a;
4582
- const { isSelected, isBaseLang, lang, onSelect } = props;
4583
- const website = useWebsite();
4584
- const [removing, setRemoving] = useState(false);
4585
- const [upsertWebsite, { isMutating }] = useUpsertOneWebsite();
4586
- const [currentLang, setCurrentLang] = useRecoilState(currentLangState);
4587
- const setSelectedContent = useSetRecoilState(selectedContentState);
4588
- const queryTheme = useLazyQueryOneEntity();
4589
- const [removeTheme] = useDeleteThemeById();
4590
- const handleDelete = useCallback(async () => {
4591
- var _a2, _b, _c;
4592
- try {
4593
- setRemoving(true);
4594
- if (((_a2 = website == null ? void 0 : website.baseLang) == null ? void 0 : _a2.id) === lang.id) {
4595
- 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
+ })) || []
4596
4585
  }
4597
- await upsertWebsite(
4598
- websiteToInput({
4599
- id: website == null ? void 0 : website.id,
4600
- langs: (_b = website == null ? void 0 : website.langs) == null ? void 0 : _b.filter((l2) => l2.id !== lang.id)
4601
- })
4602
- );
4603
- if (currentLang === lang.id) {
4604
- setCurrentLang((_c = website == null ? void 0 : website.baseLang) == null ? void 0 : _c.id);
4605
- 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: "添加"
4606
4596
  }
4607
- const langTheme = await queryTheme(
4608
- new ThemeQueryOptions([ThemeFields.id], {
4609
- where: {
4610
- website: {
4611
- id: {
4612
- _eq: website == null ? void 0 : website.id
4613
- }
4614
- },
4615
- lang: {
4616
- id: {
4617
- _eq: lang.id
4618
- }
4619
- }
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
+ });
4620
4615
  }
4621
- }).toGqlOptions()
4622
- );
4623
- if (langTheme.id) {
4624
- removeTheme(langTheme.id);
4625
- }
4626
- } finally {
4627
- setRemoving(false);
4616
+ }
4617
+ ) })
4628
4618
  }
4629
- }, [
4630
- currentLang,
4631
- lang.id,
4632
- queryTheme,
4633
- removeTheme,
4634
- setCurrentLang,
4635
- setSelectedContent,
4636
- upsertWebsite,
4637
- (_a = website == null ? void 0 : website.baseLang) == null ? void 0 : _a.id,
4638
- website == null ? void 0 : website.id,
4639
- website == null ? void 0 : website.langs
4640
- ]);
4619
+ );
4620
+ }
4621
+ function ProductPanel(props) {
4622
+ const { settings, onChange } = props;
4641
4623
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
4642
- Card,
4624
+ "div",
4643
4625
  {
4644
- shadow: "sm",
4645
- className: "bg-background cursor-pointer transition-colors group relative",
4646
- classNames: {
4647
- base: isSelected ? "outline-2 outline-primary" : "hover:bg-default-100"
4648
- },
4649
- isPressable: !removing,
4650
- as: "div",
4651
- isDisabled: removing,
4652
- onPress: () => onSelect(lang.id),
4653
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(CardBody, { className: "p-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
4654
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
4655
- lang.icon && /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { icon: lang.icon, className: "text-2xl shrink-0" }),
4656
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
4657
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
4658
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "font-medium truncate", children: lang.cnName }),
4659
- 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: "基准语言" }) })
4660
- ] }),
4661
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-default-500 truncate", children: lang.abbr })
4662
- ] })
4663
- ] }),
4664
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
4665
- isSelected && /* @__PURE__ */ jsxRuntimeExports.jsx(CheckCircleIcon, { className: "text-primary size-5 shrink-0" }),
4666
- !isBaseLang && !isMutating && /* @__PURE__ */ jsxRuntimeExports.jsx(
4667
- Button$1,
4668
- {
4669
- isIconOnly: true,
4670
- size: "sm",
4671
- variant: "light",
4672
- 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",
4673
- onPress: handleDelete,
4674
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(CloseIcon, { className: "size-4" })
4675
- }
4676
- ),
4677
- isMutating && /* @__PURE__ */ jsxRuntimeExports.jsx(
4678
- CircularProgress,
4679
- {
4680
- "aria-label": "Loading...",
4681
- size: "sm",
4682
- className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2"
4683
- }
4684
- )
4685
- ] })
4686
- ] }) })
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
+ ) })
4687
4639
  }
4688
4640
  );
4689
4641
  }
4690
- const TRANSLATE_THEME_KEY = "translate-theme";
4691
- function useTranslateThemeTask() {
4692
- const theme = useStudioTheme();
4693
- const lang = useCurrentLang();
4694
- const baseThemeId = useBaseLangThemeId();
4695
- const appKey = (theme == null ? void 0 : theme.id) || "";
4696
- const taskState = useInprogressTaskByKey(TRANSLATE_THEME_KEY, appKey);
4697
- const setTask = useUpdateTask(appKey);
4698
- const entifyClient = useCreateEntityClient();
4699
- const task = taskState && taskState.status !== "done" ? taskPool[taskState.taskId] : void 0;
4700
- const aiUrl = useAiUrl();
4701
- const handleTaskChange = useCallback(
4702
- (data) => {
4703
- setTask(data);
4704
- },
4705
- [setTask]
4706
- );
4707
- const translateAndReset = useCallback(() => {
4708
- if (!(theme == null ? void 0 : theme.id)) {
4709
- console.error("没设置Theme");
4710
- return;
4711
- }
4712
- if (!entifyClient) {
4713
- console.error("entifyClient 创建失败");
4714
- return;
4715
- }
4716
- if (!aiUrl) {
4717
- console.error("没设置aiUrl");
4718
- return;
4719
- }
4720
- if (!baseThemeId) {
4721
- console.error("没设置baseThemeId");
4722
- return;
4723
- }
4724
- const task2 = new TranslateThemeTask({
4725
- key: TRANSLATE_THEME_KEY,
4726
- entifyClient,
4727
- baseThemeId,
4728
- themeId: theme == null ? void 0 : theme.id,
4729
- lang,
4730
- 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
4731
4657
  });
4732
- taskPool[task2.id] = task2;
4733
- task2.onDataChange(handleTaskChange);
4734
- task2.start();
4735
- }, [aiUrl, baseThemeId, entifyClient, handleTaskChange, lang, theme == null ? void 0 : theme.id]);
4736
- return { taskState, translateAndReset, task };
4737
- }
4738
- const linkTypes = [
4739
- {
4740
- key: "path",
4741
- label: "子网址",
4742
- description: "例如:example.com/en",
4743
- icon: /* @__PURE__ */ jsxRuntimeExports.jsx(
4744
- "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,
4745
4665
  {
4746
- xmlns: "http://www.w3.org/2000/svg",
4747
- className: "size-5 text-default-500",
4748
- viewBox: "0 0 24 24",
4749
- children: /* @__PURE__ */ jsxRuntimeExports.jsxs("g", { fill: "none", children: [
4750
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4751
- "path",
4752
- {
4753
- stroke: "currentColor",
4754
- strokeWidth: 1.5,
4755
- 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"
4756
- }
4757
- ),
4758
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4759
- "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,
4760
4672
  {
4761
- fill: "currentColor",
4762
- 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
+ }
4763
4680
  }
4764
- ),
4765
- /* @__PURE__ */ jsxRuntimeExports.jsx(
4766
- "path",
4681
+ ) }, "product"),
4682
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Tab, { title: "文章", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4683
+ PostPanel,
4767
4684
  {
4768
- fill: "currentColor",
4769
- 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
+ }
4770
4692
  }
4771
- )
4772
- ] })
4773
- }
4774
- )
4775
- },
4776
- {
4777
- key: "subdomain",
4778
- label: "二级域名",
4779
- description: "例如:en.example.com",
4780
- icon: /* @__PURE__ */ jsxRuntimeExports.jsx(
4781
- "svg",
4782
- {
4783
- xmlns: "http://www.w3.org/2000/svg",
4784
- className: "size-5 text-default-500",
4785
- viewBox: "0 0 24 24",
4786
- children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
4787
- "g",
4788
- {
4789
- fill: "none",
4790
- stroke: "currentColor",
4791
- strokeLinecap: "round",
4792
- strokeWidth: 1.5,
4793
- children: [
4794
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M14 12a6 6 0 1 1-6-6" }),
4795
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M10 12a6 6 0 1 1 6 6" })
4796
- ]
4797
- }
4798
- )
4799
- }
4800
- )
4801
- }
4802
- ];
4803
- function MultiLangPanel() {
4804
- var _a, _b, _c, _d, _e, _f;
4805
- const [linkType, setLinkType] = useState("subdomain");
4806
- const [confirmOpen, setConfirmOpen] = useState(false);
4807
- const [currentLang, setCurrentLang] = useRecoilState(currentLangState);
4808
- const [selectedContent, setSelectedContent] = useRecoilState(selectedContentState);
4809
- const website = useWebsite();
4810
- const isChanginBaseLangRef = useRef(false);
4811
- const [upsertTheme, { isMutating: isCreating }] = useUpsertOneTheme();
4812
- const { taskState, task, translateAndReset } = useTranslateThemeTask();
4813
- useEffect(() => {
4814
- var _a2;
4815
- if (website && !currentLang) {
4816
- setCurrentLang((_a2 = website.baseLang) == null ? void 0 : _a2.id);
4817
- }
4818
- }, [currentLang, setCurrentLang, website]);
4819
- const { data: allLangs, isLoading: allLangsLoading } = useLangList(
4820
- new LangQueryOptions([
4821
- LangFields.id,
4822
- LangFields.abbr,
4823
- LangFields.enName,
4824
- LangFields.cnName,
4825
- LangFields.localName,
4826
- LangFields.description,
4827
- LangFields.circleIcon,
4828
- LangFields.icon
4829
- ])
4830
- );
4831
- const [upsertWebsite, { isMutating }] = useUpsertOneWebsite();
4832
- useEffect(() => {
4833
- if (!isMutating) {
4834
- isChanginBaseLangRef.current = false;
4835
- }
4836
- }, [isMutating]);
4837
- const handleBaseLangChange = useCallback(
4838
- (selection) => {
4839
- isChanginBaseLangRef.current = true;
4840
- upsertWebsite(
4841
- websiteToInput({
4842
- id: website == null ? void 0 : website.id,
4843
- [WebsiteAssciations.baseLang]: { id: selection.currentKey }
4844
- })
4845
- );
4846
- },
4847
- [upsertWebsite, website == null ? void 0 : website.id]
4848
- );
4849
- const handleLangSelect = useCallback(
4850
- (langId) => {
4851
- setCurrentLang(langId);
4852
- if ((selectedContent == null ? void 0 : selectedContent.id) && langId !== currentLang) {
4853
- setSelectedContent(void 0);
4693
+ ) }, "post")
4694
+ ]
4854
4695
  }
4855
- },
4856
- [selectedContent == null ? void 0 : selectedContent.id, setCurrentLang, setSelectedContent, currentLang]
4857
- );
4858
- const leftLangs = useMemo(() => {
4859
- var _a2;
4860
- return (_a2 = allLangs == null ? void 0 : allLangs.items) == null ? void 0 : _a2.filter(
4861
- (lang) => {
4862
- var _a3;
4863
- 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
+ }
4864
4743
  }
4865
- );
4866
- }, [allLangs, website]);
4867
- const handleAddLanguage = useCallback(
4868
- async (langId) => {
4869
- var _a2;
4870
- await upsertWebsite(
4871
- websiteToInput({
4872
- id: website == null ? void 0 : website.id,
4873
- [WebsiteAssciations.langs]: [
4874
- ...((_a2 = website == null ? void 0 : website.langs) == null ? void 0 : _a2.map((lang) => ({
4875
- id: lang.id
4876
- }))) || [],
4877
- { id: langId }
4878
- ]
4879
- })
4880
- );
4881
- if ((website == null ? void 0 : website.id) && langId) {
4882
- console.log("create theme");
4883
- await upsertTheme({
4884
- name: (website.name || "") + (langId || "") + "主题",
4885
- lang: {
4886
- sync: { id: langId }
4887
- },
4888
- website: {
4889
- 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
4890
4762
  }
4891
- });
4763
+ }
4892
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));
4893
4782
  },
4894
- [upsertTheme, upsertWebsite, website == null ? void 0 : website.id, website == null ? void 0 : website.langs, website == null ? void 0 : website.name]
4783
+ [save]
4895
4784
  );
4896
- const handleTranslate = useCallback(() => {
4897
- setConfirmOpen(true);
4898
- }, []);
4899
- const handleStop = useCallback(() => {
4900
- task == null ? void 0 : task.stop();
4901
- }, [task]);
4902
- const handleCloseConfirm = useCallback(() => {
4903
- setConfirmOpen(false);
4904
- }, []);
4905
- const handleConfirm = useCallback(() => {
4906
- translateAndReset();
4907
- }, [translateAndReset]);
4908
- const isRunning = (taskState == null ? void 0 : taskState.status) === "in-progress";
4909
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
4910
- /* @__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: [
4911
- /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { className: "bg-default-50", children: [
4912
- /* @__PURE__ */ jsxRuntimeExports.jsx(CardHeader, { className: "flex gap-3 px-6 pt-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col flex-grow", children: [
4913
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-lg font-semibold", children: "基准语言" }),
4914
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-small text-default-500", children: "从已启用的语言中选择网站的基准语言,作为翻译的原稿,默认为英文" })
4915
- ] }) }),
4916
- /* @__PURE__ */ jsxRuntimeExports.jsx(CardBody, { className: "px-6 pb-6", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4917
- Select,
4918
- {
4919
- label: "基准语言",
4920
- labelPlacement: "outside",
4921
- placeholder: "请选择网站基准的语言",
4922
- className: "max-w-sm",
4923
- selectedKeys: [((_a = website == null ? void 0 : website.baseLang) == null ? void 0 : _a.id) || ""],
4924
- isDisabled: (isMutating || isCreating) && isChanginBaseLangRef.current,
4925
- isLoading: (isMutating || isCreating) && isChanginBaseLangRef.current,
4926
- renderValue: (langValues) => {
4927
- return (langValues == null ? void 0 : langValues.map((langValue) => {
4928
- var _a2, _b2;
4929
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(
4930
- "div",
4931
- {
4932
- className: "flex items-center gap-2",
4933
- children: [
4934
- (_a2 = langValue == null ? void 0 : langValue.props) == null ? void 0 : _a2.startContent,
4935
- (_b2 = langValue == null ? void 0 : langValue.props) == null ? void 0 : _b2.children
4936
- ]
4937
- },
4938
- langValue == null ? void 0 : langValue.key
4939
- );
4940
- })) || [];
4941
- },
4942
- onSelectionChange: handleBaseLangChange,
4943
- children: ((_b = website == null ? void 0 : website.langs) == null ? void 0 : _b.map((lang) => /* @__PURE__ */ jsxRuntimeExports.jsx(
4944
- 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,
4945
4803
  {
4946
- startContent: lang.icon ? /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { icon: lang.icon, className: "text-xl" }) : null,
4947
- textValue: lang.abbr,
4948
- children: lang.cnName || lang.enName
4949
- },
4950
- lang.id
4951
- ))) || []
4952
- }
4953
- ) })
4954
- ] }),
4955
- /* @__PURE__ */ jsxRuntimeExports.jsxs(Card, { className: "bg-default-50", children: [
4956
- /* @__PURE__ */ jsxRuntimeExports.jsx(CardHeader, { className: "flex gap-3 px-6 pt-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col flex-grow", children: [
4957
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-lg font-semibold", children: "已启用的语言" }),
4958
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-small text-default-500", children: "管理网站支持的语言" })
4959
- ] }) }),
4960
- /* @__PURE__ */ jsxRuntimeExports.jsxs(CardBody, { className: "px-6 pb-6", children: [
4961
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid gap-4 md:grid-cols-2 ", children: [
4962
- (_c = website == null ? void 0 : website.langs) == null ? void 0 : _c.map((lang) => {
4963
- var _a2;
4964
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
4965
- 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,
4966
4825
  {
4967
- lang,
4968
- isSelected: currentLang === lang.id,
4969
- isBaseLang: ((_a2 = website == null ? void 0 : website.baseLang) == null ? void 0 : _a2.id) === lang.id,
4970
- onSelect: handleLangSelect
4971
- },
4972
- lang.id
4973
- );
4974
- }),
4975
- /* @__PURE__ */ jsxRuntimeExports.jsxs(Dropdown, { placement: "bottom-end", children: [
4976
- /* @__PURE__ */ jsxRuntimeExports.jsx(DropdownTrigger, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
4977
- 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,
4978
4937
  {
4979
- variant: "flat",
4980
- className: "h-[88px] bg-default-100 hover:bg-default-200 w-full",
4981
- startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(AddIcon, { className: "size-6 shrink-0" }),
4982
- isLoading: allLangsLoading || isMutating && !isChanginBaseLangRef.current,
4983
- children: "添加语言"
4938
+ name: "subject",
4939
+ label: "标题",
4940
+ labelPlacement: "outside",
4941
+ placeholder: "请输入标题"
4984
4942
  }
4985
- ) }),
4943
+ ),
4986
4944
  /* @__PURE__ */ jsxRuntimeExports.jsx(
4987
- DropdownMenu,
4945
+ TextareaField,
4988
4946
  {
4989
- "aria-label": "全部语言列表",
4990
- items: leftLangs,
4991
- className: "max-h-[300px] overflow-y-auto",
4992
- disallowEmptySelection: true,
4993
- selectionMode: "single",
4994
- onAction: handleAddLanguage,
4995
- children: (item) => /* @__PURE__ */ jsxRuntimeExports.jsx(
4996
- DropdownItem,
4997
- {
4998
- className: "gap-2",
4999
- startContent: item.icon ? /* @__PURE__ */ jsxRuntimeExports.jsx(
5000
- Icon,
5001
- {
5002
- icon: item.icon,
5003
- className: "text-xl shrink-0"
5004
- }
5005
- ) : null,
5006
- textValue: item.cnName || item.enName,
5007
- children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: item.cnName || item.enName })
5008
- },
5009
- item.id
5010
- )
4947
+ name: "content",
4948
+ label: "内容",
4949
+ minRows: 5,
4950
+ labelPlacement: "outside",
4951
+ placeholder: "请输入内容"
5011
4952
  }
5012
4953
  )
5013
4954
  ] })
5014
- ] }),
5015
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-6 flex items-center justify-between", children: [
5016
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-default-500", children: taskState == null ? void 0 : taskState.infoMessage }),
5017
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-end gap-2", children: [
5018
- isRunning && /* @__PURE__ */ jsxRuntimeExports.jsx(
5019
- 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,
5020
4965
  {
5021
- variant: "flat",
5022
- startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(TaskStopIcon, { className: "size-5" }),
5023
- onPress: handleStop,
5024
- children: "停止"
4966
+ name: "subject",
4967
+ label: "标题",
4968
+ labelPlacement: "outside",
4969
+ placeholder: "请输入标题"
5025
4970
  }
5026
4971
  ),
5027
4972
  /* @__PURE__ */ jsxRuntimeExports.jsx(
5028
- Button$1,
4973
+ TextareaField,
5029
4974
  {
5030
- color: "primary",
5031
- startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(AiStarIcon, { className: "size-5" }),
5032
- isDisabled: currentLang === ((_d = website == null ? void 0 : website.baseLang) == null ? void 0 : _d.id),
5033
- isLoading: isRunning,
5034
- onPress: handleTranslate,
5035
- children: "翻译 & 重置"
4975
+ name: "content",
4976
+ label: "内容",
4977
+ minRows: 5,
4978
+ labelPlacement: "outside",
4979
+ placeholder: "请输入内容"
5036
4980
  }
5037
4981
  )
5038
4982
  ] })
5039
- ] })
5040
- ] })
5041
- ] }),
5042
- !!((_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: [
5043
- /* @__PURE__ */ jsxRuntimeExports.jsx(CardHeader, { className: "flex gap-3 px-6 pt-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col flex-grow", children: [
5044
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-lg font-semibold", children: "链接方式" }),
5045
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-small text-default-500", children: "选择多语言网站的访问方式" })
5046
- ] }) }),
5047
- /* @__PURE__ */ jsxRuntimeExports.jsxs(CardBody, { className: "px-6 pb-6", children: [
5048
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid gap-4 md:grid-cols-2", children: linkTypes.map((type) => /* @__PURE__ */ jsxRuntimeExports.jsx(
5049
- Card,
5050
- {
5051
- shadow: "sm",
5052
- className: `bg-background cursor-pointer transition-colors ${linkType === type.key ? "border-2 border-primary" : "hover:bg-default-100"}`,
5053
- isPressable: type.key !== "path",
5054
- as: "div",
5055
- isDisabled: type.key === "path",
5056
- onPress: () => type.key !== "path" && setLinkType(type.key),
5057
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(CardBody, { className: "p-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
5058
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center size-10 rounded-lg bg-default-100", children: type.icon }),
5059
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1", children: [
5060
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "font-medium", children: type.label }),
5061
- /* @__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
+ )
5062
5183
  ] }),
5063
- linkType === type.key && /* @__PURE__ */ jsxRuntimeExports.jsx(CheckCircleIcon, { className: "text-primary size-5" })
5064
- ] }) })
5065
- },
5066
- type.key
5067
- )) }),
5068
- /* @__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: "保存" })
5069
5255
  ] })
5070
- ] })
5071
- ] }) }),
5072
- /* @__PURE__ */ jsxRuntimeExports.jsx(
5073
- ConfirmDialog,
5074
- {
5075
- open: confirmOpen,
5076
- onClose: handleCloseConfirm,
5077
- onConfirm: handleConfirm,
5078
- confirm: "翻译会重置并覆盖当前网站内容,不可撤销,您确定要翻译吗?"
5079
- }
5080
- )
5081
- ] });
5256
+ ]
5257
+ }
5258
+ ) }) });
5082
5259
  }
5083
5260
  function ConfigDrawer() {
5084
5261
  const [openSettingsType, setOpenSettingsType] = useRecoilState(configTypeState);
@@ -5093,6 +5270,7 @@ function ConfigDrawer() {
5093
5270
  onClose: () => setOpenSettingsType(void 0),
5094
5271
  children: [
5095
5272
  /* @__PURE__ */ jsxRuntimeExports.jsxs(ModalHeader, { className: "pr-2 h-12", children: [
5273
+ openSettingsType === ThemeConfigType.Favicon && "网站图标",
5096
5274
  openSettingsType === ThemeConfigType.MultiLang && "多语言配置",
5097
5275
  openSettingsType === ThemeConfigType.Tailwind && "Tailwind 配置",
5098
5276
  openSettingsType === ThemeConfigType.CSS && "自定义CSS",
@@ -5103,6 +5281,7 @@ function ConfigDrawer() {
5103
5281
  /* @__PURE__ */ jsxRuntimeExports.jsx(ModalClose, {})
5104
5282
  ] }),
5105
5283
  /* @__PURE__ */ jsxRuntimeExports.jsx(Divider, {}),
5284
+ openSettingsType === ThemeConfigType.Favicon && /* @__PURE__ */ jsxRuntimeExports.jsx(FaviconPanel, { onSuccess: () => setOpenSettingsType(void 0) }),
5106
5285
  openSettingsType === ThemeConfigType.MultiLang && /* @__PURE__ */ jsxRuntimeExports.jsx(MultiLangPanel, {}),
5107
5286
  openSettingsType === ThemeConfigType.Extends && /* @__PURE__ */ jsxRuntimeExports.jsx(ExtendsPanel, {}),
5108
5287
  openSettingsType === ThemeConfigType.WebsiteInfo && /* @__PURE__ */ jsxRuntimeExports.jsx(WebsiteInfoPanel, { onSuccess: () => setOpenSettingsType(void 0) }),
@@ -5210,7 +5389,7 @@ const ThemeSelectionStep = (props) => {
5210
5389
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm", children: "当前父主题:" }),
5211
5390
  parentTheme == null ? void 0 : parentTheme.name
5212
5391
  ] }),
5213
- (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: "选中的主题与父主题相同" })
5214
5393
  ] }),
5215
5394
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
5216
5395
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -6422,6 +6601,94 @@ const ThemeIcon = (props) => {
6422
6601
  }
6423
6602
  ) });
6424
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
+ }
6425
6692
  function MoreActions$1() {
6426
6693
  const {
6427
6694
  isOpen: isParentThemeOpen,
@@ -6471,6 +6738,15 @@ function MoreActions$1() {
6471
6738
  },
6472
6739
  ThemeConfigType.WebsiteInfo
6473
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
+ ),
6474
6750
  /* @__PURE__ */ jsxRuntimeExports.jsx(
6475
6751
  DropdownItem,
6476
6752
  {
@@ -12552,7 +12828,7 @@ function ViewModeButtons() {
12552
12828
  select: viewMode === ViewMode.Preview,
12553
12829
  isDisabled: !selectedContent,
12554
12830
  onPress: () => handleSetViewMode(ViewMode.Preview),
12555
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(PlayIcon, { className: "size-5" })
12831
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(PlayIcon, { className: "size-4" })
12556
12832
  }
12557
12833
  )
12558
12834
  ] });
@@ -12770,7 +13046,7 @@ const WebsiteToolbar = memo(() => {
12770
13046
  {
12771
13047
  className: `h-12 w-full flex px-0 justify-between items-center border-b border-divider`,
12772
13048
  children: [
12773
- /* @__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)) }) }),
12774
13050
  /* @__PURE__ */ jsxRuntimeExports.jsx(DeviceTabs, {}),
12775
13051
  /* @__PURE__ */ jsxRuntimeExports.jsxs(
12776
13052
  "div",
@@ -12878,10 +13154,129 @@ const SettingsForm = memo(() => {
12878
13154
  );
12879
13155
  });
12880
13156
  function MetaInfo() {
12881
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-2 px-4 text-sm text-default-500", children: [
12882
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "搜索引擎预览" }),
12883
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "社媒分享预览" }),
12884
- /* @__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
+ ] })
12885
13280
  ] });
12886
13281
  }
12887
13282
  const rightPanelWidth = "w-[22rem]";
@@ -15670,137 +16065,137 @@ function PagesPanel(props) {
15670
16065
  }
15671
16066
  function SEOPanel(props) {
15672
16067
  const { hidden } = props;
15673
- const [page, setEditingPage] = useRecoilState(editingPageState);
15674
- 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;
15675
16071
  const handleValueChange = useCallback(
15676
16072
  (values) => {
15677
- setEditingPage((page2) => ({
15678
- ...page2,
15679
- meta: {
15680
- ...page2 == null ? void 0 : page2.meta,
15681
- ...values
15682
- }
15683
- }));
15684
- setChanged(true);
16073
+ doc.setConfig({
16074
+ ...pageConfig || {},
16075
+ pageMeta: { ...pageConfig == null ? void 0 : pageConfig.pageMeta, ...values }
16076
+ });
15685
16077
  },
15686
- [setChanged, setEditingPage]
16078
+ [doc, pageConfig]
15687
16079
  );
15688
16080
  const initialValue = useMemo(
15689
- () => {
15690
- var _a, _b, _c;
15691
- return {
15692
- [PageMetaFields.seoTitle]: ((_a = page == null ? void 0 : page.meta) == null ? void 0 : _a.seoTitle) || "",
15693
- [PageMetaFields.seoKeywords]: ((_b = page == null ? void 0 : page.meta) == null ? void 0 : _b.seoKeywords) || "",
15694
- [PageMetaFields.seoDescription]: ((_c = page == null ? void 0 : page.meta) == null ? void 0 : _c.seoDescription) || ""
15695
- };
15696
- },
15697
- [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]
15698
16087
  );
15699
- return /* @__PURE__ */ jsxRuntimeExports.jsx(Form, { initialValue, onValueChange: handleValueChange, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(LeftPanel, { className: "p-4", hidden, children: [
15700
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1", children: [
15701
- /* @__PURE__ */ jsxRuntimeExports.jsx(TitleViewField, { name: PageMetaFields.seoTitle }),
15702
- /* @__PURE__ */ jsxRuntimeExports.jsx(DescriptionViewField, { name: PageMetaFields.seoDescription })
15703
- ] }),
15704
- /* @__PURE__ */ jsxRuntimeExports.jsx(
15705
- InputField,
15706
- {
15707
- name: PageMetaFields.seoTitle,
15708
- label: "标题",
15709
- labelPlacement: "outside",
15710
- placeholder: "请输入SEO标题"
15711
- }
15712
- ),
15713
- /* @__PURE__ */ jsxRuntimeExports.jsx(
15714
- TextareaField,
15715
- {
15716
- name: PageMetaFields.seoKeywords,
15717
- label: "关键词",
15718
- minRows: 2,
15719
- labelPlacement: "outside",
15720
- placeholder: "请输入SEO关键词"
15721
- }
15722
- ),
15723
- /* @__PURE__ */ jsxRuntimeExports.jsx(
15724
- TextareaField,
15725
- {
15726
- name: PageMetaFields.seoDescription,
15727
- label: "描述",
15728
- labelPlacement: "outside",
15729
- placeholder: "请输入SEO描述",
15730
- minRows: 3
15731
- }
15732
- )
15733
- ] }) });
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
+ ) });
15734
16131
  }
15735
16132
  function SNSPanel(props) {
15736
16133
  const { hidden } = props;
15737
16134
  const webSite = useWebsite();
15738
- const [page, setEditingPage] = useRecoilState(editingPageState);
15739
- const setChanged = useSetRecoilState(contentChangedState);
15740
- const handleValueChange = useCallback((values) => {
15741
- setEditingPage(
15742
- (page2) => ({
15743
- ...page2,
15744
- ...values
15745
- })
15746
- );
15747
- setChanged(true);
15748
- }, [setChanged, setEditingPage]);
15749
- const initialValue = useMemo(() => ({
15750
- [PageAssciations.ogImage]: page == null ? void 0 : page.ogImage,
15751
- [PageFields.ogTitle]: (page == null ? void 0 : page.ogTitle) || "",
15752
- [PageFields.ogDescription]: (page == null ? void 0 : page.ogDescription) || ""
15753
- }), [page]);
15754
- 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(
15755
16156
  Form,
15756
16157
  {
16158
+ className: "flex-1 flex flex-col gap-4",
15757
16159
  initialValue,
15758
16160
  onValueChange: handleValueChange,
15759
- children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
15760
- LeftPanel,
15761
- {
15762
- className: "p-4",
15763
- hidden,
15764
- children: [
15765
- /* @__PURE__ */ jsxRuntimeExports.jsx(
15766
- MediaSingleSelectField,
15767
- {
15768
- name: PageAssciations.ogImage,
15769
- label: "图片",
15770
- websiteId: webSite == null ? void 0 : webSite.id,
15771
- className: "aspect-[16/6]",
15772
- classNames: {
15773
- base: "flex-col"
15774
- },
15775
- width: "1200",
15776
- height: "630",
15777
- mediaTypes: [MediaType.image]
15778
- }
15779
- ),
15780
- /* @__PURE__ */ jsxRuntimeExports.jsx(
15781
- InputField,
15782
- {
15783
- name: PageFields.ogTitle,
15784
- label: "标题",
15785
- labelPlacement: "outside",
15786
- placeholder: "请输入社媒标题"
15787
- }
15788
- ),
15789
- /* @__PURE__ */ jsxRuntimeExports.jsx(
15790
- TextareaField,
15791
- {
15792
- name: PageFields.ogDescription,
15793
- label: "描述",
15794
- minRows: 3,
15795
- labelPlacement: "outside",
15796
- placeholder: "请输入社媒描述"
15797
- }
15798
- )
15799
- ]
15800
- }
15801
- )
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
+ ]
15802
16197
  }
15803
- );
16198
+ ) });
15804
16199
  }
15805
16200
  function LeftDrawerPannels() {
15806
16201
  const drawerType = useRecoilValue(drawerTypeState);
@@ -15922,436 +16317,172 @@ function ComponentModal(props) {
15922
16317
  labelPlacement: "outside",
15923
16318
  placeholder: "请输入顺序"
15924
16319
  }
15925
- )
15926
- ] })
15927
- }
15928
- );
15929
- }
15930
- function useRegisterComponent(component) {
15931
- const [rxProps, setRxProps] = React__default.useState();
15932
- const engine = useDesignerEngine();
15933
- const editingComponent = useRecoilValue(editingComponentState);
15934
- useEffect(() => {
15935
- var _a;
15936
- if (engine && (editingComponent == null ? void 0 : editingComponent.id) !== component.id && component.name) {
15937
- const newSlots = {};
15938
- const { children: childrenSlotNode, ...namedSlots } = component.slots || {};
15939
- for (const key in namedSlots) {
15940
- newSlots[key] = { ...namedSlots[key], componentName: slotContentName };
15941
- }
15942
- engine.getResourceManager().registerResources({
15943
- name: component.name,
15944
- title: component.title,
15945
- elements: [
15946
- {
15947
- componentName: component.name,
15948
- props: {
15949
- //默认属性配置
15950
- ...component.testConfig
15951
- },
15952
- //默认slots
15953
- slots: newSlots,
15954
- children: childrenSlotNode == null ? void 0 : childrenSlotNode.children
15955
- }
15956
- ]
15957
- });
15958
- const props = (_a = engine.getResourceManager().getResourceByName(component.name)) == null ? void 0 : _a.rxProps;
15959
- if (props) {
15960
- setRxProps(props);
15961
- }
15962
- return () => {
15963
- if (component.name) {
15964
- engine.getResourceManager().unregisterResources(component.name);
15965
- }
15966
- };
15967
- }
15968
- }, [component, editingComponent == null ? void 0 : editingComponent.id, engine]);
15969
- return rxProps;
15970
- }
15971
- function ComponentNode(props) {
15972
- const { component, readonly, selectedId, onSelect } = props;
15973
- const [open, setOpen] = React__default.useState(false);
15974
- const [remove, { isMutating }] = useRemoveRow();
15975
- const edit = useEditRow();
15976
- const rxProps = useRegisterComponent(component);
15977
- const handleOpenChange = React__default.useCallback((open2) => {
15978
- setOpen(open2);
15979
- }, []);
15980
- const handleDesign = React__default.useCallback(() => {
15981
- onSelect == null ? void 0 : onSelect(component.id || null);
15982
- }, [onSelect, component.id]);
15983
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
15984
- LeafNode,
15985
- {
15986
- fiexdAction: open || isMutating,
15987
- hover: open || isMutating,
15988
- icon: /* @__PURE__ */ jsxRuntimeExports.jsx(AstroIcon, { className: "size-4 mt-1" }),
15989
- className: "text-sm",
15990
- selected: selectedId === component.id,
15991
- actions: !readonly && /* @__PURE__ */ jsxRuntimeExports.jsxs(Dropdown, { onOpenChange: handleOpenChange, children: [
15992
- /* @__PURE__ */ jsxRuntimeExports.jsx(DropdownTrigger, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
15993
- Button$1,
15994
- {
15995
- isLoading: isMutating,
15996
- isIconOnly: true,
15997
- variant: "light",
15998
- size: "sm",
15999
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(
16000
- Icon,
16001
- {
16002
- icon: "mdi:more-horiz",
16003
- className: "size-5 text-default-600"
16004
- }
16005
- )
16006
- }
16007
- ) }),
16008
- /* @__PURE__ */ jsxRuntimeExports.jsxs(DropdownMenu, { "aria-label": "Actions", children: [
16009
- /* @__PURE__ */ jsxRuntimeExports.jsx(
16010
- DropdownItem,
16011
- {
16012
- onPress: handleDesign,
16013
- startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(DesignIcon, { className: "size-4" }),
16014
- children: "设计"
16015
- },
16016
- "design"
16017
- ),
16018
- /* @__PURE__ */ jsxRuntimeExports.jsx(
16019
- DropdownItem,
16020
- {
16021
- startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(EditIcon, { className: "size-4" }),
16022
- showDivider: true,
16023
- onPress: edit,
16024
- children: "编辑"
16025
- },
16026
- "edit"
16027
- ),
16028
- /* @__PURE__ */ jsxRuntimeExports.jsx(
16029
- DropdownItem,
16030
- {
16031
- color: "danger",
16032
- startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(RemoveIcon, { className: "size-4" }),
16033
- onPress: () => remove(),
16034
- children: "删除"
16035
- },
16036
- "remove"
16037
- )
16038
- ] })
16039
- ] }),
16040
- ...rxProps,
16041
- children: component.title || component.name
16042
- }
16043
- );
16044
- }
16045
- function ComponentList(props) {
16046
- var _a;
16047
- const { themeId, readonly, list, category, newComponent, noCagegory, selectedId, onSelect, onClearNewComponent } = props;
16048
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(
16049
- EntityListScope,
16050
- {
16051
- entityName: FrontComponentEntityName,
16052
- data: list,
16053
- children: [
16054
- (_a = list == null ? void 0 : list.items) == null ? void 0 : _a.map((item) => {
16055
- return /* @__PURE__ */ jsxRuntimeExports.jsx(EntityRowScope, { row: item, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
16056
- ComponentNode,
16057
- {
16058
- component: item,
16059
- readonly,
16060
- selectedId,
16061
- categoryId: category == null ? void 0 : category.id,
16062
- onSelect
16063
- }
16064
- ) }, item.id);
16065
- }),
16066
- !readonly && /* @__PURE__ */ jsxRuntimeExports.jsx(
16067
- ComponentModal,
16068
- {
16069
- themeId,
16070
- value: newComponent,
16071
- noCagegory,
16072
- onClose: onClearNewComponent,
16073
- categoryId: category == null ? void 0 : category.id
16074
- }
16075
- )
16076
- ]
16077
- }
16078
- );
16079
- }
16080
- function ComponentsSkeletons() {
16081
- 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)) }) });
16082
- }
16083
- const IMPORT_COMPONENTS_KEY = "import-components";
16084
- function useComponentsImportTask(categoryId) {
16085
- const theme = useStudioTheme();
16086
- const lang = useCurrentLang();
16087
- const components = useFrontComponents();
16088
- const appKey = (theme == null ? void 0 : theme.id) || "";
16089
- const taskState = useInprogressTaskByKey(
16090
- IMPORT_COMPONENTS_KEY + (categoryId || ""),
16091
- appKey
16092
- );
16093
- const setTask = useUpdateTask(appKey);
16094
- const setTaskRef = useRef(setTask);
16095
- setTaskRef.current = setTask;
16096
- const entifyClient = useCreateEntityClient();
16097
- const task = taskState && taskState.status !== "done" ? taskPool[taskState.taskId] : void 0;
16098
- const aiUrl = useAiUrl();
16099
- const handleTaskChange = useCallback((data) => {
16100
- setTaskRef.current(data);
16101
- }, []);
16102
- const importComponents = useCallback(
16103
- (ids, categoryId2, needTranslate) => {
16104
- if (!(theme == null ? void 0 : theme.id)) {
16105
- console.error("没设置Theme");
16106
- return;
16107
- }
16108
- if (!entifyClient) {
16109
- console.error("entifyClient 创建失败");
16110
- return;
16111
- }
16112
- if (!aiUrl) {
16113
- console.error("没设置aiUrl");
16114
- return;
16115
- }
16116
- const task2 = new ImportComponentsTask(
16117
- {
16118
- key: IMPORT_COMPONENTS_KEY + (categoryId2 || ""),
16119
- ids,
16120
- entifyClient,
16121
- needTranslate,
16122
- themeId: theme == null ? void 0 : theme.id,
16123
- lang,
16124
- aiUrl,
16125
- categoryId: categoryId2
16126
- },
16127
- components || []
16128
- );
16129
- taskPool[task2.id] = task2;
16130
- task2.onDataChange(handleTaskChange);
16131
- task2.start();
16132
- },
16133
- [aiUrl, entifyClient, handleTaskChange, lang, components, theme == null ? void 0 : theme.id]
16134
- );
16135
- return { taskState, importComponents, task };
16136
- }
16137
- function ImportComponentModal({
16138
- categoryId,
16139
- open,
16140
- onClose
16141
- }) {
16142
- const [selection, setSelections] = useState([]);
16143
- const [confirmTitle, setConfirmTitle] = useState(
16144
- void 0
16145
- );
16146
- const baseThemeId = useBaseLangThemeId();
16147
- const isBaseTheme = useIsBaseLangTheme();
16148
- const parentTheme = useParentTheme();
16149
- const themeComs = useFrontComponents();
16150
- const { taskState, importComponents, task } = useComponentsImportTask(
16151
- categoryId || ""
16152
- );
16153
- useEffect(() => {
16154
- var _a;
16155
- setSelections == null ? void 0 : setSelections(((_a = taskState == null ? void 0 : taskState.data) == null ? void 0 : _a.ids) || []);
16156
- }, [setSelections, taskState == null ? void 0 : taskState.data]);
16157
- useEffect(() => {
16158
- if ((taskState == null ? void 0 : taskState.status) === "done") {
16159
- setSelections == null ? void 0 : setSelections([]);
16160
- }
16161
- }, [setSelections, taskState]);
16162
- const confirmResolveRef = useRef();
16163
- const { data: baseTheme, isLoading } = useOneThemeById(
16164
- baseThemeId || void 0,
16165
- new ThemeQueryOptions([ThemeFields.id, ThemeFields.name]).componentCategories([
16166
- ComponentCategoryFields.id,
16167
- ComponentCategoryFields.name
16168
- ]).components(
16169
- new FrontComponentQueryOptions([
16170
- FrontComponentFields.id,
16171
- FrontComponentFields.name,
16172
- FrontComponentFields.title,
16173
- FrontComponentFields.code,
16174
- FrontComponentFields.props,
16175
- FrontComponentFields.testConfig
16176
- ]).category()
16177
- )
16320
+ )
16321
+ ] })
16322
+ }
16178
16323
  );
16179
- const categories = useMemo(() => {
16180
- return !isBaseTheme ? (baseTheme == null ? void 0 : baseTheme.componentCategories) || [] : (parentTheme == null ? void 0 : parentTheme.componentCategories) || [];
16181
- }, [
16182
- baseTheme == null ? void 0 : baseTheme.componentCategories,
16183
- parentTheme == null ? void 0 : parentTheme.componentCategories,
16184
- isBaseTheme
16185
- ]);
16186
- const components = useMemo(() => {
16187
- return !isBaseTheme ? (baseTheme == null ? void 0 : baseTheme.components) || [] : (parentTheme == null ? void 0 : parentTheme.components) || [];
16188
- }, [baseTheme == null ? void 0 : baseTheme.components, parentTheme == null ? void 0 : parentTheme.components, isBaseTheme]);
16189
- const noCategoryComponents = useMemo(() => {
16190
- return components.filter((component) => {
16191
- var _a;
16192
- return !((_a = component.category) == null ? void 0 : _a.id);
16193
- });
16194
- }, [components]);
16195
- const handleToggleSelect = React__default.useCallback((id) => {
16196
- setSelections((prev) => {
16197
- if (prev.includes(id)) {
16198
- return prev.filter((item) => item !== id);
16199
- } else {
16200
- 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 };
16201
16336
  }
16202
- });
16203
- }, []);
16204
- const handleConfirm = useCallback(() => {
16205
- setConfirmTitle(void 0);
16206
- if (confirmResolveRef.current) {
16207
- confirmResolveRef.current(true);
16208
- confirmResolveRef.current = void 0;
16209
- }
16210
- }, []);
16211
- const confirmOverride = useCallback(async (count) => {
16212
- setConfirmTitle(`${count} 个组件已存在,要全部覆盖吗?`);
16213
- return new Promise((resolve) => {
16214
- confirmResolveRef.current = resolve;
16215
- });
16216
- }, []);
16217
- const handleImport = useCallback(async () => {
16218
- const comsToImport = components.filter(
16219
- (c) => selection.includes(c.id || "")
16220
- );
16221
- const existings = themeComs == null ? void 0 : themeComs.filter(
16222
- (c) => comsToImport == null ? void 0 : comsToImport.find((com) => c.name === com.name)
16223
- );
16224
- if (existings == null ? void 0 : existings.length) {
16225
- const result = await confirmOverride(existings.length);
16226
- if (!result) {
16227
- 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);
16228
16356
  }
16357
+ return () => {
16358
+ if (component.name) {
16359
+ engine.getResourceManager().unregisterResources(component.name);
16360
+ }
16361
+ };
16229
16362
  }
16230
- importComponents(selection, categoryId || void 0, !isBaseTheme);
16231
- }, [
16232
- categoryId,
16233
- components,
16234
- confirmOverride,
16235
- importComponents,
16236
- isBaseTheme,
16237
- selection,
16238
- themeComs
16239
- ]);
16240
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(Modal, { isOpen: open, onClose, children: [
16241
- /* @__PURE__ */ jsxRuntimeExports.jsx(ModalOverlay, { className: "z-10" }),
16242
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
16243
- ModalContent,
16244
- {
16245
- className: "h-[80vh] shadow-lg border border-divider z-10",
16246
- width: 600,
16247
- children: [
16248
- /* @__PURE__ */ jsxRuntimeExports.jsxs(ModalHeader, { className: "pr-3", children: [
16249
- "转入组件",
16250
- /* @__PURE__ */ jsxRuntimeExports.jsx(ModalClose, {})
16251
- ] }),
16252
- /* @__PURE__ */ jsxRuntimeExports.jsx(Divider, {}),
16253
- /* @__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: [
16254
- categories == null ? void 0 : categories.map((category) => /* @__PURE__ */ jsxRuntimeExports.jsx(GroupNode, { title: category.name, icon: false, children: components.filter(
16255
- (component) => {
16256
- var _a;
16257
- return ((_a = component.category) == null ? void 0 : _a.id) === category.id;
16258
- }
16259
- ).map((component) => /* @__PURE__ */ jsxRuntimeExports.jsx(
16260
- LeafNode,
16261
- {
16262
- icon: /* @__PURE__ */ jsxRuntimeExports.jsx(
16263
- Checkbox,
16264
- {
16265
- isSelected: selection.includes(component.id || ""),
16266
- onValueChange: () => handleToggleSelect(component.id || "")
16267
- }
16268
- ),
16269
- onClick: () => handleToggleSelect(component.id || ""),
16270
- children: component.title || component.name
16271
- },
16272
- component.id
16273
- )) }, category.id)),
16274
- noCategoryComponents.map((component) => /* @__PURE__ */ jsxRuntimeExports.jsx(
16275
- 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,
16276
16396
  {
16277
- icon: /* @__PURE__ */ jsxRuntimeExports.jsx(
16278
- Checkbox,
16279
- {
16280
- isSelected: selection.includes(component.id || ""),
16281
- onValueChange: () => handleToggleSelect(component.id || "")
16282
- }
16283
- ),
16284
- onClick: () => handleToggleSelect(component.id || ""),
16285
- children: component.title || component.name
16286
- },
16287
- component.id
16288
- ))
16289
- ] }) }),
16290
- /* @__PURE__ */ jsxRuntimeExports.jsx(Divider, {}),
16291
- /* @__PURE__ */ jsxRuntimeExports.jsxs(ModalFooter, { className: "justify-between", children: [
16292
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-default-500 flex items-center gap-2", children: [
16293
- selection.length > 0 && (taskState == null ? void 0 : taskState.status) !== "in-progress" ? `${selection.length}个组件选中` : "",
16294
- taskState == null ? void 0 : taskState.infoMessage,
16295
- (taskState == null ? void 0 : taskState.status) === "in-progress" && /* @__PURE__ */ jsxRuntimeExports.jsx(
16296
- Button$1,
16297
- {
16298
- variant: "light",
16299
- size: "sm",
16300
- isIconOnly: true,
16301
- onPress: () => {
16302
- task == null ? void 0 : task.stop();
16303
- },
16304
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(TaskStopIcon, { className: "size-9 text-primary" })
16305
- }
16306
- )
16307
- ] }),
16308
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
16309
- /* @__PURE__ */ jsxRuntimeExports.jsx(Button$1, { variant: "light", onPress: onClose, children: "关闭" }),
16310
- /* @__PURE__ */ jsxRuntimeExports.jsx(
16311
- Button$1,
16312
- {
16313
- variant: "solid",
16314
- color: "primary",
16315
- onPress: handleImport,
16316
- isLoading: (taskState == null ? void 0 : taskState.status) === "in-progress",
16317
- children: "转入"
16318
- }
16319
- )
16320
- ] })
16321
- ] }),
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: [
16322
16404
  /* @__PURE__ */ jsxRuntimeExports.jsx(
16323
- 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,
16324
16452
  {
16325
- open: !!confirmTitle,
16326
- onClose: () => {
16327
- setConfirmTitle(void 0);
16328
- if (confirmResolveRef.current) {
16329
- confirmResolveRef.current(false);
16330
- confirmResolveRef.current = void 0;
16331
- }
16332
- },
16333
- onConfirm: handleConfirm,
16334
- confirm: confirmTitle
16453
+ component: item,
16454
+ readonly,
16455
+ selectedId,
16456
+ categoryId: category == null ? void 0 : category.id,
16457
+ onSelect
16335
16458
  }
16336
- )
16337
- ]
16338
- }
16339
- )
16340
- ] });
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
+ );
16341
16474
  }
16342
16475
  const ComponentCategoryNode = memo(
16343
16476
  (props) => {
16344
16477
  var _a;
16345
16478
  const { category, themeId, readonly, selectedId, onSelect } = props;
16346
16479
  const [open, setOpen] = React__default.useState(false);
16347
- const [comModalOpen, setComModalOpen] = React__default.useState(false);
16348
16480
  const website = useWebsite();
16349
16481
  const [remove, { isMutating }] = useRemoveRow({
16350
16482
  onSuccess: () => {
16351
16483
  emitEntityChange(FrontComponentEntityName);
16352
16484
  }
16353
16485
  });
16354
- const { taskState } = useComponentsImportTask((category == null ? void 0 : category.id) || "");
16355
16486
  const [newComponent, setNewComponent] = React__default.useState();
16356
16487
  const edit = useEditRow();
16357
16488
  const components = useFrontComponents();
@@ -16381,107 +16512,87 @@ const ComponentCategoryNode = memo(
16381
16512
  items: componentsInCategory
16382
16513
  };
16383
16514
  }, [componentsInCategory]);
16384
- const running = (taskState == null ? void 0 : taskState.status) === "in-progress";
16385
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
16386
- /* @__PURE__ */ jsxRuntimeExports.jsx(
16387
- GroupNode,
16388
- {
16389
- title: category.name,
16390
- fiexdAction: open || isMutating || running,
16391
- icon: null,
16392
- classNames: {
16393
- title: "text-sm"
16394
- },
16395
- defaultExpanded: !!((_a = data.items) == null ? void 0 : _a.find((item) => item.id === selectedId)),
16396
- action: !readonly && /* @__PURE__ */ jsxRuntimeExports.jsxs(Dropdown, { onOpenChange: handleOpenChange, children: [
16397
- /* @__PURE__ */ jsxRuntimeExports.jsx(DropdownTrigger, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
16398
- Button$1,
16399
- {
16400
- isLoading: isMutating || running,
16401
- isIconOnly: true,
16402
- variant: "light",
16403
- size: "sm",
16404
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(
16405
- 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,
16406
16550
  {
16407
- icon: "mdi:more-horiz",
16408
- className: "size-5 text-default-600"
16409
- }
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"
16410
16576
  )
16411
- }
16412
- ) }),
16413
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
16414
- DropdownMenu,
16415
- {
16416
- "aria-label": "Actions",
16417
- disabledKeys: (website == null ? void 0 : website.id) ? void 0 : ["import"],
16418
- children: [
16419
- /* @__PURE__ */ jsxRuntimeExports.jsx(
16420
- DropdownItem,
16421
- {
16422
- startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(AddIcon, { className: "size-4" }),
16423
- onPress: handleNewComponent,
16424
- children: "添加组件"
16425
- },
16426
- "add"
16427
- ),
16428
- /* @__PURE__ */ jsxRuntimeExports.jsx(
16429
- DropdownItem,
16430
- {
16431
- startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(ImportIcon, { className: "size-4" }),
16432
- onPress: () => setComModalOpen(true),
16433
- children: "转入组件"
16434
- },
16435
- "import"
16436
- ),
16437
- /* @__PURE__ */ jsxRuntimeExports.jsx(
16438
- DropdownItem,
16439
- {
16440
- startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(EditIcon, { className: "size-4" }),
16441
- showDivider: true,
16442
- onPress: handleEdit,
16443
- children: "编辑"
16444
- },
16445
- "edit"
16446
- ),
16447
- /* @__PURE__ */ jsxRuntimeExports.jsx(
16448
- DropdownItem,
16449
- {
16450
- color: "danger",
16451
- startContent: /* @__PURE__ */ jsxRuntimeExports.jsx(RemoveIcon, { className: "size-4" }),
16452
- onPress: () => remove(),
16453
- children: "删除"
16454
- },
16455
- "remove"
16456
- )
16457
- ]
16458
- }
16459
- )
16460
- ] }),
16461
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(
16462
- ComponentList,
16463
- {
16464
- category,
16465
- themeId,
16466
- readonly,
16467
- list: data,
16468
- newComponent,
16469
- selectedId,
16470
- onSelect,
16471
- onClearNewComponent: () => setNewComponent(void 0)
16577
+ ]
16472
16578
  }
16473
16579
  )
16474
- }
16475
- ),
16476
- /* @__PURE__ */ jsxRuntimeExports.jsx(
16477
- ImportComponentModal,
16478
- {
16479
- open: comModalOpen,
16480
- categoryId: category.id,
16481
- onClose: () => setComModalOpen(false)
16482
- }
16483
- )
16484
- ] });
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
+ ) });
16485
16596
  }
16486
16597
  );
16487
16598
  function ComponentCategoryList(props) {
@@ -16945,53 +17056,318 @@ function MaterialNodeView(props) {
16945
17056
  }
16946
17057
  );
16947
17058
  }
16948
- function WebComponents() {
16949
- return /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: resourceTreeNodes.map((node) => {
16950
- return /* @__PURE__ */ jsxRuntimeExports.jsx(MaterialNodeView, { node }, node.title);
16951
- }) });
16952
- }
16953
- function ComponentCategoryModal(props) {
16954
- const { themeId, onClose } = props;
16955
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
16956
- EntityEditModal,
16957
- {
16958
- entityName: ComponentCategoryEntityName,
16959
- entityLabel: "组件分类",
16960
- initialValue: {
16961
- theme: { id: themeId }
16962
- },
16963
- classNames: {
16964
- content: "max-w-sm"
16965
- },
16966
- entityToInput: componentCategoryToInput,
16967
- onClose,
16968
- children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-4", children: [
16969
- /* @__PURE__ */ jsxRuntimeExports.jsx(
16970
- InputField,
16971
- {
16972
- name: "name",
16973
- label: "名称",
16974
- validateSchema: {
16975
- type: "string",
16976
- required: true
16977
- },
16978
- labelPlacement: "outside",
16979
- placeholder: "请输入名称"
16980
- }
16981
- ),
16982
- /* @__PURE__ */ jsxRuntimeExports.jsx(
16983
- InputField,
16984
- {
16985
- name: "seqValue",
16986
- label: "顺序",
16987
- type: "number",
16988
- labelPlacement: "outside",
16989
- placeholder: "请输入顺序"
16990
- }
16991
- )
16992
- ] })
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([]);
16993
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
+ )
16994
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
+ ] });
16995
17371
  }
16996
17372
  function ComponentsRootNode(props) {
16997
17373
  const { themeId, readonly, selectedContent, onSelectContent } = props;
@@ -17802,6 +18178,15 @@ function MoreActions() {
17802
18178
  },
17803
18179
  ThemeConfigType.WebsiteInfo
17804
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
+ ),
17805
18190
  /* @__PURE__ */ jsxRuntimeExports.jsx(
17806
18191
  DropdownItem,
17807
18192
  {