diff --git a/package.json b/package.json index 06e75a5dd..c20c74153 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "webgal-terre", - "version": "4.4.8", + "version": "4.4.9", "private": true, "scripts": { "dev": "concurrently \"yarn dev:terre\" \"yarn dev:origine\" \"yarn dev:start-dev-server\"", diff --git a/packages/dev-server/index.js b/packages/dev-server/index.js index d9c9be64d..200248dee 100644 --- a/packages/dev-server/index.js +++ b/packages/dev-server/index.js @@ -1,12 +1,17 @@ const express = require("express"); const { createProxyMiddleware } = require("http-proxy-middleware"); +const { env } = require("process") + const app = express(); app.set("port", "80"); -app.all("*", function(req, res, next) { +app.all("*", function (req, res, next) { // 解决跨域问题 res.header("Access-Control-Allow-Origin", "*"); - res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With"); + res.header( + "Access-Control-Allow-Headers", + "Content-Type,Content-Length, Authorization, Accept,X-Requested-With" + ); res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS"); if (req.method === "OPTIONS") { res.send(200); @@ -15,21 +20,32 @@ app.all("*", function(req, res, next) { } }); -app.use(createProxyMiddleware("/api", { - target: "http://localhost:3001",// http代理跨域目标接口 - changeOrigin: true -})); +let WEBGAL_PORT = 3000; // default port +if (env.WEBGAL_PORT) { + WEBGAL_PORT = Number.parseInt(env.WEBGAL_PORT); +} + +app.use( + createProxyMiddleware("/api", { + target: `http://localhost:${WEBGAL_PORT + 1}`, // http代理跨域目标接口 + changeOrigin: true, + }) +); -app.use(createProxyMiddleware("/games", { - target: "http://localhost:3001",// http代理跨域目标接口 - changeOrigin: true, -})); +app.use( + createProxyMiddleware("/games", { + target: `http://localhost:${WEBGAL_PORT + 1}`, // http代理跨域目标接口 + changeOrigin: true, + }) +); -app.use(createProxyMiddleware("/", { - target: "http://localhost:3000",// http代理跨域目标接口 - ws:true, - changeOrigin: true -})); +app.use( + createProxyMiddleware("/", { + target: `http://localhost:${WEBGAL_PORT}`, // http代理跨域目标接口 + ws: true, + changeOrigin: true, + }) +); app.listen(app.get("port"), () => { console.log(`反向代理已开启,端口:${app.get("port")}`); diff --git a/packages/origine2/openapi.ts b/packages/origine2/openapi.ts index 084d1c9f1..3f40b6974 100644 --- a/packages/origine2/openapi.ts +++ b/packages/origine2/openapi.ts @@ -4,9 +4,15 @@ import axios from 'axios'; import {writeFileSync} from 'fs'; -import { exec } from 'child_process'; +import { exec } from 'child_process' +import { env } from 'process'; -const SWAGGER_URL = 'http://localhost:3001/api-json'; +let WEBGAL_PORT = 3000; // default port +if (env.WEBGAL_PORT) { + WEBGAL_PORT = Number.parseInt(env.WEBGAL_PORT); +}; + +const SWAGGER_URL = `http://localhost:${WEBGAL_PORT + 1}/api-json`; const SWAGGER_JSON_PATH = './src/config/swagger.json'; const API_OUTPUT_PATH = './src/api'; diff --git a/packages/origine2/package.json b/packages/origine2/package.json index ec3240466..8f98e0f81 100644 --- a/packages/origine2/package.json +++ b/packages/origine2/package.json @@ -1,10 +1,10 @@ { "name": "webgal-origine-2", "private": true, - "version": "4.4.8", + "version": "4.4.9", "license": "MPL-2.0", "scripts": { - "dev": "vite --port=3000 --host", + "dev": "vite --host", "build": "node version-sync.js && tsc && vite build --base=./", "build-lowram": "node version-sync.js && tsc && node --max_old_space_size=512000 ./node_modules/bin/vite build --base=./", "preview": "vite preview", @@ -13,6 +13,8 @@ }, "dependencies": { "@fluentui/react": "^8.77.3", + "@fluentui/react-components": "^9.44.1", + "@fluentui/react-icons": "^2.0.224", "@fluentui/react-icons-mdl2": "^1.3.41", "@icon-park/react": "^1.4.2", "@monaco-editor/react": "^4.4.5", diff --git a/packages/origine2/src/App.css b/packages/origine2/src/App.css index 9f450a33d..f74f5f48c 100644 --- a/packages/origine2/src/App.css +++ b/packages/origine2/src/App.css @@ -1,5 +1,8 @@ .App { text-align: center; + background-color: #fafafa; + width: 100%; + height: 100%; } .App-logo { diff --git a/packages/origine2/src/App.tsx b/packages/origine2/src/App.tsx index 7ac2f8cd3..6ce7071af 100644 --- a/packages/origine2/src/App.tsx +++ b/packages/origine2/src/App.tsx @@ -51,9 +51,10 @@ function App() { }, triggerCharacters: ["-", "", ":", "\n"] }); }); + return ( // 将编辑器的根元素占满整个视口 -
+
diff --git a/packages/origine2/src/config/info.ts b/packages/origine2/src/config/info.ts index 0263c20f6..47e3f9cad 100644 --- a/packages/origine2/src/config/info.ts +++ b/packages/origine2/src/config/info.ts @@ -4,6 +4,6 @@ export interface Info { } export const __INFO: Info = { - version: '4.4.8', + version: '4.4.9', buildTime: '2023-12-30T03:22:49.651Z', // 编译时会通过 version-sync.js 自动更新 }; diff --git a/packages/origine2/src/hooks/useExpand.ts b/packages/origine2/src/hooks/useExpand.ts new file mode 100644 index 000000000..ffe38666b --- /dev/null +++ b/packages/origine2/src/hooks/useExpand.ts @@ -0,0 +1,10 @@ +import {useDispatch, useSelector} from "react-redux"; +import {RootState} from "@/store/origineStore"; +import {updateGraphicalEditorCurrentExpandSentence} from "@/store/statusReducer"; + +export function useExpand() { + const currentExpandSentence = useSelector((state: RootState) => state.status.editor.graphicalEditorState.currentExpandSentence); + const dispatch = useDispatch(); + const updateIndex = (index:number)=>dispatch(updateGraphicalEditorCurrentExpandSentence(index)); + return {expandIndex:currentExpandSentence,updateExpandIndex:updateIndex}; +} diff --git a/packages/origine2/src/main.tsx b/packages/origine2/src/main.tsx index 1c7611a4f..4f1444222 100644 --- a/packages/origine2/src/main.tsx +++ b/packages/origine2/src/main.tsx @@ -10,6 +10,37 @@ import { jp } from "./translations/jp"; import 'primereact/resources/themes/fluent-light/theme.css'; import "primereact/resources/primereact.min.css"; import "./primereact.scss"; +import { BrandVariants, createLightTheme, createDarkTheme, FluentProvider, makeStyles, Theme } from "@fluentui/react-components"; + +const terre: BrandVariants = { + 10: "#020306", + 20: "#111725", + 30: "#152642", + 40: "#17325A", + 50: "#163E73", + 60: "#124B8D", + 70: "#0558A8", + 80: "#2A65B4", + 90: "#4672BC", + 100: "#5D80C3", + 110: "#728ECA", + 120: "#859CD1", + 130: "#98ABD8", + 140: "#ABB9DF", + 150: "#BEC8E7", + 160: "#D0D7EE" +}; + +const lightTheme: Theme = { + ...createLightTheme(terre), +}; + +const darkTheme: Theme = { + ...createDarkTheme(terre), +}; + +darkTheme.colorBrandForeground1 = terre[110]; +darkTheme.colorBrandForeground2 = terre[120]; function initTranslation() { i18n.use(initReactI18next) // passes i18n down to react-i18next @@ -38,6 +69,8 @@ initializeIcons(); // 不用 StrictMode,因为会和 react-butiful-dnd 冲突 ReactDOM.createRoot(document.getElementById("root")!).render( // - + + + // ); diff --git a/packages/origine2/src/pages/dashboard/About.tsx b/packages/origine2/src/pages/dashboard/About.tsx index 3d392aacb..2f5faeaa8 100644 --- a/packages/origine2/src/pages/dashboard/About.tsx +++ b/packages/origine2/src/pages/dashboard/About.tsx @@ -1,12 +1,11 @@ import * as React from 'react'; -import { Callout, Link, Text } from '@fluentui/react'; -import { useBoolean, useId } from '@fluentui/react-hooks'; -import { CommandBarButton } from '@fluentui/react/lib/Button'; -import styles from './about.module.scss'; import { __INFO } from "@/config/info"; import { useRelease } from "../../hooks/useRelease"; import { logger } from '@/utils/logger'; import useTrans from '@/hooks/useTrans'; +import { Link, Popover, PopoverSurface, PopoverTrigger, Text, Title1, ToolbarButton } from '@fluentui/react-components'; +import { Info24Filled, Info24Regular, bundleIcon } from '@fluentui/react-icons'; +import { useState } from 'react'; interface DateTimeFormatOptions { year: 'numeric' | '2-digit'; @@ -15,15 +14,12 @@ interface DateTimeFormatOptions { } const About: React.FunctionComponent = () => { - const [isCalloutVisible, { toggle: toggleIsCalloutVisible }] = useBoolean(false); - const buttonId = useId('callout-button'); - const labelId = useId('callout-label'); - const descriptionId = useId('callout-description'); - + const [open, setOpen] = useState(false); const t = useTrans('editor.topBar.'); - const latestRelease = useRelease(); + const InfoIcon = bundleIcon(Info24Filled, Info24Regular); + /** * 比较版本号 * @param latestVersion 最新版本 @@ -60,29 +56,23 @@ const About: React.FunctionComponent = () => { const dateTimeOptions: DateTimeFormatOptions = { year: 'numeric', month: '2-digit', day: '2-digit' }; return ( - <> - - {isCalloutVisible && - - + setOpen(!open)} + > + + }> + {t('about.about')} {isNewRelease ? `(${t('about.checkedForNewVersion')})` : ''} + + + +
+ WebGAL Terre - +

{t('about.slogan')}

{t('about.currentVersion')}: {`${__INFO.version} (${new Date(__INFO.buildTime).toLocaleString('zh-CN', dateTimeOptions).replaceAll('/', '-')})`}
@@ -95,7 +85,7 @@ const About: React.FunctionComponent = () => {

{ isNewRelease && - + {t('about.downloadLatest')} } @@ -109,20 +99,20 @@ const About: React.FunctionComponent = () => {

-
- +
+ {t('about.homePage')} - + {t('about.document')} - + GitHub
- - } - +
+ + ); }; diff --git a/packages/origine2/src/pages/dashboard/DashBoard.tsx b/packages/origine2/src/pages/dashboard/DashBoard.tsx index 89f7f8fa3..c9bd9a918 100644 --- a/packages/origine2/src/pages/dashboard/DashBoard.tsx +++ b/packages/origine2/src/pages/dashboard/DashBoard.tsx @@ -5,15 +5,16 @@ import { logger } from "../../utils/logger"; import { Message, TestRefRef } from "../../components/message/Message"; import styles from "./dashboard.module.scss"; import Sidebar from "./Sidebar"; -import { GamePreview } from "./GamePreview"; +import GamePreview from "./GamePreview"; import { useSelector } from "react-redux"; -import { origineStore, RootState } from "../../store/origineStore"; +import { RootState } from "../../store/origineStore"; import useTrans from "@/hooks/useTrans"; import useLanguage from "@/hooks/useLanguage"; -import { CommandBar, ICommandBarItemProps } from "@fluentui/react"; import { language } from "@/store/statusReducer"; import About from "./About"; import { WebgalParser } from "../editor/GraphicalEditor/parser"; +import { Card, Menu, MenuItem, MenuList, MenuPopover, MenuTrigger, Toolbar, ToolbarButton } from "@fluentui/react-components"; +import { LocalLanguage24Filled, LocalLanguage24Regular, bundleIcon } from "@fluentui/react-icons"; // 返回的文件信息(单个) interface IFileInfo { @@ -33,6 +34,8 @@ export default function DashBoard() { const setLanguage = useLanguage(); const trans = useTrans('dashBoard.'); + const LocalLanguageIcon = bundleIcon(LocalLanguage24Filled, LocalLanguage24Regular); + const isDashboardShow:boolean = useSelector((state: RootState) => state.status.dashboard.showDashBoard); const messageRef = useRef(null); @@ -83,68 +86,53 @@ export default function DashBoard() { refreashDashboard(); }, []); - const _items: ICommandBarItemProps[] = [ - { - key: "language", - text: t('commandBar.items.language.text'), - cacheKey: 'language', - iconProps: { iconName: 'LocaleLanguage'}, - subMenuProps: { - items: [ - { - key: 'zhCn', - text: '简体中文', - onClick() {setLanguage(language.zhCn);} - }, - { - key: 'en', - text: 'English', - onClick() {setLanguage(language.en);} - }, - { - key: 'jp', - text: '日本語', - onClick() {setLanguage(language.jp);} - } - ] - } - }, - ]; - const refreash = () => { refreashDashboard(); setCurrentGame(null); }; return <> - { isDashboardShow && (
-
+ { isDashboardShow && +
+
WebGAL Terre -
- + + + + + }>{t('commandBar.items.language.text')} + + + + setLanguage(language.zhCn)}>简体中文 + setLanguage(language.en)}>English + setLanguage(language.jp)}>日本语 + + + + +
+
+ +
+ + { + currentGame.value && + e.dir === currentGame.value)!} + /> + } + +
+
- -
-
- - - {currentGame.value && - e.dir === currentGame.value)!}/>} - {/* 测试新建游戏 */} -
-
)} +
} ; } diff --git a/packages/origine2/src/pages/dashboard/GameElement.tsx b/packages/origine2/src/pages/dashboard/GameElement.tsx index bb18f0258..1e3052c3b 100644 --- a/packages/origine2/src/pages/dashboard/GameElement.tsx +++ b/packages/origine2/src/pages/dashboard/GameElement.tsx @@ -1,5 +1,4 @@ import styles from "./gameElement.module.scss"; -import { CommandBarButton, DefaultButton, Dialog, DialogFooter, DialogType, IContextualMenuProps, PrimaryButton, Stack, TextField } from "@fluentui/react"; import axios from "axios"; import { useDispatch } from "react-redux"; import { setDashboardShow, setEditingGame } from "../../store/statusReducer"; @@ -7,12 +6,14 @@ import { useValue } from "../../hooks/useValue"; import useVarTrans from "@/hooks/useVarTrans"; import { GameInfo } from "./DashBoard"; import { useMemo } from "react"; -import {api} from "@/api"; +import { api } from "@/api"; +import { Button, Dialog, DialogActions, DialogBody, DialogContent, DialogSurface, DialogTitle, Input, Menu, MenuButton, MenuItem, MenuList, MenuPopover, MenuTrigger } from "@fluentui/react-components"; +import { Delete24Filled, Delete24Regular, FolderOpen24Filled, FolderOpen24Regular, MoreVertical24Filled, MoreVertical24Regular, Open24Filled, Open24Regular, Rename24Filled, Rename24Regular, bundleIcon } from "@fluentui/react-icons"; interface IGameElementProps { gameInfo: GameInfo; checked: boolean; - onClick: Function; + onClick: () => void; refreash?: () => void; } @@ -22,10 +23,16 @@ export default function GameElement(props: IGameElementProps) { const t = useVarTrans('dashBoard.'); const dispatch = useDispatch(); - function enterEditor(gameName: string) { + const MoreVerticalIcon = bundleIcon(MoreVertical24Filled, MoreVertical24Regular); + const FolderOpenIcon = bundleIcon(FolderOpen24Filled, FolderOpen24Regular); + const OpenIcon = bundleIcon(Open24Filled, Open24Regular); + const RenameIcon = bundleIcon(Rename24Filled, Rename24Regular); + const DeleteIcon = bundleIcon(Delete24Filled, Delete24Regular); + + const enterEditor = (gameName: string) => { dispatch(setEditingGame(gameName)); dispatch(setDashboardShow(false)); - } + }; let className = styles.gameElement_main; if (props.checked) { @@ -47,46 +54,6 @@ export default function GameElement(props: IGameElementProps) { const isShowRenameDialog = useValue(false); const newGameName = useValue(props.gameInfo.dir); - const deleteDialogContentProps = { - type: DialogType.normal, - title: t('dialogs.deleteGame.title'), - subText: t('dialogs.deleteGame.subtext', {gameName: props.gameInfo.dir}), - }; - - const renameDialogContentProps = { - type: DialogType.normal, - title: t('dialogs.renameDir.title'), - }; - - const menuProps: IContextualMenuProps = { - items: [ - { - key: 'openInFileExplorer', - text: t('menu.openInFileExplorer'), - iconProps: { iconName: 'OpenFolderHorizontal' }, - onClick: () => openInFileExplorer(), - }, - { - key: 'previewInNewTab', - text: t('menu.previewInNewTab'), - iconProps: { iconName: 'OpenInNewTab' }, - onClick: () => previewInNewTab(), - }, - { - key: 'renameDir', - text: t('menu.renameDir'), - iconProps: { iconName: 'Rename' }, - onClick: () => isShowRenameDialog.set(true), - }, - { - key: 'deleteGame', - text: t('menu.deleteGame'), - iconProps: { iconName: 'Delete' }, - onClick: () => isShowDeleteDialog.set(true), - }, - ], - }; - const openInFileExplorer = () => { api.manageGameControllerOpenGameDict(props.gameInfo.dir); }; @@ -113,56 +80,76 @@ export default function GameElement(props: IGameElementProps) { ); }; - // @ts-ignore - return
- {props.gameInfo.title} -
- {props.gameInfo.title} -
-
- {props.gameInfo.dir} -
- enterEditor(props.gameInfo.dir)} className={styles.editGameButton}>{t('preview.editGame')} - - - + return ( + <> +
+ {props.gameInfo.title} +
+ {props.gameInfo.title} +
+
+ {props.gameInfo.dir} +
event.stopPropagation()}> + + + + } /> + + + + } onClick={() => openInFileExplorer()}>{t('menu.openInFileExplorer')} + } onClick={() => previewInNewTab()}>{t('menu.previewInNewTab')} + } onClick={() => isShowRenameDialog.set(true)}>{t('menu.renameDir')} + } onClick={() => isShowDeleteDialog.set(true)}>{t('menu.deleteGame')} + + + +
+
-
- {/* 删除对话框 */} - - {/* 重命名对话框 */} - -
; + {/* 重命名对话框 */} + isShowRenameDialog.set(!isShowRenameDialog.value)} + > + + + {t('dialogs.renameDir.title')} + + newGameName.set(event.target.value ? event.target.value.trim() : props.gameInfo.dir)} + onKeyDown={(event) => (event.key === 'Enter') && renameThisGame(props.gameInfo.dir, newGameName.value)} + /> + + + + + + + + + {/* 删除对话框 */} + isShowDeleteDialog.set(!isShowDeleteDialog.value)} + > + + + {t('dialogs.deleteGame.title')} + {t('dialogs.deleteGame.subtext', { gameName: props.gameInfo.dir })} + + + + + + + + + ); }; diff --git a/packages/origine2/src/pages/dashboard/GamePreview.tsx b/packages/origine2/src/pages/dashboard/GamePreview.tsx index ec303cb89..58cf89ed9 100644 --- a/packages/origine2/src/pages/dashboard/GamePreview.tsx +++ b/packages/origine2/src/pages/dashboard/GamePreview.tsx @@ -3,7 +3,8 @@ import { useDispatch } from "react-redux"; import { setDashboardShow, setEditingGame } from "../../store/statusReducer"; import useTrans from "@/hooks/useTrans"; import { GameInfo } from './DashBoard'; -import { IconButton } from "@fluentui/react"; +import { Button } from "@fluentui/react-components"; +import { Dismiss48Filled, Dismiss48Regular, bundleIcon } from "@fluentui/react-icons"; interface IGamePreviewProps { currentGame: string; @@ -11,26 +12,22 @@ interface IGamePreviewProps { gameInfo: GameInfo; } -export function GamePreview(props: IGamePreviewProps) { +export default function GamePreview(props: IGamePreviewProps) { const t = useTrans('dashBoard.preview.'); const dispatch = useDispatch(); + + const DismissIcon = bundleIcon(Dismiss48Filled, Dismiss48Regular); + if (props.currentGame === null) { return
{t('noneChecked')}
; } - function enterEditor(gameName: string) { - dispatch(setEditingGame(gameName)); - dispatch(setDashboardShow(false)); - } - return
- props.setCurrentGame(null)} /> - {/* enterEditor(props.currentGame.dir)} className={styles.editGameButton}>{t('editGame')} */} {props.gameInfo.title} - +
{/* eslint-disable-next-line react/iframe-missing-sandbox */}