diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 00000000..b6ac8dac Binary files /dev/null and b/.DS_Store differ diff --git a/docker-conf/.DS_Store b/docker-conf/.DS_Store new file mode 100644 index 00000000..570de7d0 Binary files /dev/null and b/docker-conf/.DS_Store differ diff --git a/docker-conf/conf.d/.DS_Store b/docker-conf/conf.d/.DS_Store new file mode 100644 index 00000000..2ba47ba0 Binary files /dev/null and b/docker-conf/conf.d/.DS_Store differ diff --git a/docker-conf/conf.d/nginx.conf b/docker-conf/conf.d/nginx.conf index 338cb330..e5789512 100644 --- a/docker-conf/conf.d/nginx.conf +++ b/docker-conf/conf.d/nginx.conf @@ -17,6 +17,7 @@ server { return 301 /competition.html?competition_id=13; } +<<<<<<< HEAD # Brotli 压缩 WebAssembly 文件处理 location ~* \.wasm\.br$ { default_type ""; @@ -32,13 +33,51 @@ server { add_header Content-Type application/javascript always; add_header Vary Accept-Encoding; expires 30d; +======= + # Unity 预压缩文件:禁止再次 gzip,避免 Content-Length 与实际内容不一致 + location ~* \.wasm\.br$ { + gzip off; + default_type application/wasm; + add_header Content-Encoding br; + add_header Content-Type application/wasm always; + add_header Vary Accept-Encoding; + add_header Accept-Ranges bytes; + expires 1h; + } + + location ~* \.js\.br$ { + gzip off; + default_type application/javascript; + add_header Content-Encoding br; + add_header Content-Type application/javascript always; + add_header Vary Accept-Encoding; + add_header Accept-Ranges bytes; + expires 1h; + } + + location ~* \.data\.br$ { + gzip off; + default_type application/octet-stream; + add_header Content-Encoding br; + add_header Vary Accept-Encoding; + add_header Accept-Ranges bytes; + expires 1h; +>>>>>>> cocos-main } # 通用 Brotli 文件处理 location ~* \.br$ { +<<<<<<< HEAD add_header Content-Encoding br; add_header Vary Accept-Encoding; expires 30d; +======= + gzip off; + add_header Content-Encoding br; + add_header Vary Accept-Encoding; + add_header Accept-Ranges bytes; + expires 1h; +>>>>>>> cocos-main } # 静态资源缓存配置 diff --git a/nginx.conf b/nginx.conf index feca8597..1706092a 100644 --- a/nginx.conf +++ b/nginx.conf @@ -37,9 +37,12 @@ server { # 通用 Brotli 文件处理 location ~* \.br$ { + gzip off; + gzip_static off; add_header Content-Encoding br; add_header Vary Accept-Encoding; - expires 30d; + add_header Accept-Ranges bytes; + expires 1h; } # 静态资源缓存配置 @@ -78,4 +81,4 @@ server { # 错误日志和访问日志配置 access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; -} \ No newline at end of file +} diff --git a/scratch-gui/competitio_login/index.html b/scratch-gui/competitio_login/index.html index 28543ab5..02d883f4 100644 --- a/scratch-gui/competitio_login/index.html +++ b/scratch-gui/competitio_login/index.html @@ -383,8 +383,8 @@ diff --git a/scratch-gui/src/components/menu-bar/menu-bar.css b/scratch-gui/src/components/menu-bar/menu-bar.css index be345f46..1ea53d98 100644 --- a/scratch-gui/src/components/menu-bar/menu-bar.css +++ b/scratch-gui/src/components/menu-bar/menu-bar.css @@ -235,52 +235,70 @@ } .startButton { - background-color: white; - color: inherit; + background: linear-gradient(135deg, #22c55e, #16a34a); + color: #fff; border: none; - padding: 10px 20px; + padding: 10px 22px; text-align: center; text-decoration: none; display: inline-block; - /* font-size: 16px; */ + font-weight: 600; + font-size: 14px; margin: 4px 2px; cursor: pointer; - transition: background-color 0.3s, transform 0.2s, box-shadow 0.3s; - border-radius: 4px; - animation: pulse 2s infinite; /* 添加吸引注意的动画 */ + transition: all 0.3s ease; + border-radius: 6px; + box-shadow: 0 2px 8px rgba(34, 197, 94, 0.3); + letter-spacing: 0.5px; } .startButton:hover { - background-color: #56b9b7; /* 悬停时颜色加深 */ - transform: scale(1.05); /* 悬停时略微放大 */ - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); /* 添加阴影 */ + background: linear-gradient(135deg, #16a34a, #15803d); + transform: scale(1.04); + box-shadow: 0 4px 16px rgba(34, 197, 94, 0.45); } .startButton:active { - background-color: #279a98; /* 点击时颜色进一步加深 */ - transform: scale(0.98); /* 点击时略微缩小 */ - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); /* 减少阴影 */ -} - -/* 定义吸引注意的动画 */ -@keyframes pulse { - 0% { - transform: scale(1); - } - 50% { - transform: scale(1.05); - } - 100% { - transform: scale(1); - } + background: linear-gradient(135deg, #15803d, #166534); + transform: scale(0.97); + box-shadow: 0 2px 6px rgba(34, 197, 94, 0.35); } /* 可选:在点击后停止动画并改变样式 */ .startButtonClicked { - background-color: #ff9800; /* 点击后颜色变为橙色 */ - transform: scale(1.1); /* 点击后稍微放大 */ - box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3); /* 增加阴影 */ - animation: none; /* 停止动画 */ + background: linear-gradient(135deg, #f59e0b, #d97706); + transform: scale(1.05); + box-shadow: 0 6px 12px rgba(245, 158, 11, 0.4); +} + +.interruptButton { + background: linear-gradient(135deg, #ef4444, #dc2626); + color: #fff; + border: none; + padding: 10px 22px; + text-align: center; + text-decoration: none; + display: inline-block; + font-weight: 600; + font-size: 14px; + margin: 4px 8px; + cursor: pointer; + transition: all 0.3s ease; + border-radius: 6px; + box-shadow: 0 2px 8px rgba(239, 68, 68, 0.3); + letter-spacing: 0.5px; +} + +.interruptButton:hover { + background: linear-gradient(135deg, #dc2626, #b91c1c); + transform: scale(1.04); + box-shadow: 0 4px 16px rgba(239, 68, 68, 0.45); +} + +.interruptButton:active { + background: linear-gradient(135deg, #b91c1c, #991b1b); + transform: scale(0.97); + box-shadow: 0 2px 6px rgba(239, 68, 68, 0.35); } .lvcount{ diff --git a/scratch-gui/src/components/menu-bar/menu-bar.jsx b/scratch-gui/src/components/menu-bar/menu-bar.jsx index 29617a3b..6f601169 100644 --- a/scratch-gui/src/components/menu-bar/menu-bar.jsx +++ b/scratch-gui/src/components/menu-bar/menu-bar.jsx @@ -246,8 +246,10 @@ class MenuBar extends React.Component { 'restoreOptionMessage', 'handleClickStart', 'handleClickStopAll', + 'handleClickInterrupt', 'handleFeedbackClick', 'handleCloseModal', + 'handleOpenNoPermissionModal', 'handleCloseVideoModal', 'handlelearnVideoClick', 'handleVideoLoaded', @@ -262,6 +264,7 @@ class MenuBar extends React.Component { showAntiAddictionMsg: false, antiAddictionMsg: '', showModal: false, + showNoPermissionModal: false, showVideoModal: false, currentLevel: window.gamelvdata ? window.gamelvdata.currentlv : '', currentGameId: window.gamelvdata ? window.gamelvdata.gameid : '', @@ -582,9 +585,15 @@ class MenuBar extends React.Component { window.vm.stopAll(); } + handleOpenNoPermissionModal() { + this.setState({ showNoPermissionModal: true }); + } + handleCloseModal() { - // 设置 showModal 为 false 以隐藏模态窗口 - this.setState({ showModal: false }); + this.setState({ showModal: false, showNoPermissionModal: false }); + if (window.location.hash === '#carousel_ac25') { + history.replaceState(null, document.title, window.location.pathname + window.location.search); + } } // 打开视频模态窗口 @@ -843,7 +852,7 @@ class MenuBar extends React.Component { let realLvId_tmp = ''; // 发送消息给 Unity 实例,切换关卡 if (localStorage.getItem('platformMode') === 'normal') { - realLvId_tmp = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber, window.gamelvdataJson.gamemode) + window.gamelvdata.currentlv; + realLvId_tmp = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber) + window.gamelvdata.currentlv; } else { realLvId_tmp = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber); } @@ -875,6 +884,42 @@ class MenuBar extends React.Component { } + handleClickInterrupt() { + console.log('取消执行按钮点击'); + // 1. 终止所有代码执行 + try { this.props.vm.stopAll(); } catch (e) { /* ignore */ } + try { if (window.pythonCodeStopRun) window.pythonCodeStopRun(); } catch (e) { /* ignore */ } + try { if (window.cppCodeStopRun) window.cppCodeStopRun(); } catch (e) { /* ignore */ } + // 2. 强制重置执行状态 + window.isPythonRun = false; + window.isScriptRunOver = true; + // 3. 重置 Unity 游戏到初始状态(重新加载当前关卡) + if (window.unityInstance && window.gamelvdataJson) { + try { + let realLvId_tmp = ''; + if (localStorage.getItem('platformMode') === 'normal') { + realLvId_tmp = CONFIG.getRealLvId( + window.gamelvdataJson.gamelv, + window.gamelvdataJson.gameid, + window.gamelvdataJson.ismatch, + window.gamelvdataJson.gameNumber + ) + (window.gamelvdata ? window.gamelvdata.currentlv : ''); + } else { + realLvId_tmp = CONFIG.getRealLvId( + window.gamelvdataJson.gamelv, + window.gamelvdataJson.gameid, + window.gamelvdataJson.ismatch, + window.gamelvdataJson.gameNumber + ); + } + window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId_tmp); + console.log('Unity 关卡重置:', realLvId_tmp); + } catch (e) { + console.warn('Unity 重置失败:', e); + } + } + } + handleChangeSkin() { unityInstance.SendMessage("Player", "CallChangeSkin", 1); } @@ -1341,6 +1386,18 @@ class MenuBar extends React.Component { */} +
+ + + +
+
+ - + {this.state.showNoPermissionModal ? ( + + ) : null} {enable_screen_block && (
{ u-container-align-center-xl u-container-style u-dialog-block + u-dialog-open u-opacity u-opacity-70 u-valign-middle-lg diff --git a/scratch-gui/src/components/stage-cpp-unity/currentLevelChoose.jsx b/scratch-gui/src/components/stage-cpp-unity/currentLevelChoose.jsx index ca9a4b98..767c3a3c 100644 --- a/scratch-gui/src/components/stage-cpp-unity/currentLevelChoose.jsx +++ b/scratch-gui/src/components/stage-cpp-unity/currentLevelChoose.jsx @@ -148,7 +148,7 @@ const CurrentLevelChoose = ({ onCancel }) => { console.warn('window.loadCppProject 未定义或不是函数'); } } - const realLvId_tmp = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber, window.gamelvdataJson.gamemode); + const realLvId_tmp = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber); const realLvId = realLvId_tmp + cellIndex window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId); CONFIG.checkGameStyle(realLvId); diff --git a/scratch-gui/src/components/stage-cpp-unity/stage-unity.jsx b/scratch-gui/src/components/stage-cpp-unity/stage-unity.jsx index 37e94646..96d4900b 100644 --- a/scratch-gui/src/components/stage-cpp-unity/stage-unity.jsx +++ b/scratch-gui/src/components/stage-cpp-unity/stage-unity.jsx @@ -12,6 +12,8 @@ import RankBadgeGenerator from '../../playground/rank-badge-generator.js'; window.RankBadgeGenerator = RankBadgeGenerator; window.CONFIG = CONFIG; import disableDevtool from 'disable-devtool'; +import { initDisableDevtool } from '../../playground/devtool-control.js'; +import { getUnityPlayerConfig, loadUnityLoaderScript } from '../../lib/unity-build-loader.js'; import { debug } from 'scratch-vm/src/util/log.js'; const MAX_LEVELS = 500; // 最大关卡数据数量 diff --git a/scratch-gui/src/components/stage-cpp/stage-cpp.css b/scratch-gui/src/components/stage-cpp/stage-cpp.css index 9843b2b3..46ab6be2 100644 --- a/scratch-gui/src/components/stage-cpp/stage-cpp.css +++ b/scratch-gui/src/components/stage-cpp/stage-cpp.css @@ -504,9 +504,41 @@ flex-direction: column; } -.apiDrawer.apiDrawerOpen { - right: 0; - /* 滑出显示 */ +.apiDrawerLoading { + position: absolute; + inset: 0; + z-index: 20; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 14px; + background: rgba(18, 18, 18, 0.82); + backdrop-filter: blur(2px); + cursor: not-allowed; +} + +.apiDrawerLoadingSpinner { + width: 38px; + height: 38px; + border: 3px solid rgba(255, 255, 255, 0.18); + border-top-color: #ba68c8; + border-radius: 50%; + animation: apiDrawerLoadingSpin 0.9s linear infinite; +} + +.apiDrawerLoadingText { + color: #e0e0e0; + font-size: 13px; + line-height: 1.7; + text-align: center; + padding: 0 18px; +} + +@keyframes apiDrawerLoadingSpin { + to { + transform: rotate(360deg); + } } .apiDrawerHeader { @@ -526,21 +558,6 @@ font-weight: 600; } -.apiDrawerClose { - background: none; - border: none; - color: white; - font-size: 20px; - cursor: pointer; - padding: 5px; - border-radius: 3px; - transition: background-color 0.2s ease; -} - -.apiDrawerClose:hover { - background-color: rgba(255, 255, 255, 0.1); -} - .apiDrawerContent { flex: 1; overflow: hidden; @@ -710,11 +727,6 @@ @media (max-width: 1200px) { .apiDrawer { width: 25vw; - right: -25vw; - } - - .apiDrawer.apiDrawerOpen { - right: 0; } .apiDrawerCategoryButton { @@ -730,11 +742,6 @@ @media (max-width: 900px) { .apiDrawer { width: 35vw; - right: -35vw; - } - - .apiDrawer.apiDrawerOpen { - right: 0; } .apiDrawerHeader h3 { diff --git a/scratch-gui/src/components/stage-python-unity/currentLevelChoose.jsx b/scratch-gui/src/components/stage-python-unity/currentLevelChoose.jsx index 2dac343e..24db794f 100644 --- a/scratch-gui/src/components/stage-python-unity/currentLevelChoose.jsx +++ b/scratch-gui/src/components/stage-python-unity/currentLevelChoose.jsx @@ -144,7 +144,7 @@ const CurrentLevelChoose = ({ onCancel }) => { // 清除所有代码 window.loadPythonProject(`` + `\n`.repeat(50)); } - const realLvId_tmp = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber, window.gamelvdataJson.gamemode); + const realLvId_tmp = CONFIG.getRealLvId(window.gamelvdataJson.gamelv, window.gamelvdataJson.gameid, window.gamelvdataJson.ismatch, window.gamelvdataJson.gameNumber); const realLvId = realLvId_tmp + cellIndex window.unityInstance.SendMessage("GameController", "SwitchLevel", realLvId); CONFIG.checkGameStyle(realLvId); diff --git a/scratch-gui/src/components/stage-python-unity/stage-unity.jsx b/scratch-gui/src/components/stage-python-unity/stage-unity.jsx index ab8754c7..ab503671 100644 --- a/scratch-gui/src/components/stage-python-unity/stage-unity.jsx +++ b/scratch-gui/src/components/stage-python-unity/stage-unity.jsx @@ -12,6 +12,8 @@ import RankBadgeGenerator from '../../playground/rank-badge-generator.js'; window.RankBadgeGenerator = RankBadgeGenerator; window.CONFIG = CONFIG; import disableDevtool from 'disable-devtool'; +import { initDisableDevtool } from '../../playground/devtool-control.js'; +import { getUnityPlayerConfig, loadUnityLoaderScript } from '../../lib/unity-build-loader.js'; import { debug } from 'scratch-vm/src/util/log.js'; const MAX_LEVELS = 500; // 最大关卡数据数量 diff --git a/scratch-gui/src/components/stage-python/stage-python.css b/scratch-gui/src/components/stage-python/stage-python.css index 8c6ecbe9..16a65291 100644 --- a/scratch-gui/src/components/stage-python/stage-python.css +++ b/scratch-gui/src/components/stage-python/stage-python.css @@ -139,103 +139,71 @@ background-color: #0056b3; } -/* API抽屉标签样式 */ -.apiDrawerTab { - position: fixed; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 45px; - height: 90px; - background: hsla(215, 100%, 65%, 1); - border: 1px solid hsla(215, 100%, 65%, 1); - border-right: none; - border-radius: 12px 0 0 12px; - cursor: pointer; - z-index: 1001; +/* API参考 + 编辑器并排:参考在左,编辑器靠右 */ +.editorWithApi { display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - gap: 6px; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - box-shadow: -4px 0 12px rgba(0, 0, 0, 0.25); - color: #BDC3C7; - backdrop-filter: blur(10px); + flex-direction: row; + height: 100%; + width: 54vw; + overflow: hidden; } -.apiDrawerTab:hover { - background: hsla(215, 100%, 65%, 1); - transform: translateY(-50%) translateX(-3px); - box-shadow: -6px 0 18px rgba(0, 0, 0, 0.35); - color: #FFFFFF; +.editorPane { + flex: 1; + min-width: 0; + height: 100%; + position: relative; + overflow: auto; } -.apiDrawerTab.apiDrawerTabOpen { - background: linear-gradient(135deg, #D35400 0%, #E67E22 100%); - border-color: #E67E22; - right: 20vw; - color: #FFFFFF; -} - -.apiDrawerTab.apiDrawerTabOpen:hover { - background: linear-gradient(135deg, #E67E22 0%, #F39C12 100%); - color: #FFFFFF; -} - -.apiDrawerTabIcon { - font-size: 14px; - font-weight: bold; - line-height: 1; - color: #FFFFFF; - opacity: 0.9; - transition: all 0.2s ease; -} - -.apiDrawerTab:hover .apiDrawerTabIcon { - opacity: 1; - transform: scale(1.1); -} - -.apiDrawerTabText { - font-size: 12px; - font-weight: 700; - text-transform: uppercase; - letter-spacing: 1.5px; - writing-mode: vertical-lr; - text-orientation: mixed; - line-height: 1; - color: #FFFFFF; - opacity: 0.8; - transition: all 0.2s ease; -} - -.apiDrawerTab:hover .apiDrawerTabText { - opacity: 1; - letter-spacing: 2px; -} - -/* API抽屉样式 */ .apiDrawer { - position: fixed; - top: 0; - right: -20vw; - /* 初始隐藏在右侧 */ + position: relative; + flex-shrink: 0; width: 20vw; - height: 100vh; + height: 100%; background: linear-gradient(135deg, #1e1e1e 0%, #2d2d2d 100%); - border-left: 2px solid #444; - box-shadow: -5px 0 20px rgba(0, 0, 0, 0.3); - z-index: 1000; - transition: right 0.3s ease; + border-right: 2px solid #444; + box-shadow: 2px 0 12px rgba(0, 0, 0, 0.2); overflow: hidden; display: flex; flex-direction: column; } -.apiDrawer.apiDrawerOpen { - right: 0; - /* 滑出显示 */ +.apiDrawerLoading { + position: absolute; + inset: 0; + z-index: 20; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 14px; + background: rgba(18, 18, 18, 0.82); + backdrop-filter: blur(2px); + cursor: not-allowed; +} + +.apiDrawerLoadingSpinner { + width: 38px; + height: 38px; + border: 3px solid rgba(255, 255, 255, 0.18); + border-top-color: #ba68c8; + border-radius: 50%; + animation: apiDrawerLoadingSpin 0.9s linear infinite; +} + +.apiDrawerLoadingText { + color: #e0e0e0; + font-size: 13px; + line-height: 1.7; + text-align: center; + padding: 0 18px; +} + +@keyframes apiDrawerLoadingSpin { + to { + transform: rotate(360deg); + } } .apiDrawerHeader { @@ -255,21 +223,6 @@ font-weight: 600; } -.apiDrawerClose { - background: none; - border: none; - color: white; - font-size: 20px; - cursor: pointer; - padding: 5px; - border-radius: 3px; - transition: background-color 0.2s ease; -} - -.apiDrawerClose:hover { - background-color: rgba(255, 255, 255, 0.1); -} - .apiDrawerContent { flex: 1; overflow: hidden; @@ -440,15 +393,6 @@ @media (max-width: 1200px) { .apiDrawer { width: 25vw; - right: -25vw; - } - - .apiDrawer.apiDrawerOpen { - right: 0; - } - - .apiDrawerTab.apiDrawerTabOpen { - right: 25vw; } .apiDrawerCategoryButton { @@ -464,34 +408,6 @@ @media (max-width: 900px) { .apiDrawer { width: 35vw; - right: -35vw; - } - - .apiDrawer.apiDrawerOpen { - right: 0; - } - - .apiDrawerTab.apiDrawerTabOpen { - right: 35vw; - } - - .apiDrawerTab { - width: 35px; - height: 75px; - gap: 4px; - } - - .apiDrawerTabIcon { - font-size: 12px; - } - - .apiDrawerTabText { - font-size: 8px; - letter-spacing: 1px; - } - - .apiDrawerTab:hover .apiDrawerTabText { - letter-spacing: 1.5px; } .apiDrawerHeader h3 { diff --git a/scratch-gui/src/components/stage-python/stage-python.jsx b/scratch-gui/src/components/stage-python/stage-python.jsx index d86e1e6e..dcb7fee4 100644 --- a/scratch-gui/src/components/stage-python/stage-python.jsx +++ b/scratch-gui/src/components/stage-python/stage-python.jsx @@ -49,9 +49,6 @@ const StageWrapperPythonCPLT = () => { ` ); - // ★★★ 添加抽屉状态管理 - const [apiDrawerOpen, setApiDrawerOpen] = useState(false); - // ★★★ 替换 workerRef,用 Pool Ref const poolRef = useRef(null); // 用这个存 Worker Pool // const workerRef = useRef(null); // <-- 删掉 @@ -60,6 +57,27 @@ const StageWrapperPythonCPLT = () => { const [errorModalVisible, setErrorModalVisible] = useState(false); const [errorMessage, setErrorMessage] = useState(''); const [overlayActive, setOverlayActive] = useState(false); + const [apiSelectedCategory, setApiSelectedCategory] = useState('player'); + const [isApiPanelReady, setIsApiPanelReady] = useState(() => window.iscreate === 1); + + // Unity 加载完成前,API 面板显示加载态并屏蔽点击(5 秒兜底自动解除) + useEffect(() => { + if (isApiPanelReady) return undefined; + const timer = setInterval(() => { + if (window.iscreate === 1) { + setIsApiPanelReady(true); + clearInterval(timer); + } + }, 300); + const fallback = setTimeout(() => { + setIsApiPanelReady(true); + clearInterval(timer); + }, 5000); + return () => { + clearInterval(timer); + clearTimeout(fallback); + }; + }, [isApiPanelReady]); // CodeMirror编辑器引用 const editorRef = useRef(null); @@ -649,15 +667,65 @@ const StageWrapperPythonCPLT = () => { if (t) parts.push(t); return parts; } + + function splitOr(stmt) { + if (!hasFuncCall(stmt)) { + return [stmt]; + } + const parts = []; + let cur = ''; + let skipChars = 0; + + parse(stmt, (ch, depth, parenDepth, i, notInStr) => { + if (skipChars > 0) { + skipChars--; + return; + } + + if (notInStr && depth === 0 && ch === 'o' && stmt[i + 1] === 'r') { + const prevChar = i > 0 ? stmt[i - 1] : ''; + const nextChar = i + 2 < stmt.length ? stmt[i + 2] : ''; + const isPrevWordChar = /[a-zA-Z0-9_]/.test(prevChar); + const isNextWordChar = /[a-zA-Z0-9_]/.test(nextChar); + + if (!isPrevWordChar && !isNextWordChar) { + const t = cur.trim(); + if (t) parts.push(t); + cur = ''; + skipChars = 1; + return; + } + } + + cur += ch; + }); + + const t = cur.trim(); + if (t) parts.push(t); + return parts; + } let count = 0; for (const stmt of splitStatements(s)) { const assign = findAssign(stmt); if (!assign) { - count += splitComma(stmt).length; + let stmtCount = 0; + for (const orPart of splitOr(stmt)) { + stmtCount += splitComma(orPart).length; + } + count += stmtCount; } else { const lhs = stmt.slice(0, assign.index).trim(); - count += hasComma(lhs) ? 1 : Math.max(1, splitComma(stmt.slice(assign.index + assign.length)).length); + if (hasComma(lhs)) { + count += 1; + } else { + const rhs = stmt.slice(assign.index + assign.length); + let rhsCount = 0; + for (const orPart of splitOr(rhs)) { + rhsCount += splitComma(orPart).length; + } + count += Math.max(1, rhsCount); + } } } return count; @@ -1168,22 +1236,15 @@ sys.settrace(trace_func)`; ); }; - // API参考抽屉组件 + // API参考面板 const ApiDrawer = () => { - const [selectedCategory, setSelectedCategory] = useState('player'); + const selectedCategory = apiSelectedCategory; + const setSelectedCategory = setApiSelectedCategory; return ( -
- {/* 抽屉头部 */} +

🐍 Python API参考

-
{/* 抽屉内容 */} @@ -1226,6 +1287,12 @@ sys.settrace(trace_func)`; ))}
+ {!isApiPanelReady && ( +
+
+
游戏引擎加载中,完成后即可插入代码…
+
+ )}
); }; @@ -1288,9 +1355,6 @@ sys.settrace(trace_func)`; }); } - // 关闭API参考窗口 - setApiDrawerOpen(false); - // 聚焦编辑器 view.focus(); } @@ -1300,36 +1364,16 @@ sys.settrace(trace_func)`; return ( <> -
- {/* API抽屉标签 */} -
setApiDrawerOpen(!apiDrawerOpen)} - title={apiDrawerOpen ? "关闭API参考" : "打开API参考"} - > -
- {apiDrawerOpen ? '▶' : '◀'} -
-
- {apiDrawerOpen ? '关闭' : 'API'} -
-
- - {/* API抽屉 */} +
- - {/* Python代码编辑器 - 现在占满整个高度 */} -
e.stopPropagation()} style={{ overflow: 'auto', position: 'relative', height: '100%' }}> +
e.stopPropagation()} + > bytes[index] === value); +} + +function looksLikeJavascript(buffer) { + const head = new TextDecoder().decode(buffer.slice(0, 80)); + return /function|unityFramework|^\s*var |^\s*const |^\s*!function/.test(head); +} + +function looksLikeUnityData(buffer) { + const head = new TextDecoder().decode(buffer.slice(0, 16)); + return head.startsWith('UnityWebData1.0'); +} + +function toTrustedUrl(fileName, buffer, sourceUrl) { + if (fileName.endsWith('.wasm.br') && isUncompressedWasm(buffer)) { + return URL.createObjectURL(new Blob([buffer], { type: 'application/wasm' })); + } + if (fileName.endsWith('.js.br') && looksLikeJavascript(buffer)) { + return URL.createObjectURL(new Blob([buffer], { type: 'application/javascript' })); + } + if (fileName.endsWith('.data.br') && looksLikeUnityData(buffer)) { + return URL.createObjectURL(new Blob([buffer])); + } + return sourceUrl; +} + +async function fetchCompleteAsset(fileName, minBytes) { + let lastError = null; + for (const base of buildCandidates()) { + const url = withVersion(`${base}/${fileName}`); + try { + const response = await fetch(url, { cache: 'no-store' }); + if (!response.ok) { + lastError = new Error(`${url} HTTP ${response.status}`); + continue; + } + const buffer = await response.arrayBuffer(); + if (buffer.byteLength < minBytes) { + console.warn(`[Unity] ${fileName} 被截断: ${buffer.byteLength} bytes(来自 ${url}),期望至少 ${minBytes}`); + lastError = new Error(`${fileName} truncated: ${buffer.byteLength}`); + continue; + } + console.log(`[Unity] ${fileName} 下载完整: ${buffer.byteLength} bytes from ${url}`); + return toTrustedUrl(fileName, buffer, url); + } catch (error) { + console.warn(`[Unity] 下载失败 ${url}`, error); + lastError = error; + } + } + throw lastError || new Error(`无法完整下载 ${fileName}`); +} + +export async function getUnityPlayerConfig() { + const [dataUrl, frameworkUrl, codeUrl] = await Promise.all([ + fetchCompleteAsset(FILES.dataUrl, MIN_BYTES.dataUrl), + fetchCompleteAsset(FILES.frameworkUrl, MIN_BYTES.frameworkUrl), + fetchCompleteAsset(FILES.codeUrl, MIN_BYTES.codeUrl) + ]); + + const streamingAssetsUrl = (CONFIG.usecdn && CONFIG.unitycdndir) + ? `${CONFIG.unitycdndir}/StreamingAssets` + : '/unity/StreamingAssets'; + + return { + dataUrl, + frameworkUrl, + codeUrl, + streamingAssetsUrl, + companyName: 'DefaultCompany', + productName: 'Web A', + productVersion: String(CONFIG.version || '1.0') + }; +} + +export function loadUnityLoaderScript() { + if (typeof window.createUnityInstance === 'function') { + return Promise.resolve(); + } + return new Promise((resolve, reject) => { + const script = document.createElement('script'); + script.src = withVersion('/unity/Build/mstest5.loader.js'); + script.onload = () => resolve(); + script.onerror = () => reject(new Error('Unity loader 加载失败')); + document.body.appendChild(script); + }); +} diff --git a/scratch-gui/src/playground/aboutus.ejs b/scratch-gui/src/playground/aboutus.ejs index 59b1881a..a5012c8d 100644 --- a/scratch-gui/src/playground/aboutus.ejs +++ b/scratch-gui/src/playground/aboutus.ejs @@ -5,6 +5,7 @@ 关于我们 - 灵丌编程(001CODE) - 你身边的青少年编程学习平台 - 图形化、Python、C++ + + + + +
+ + + + + 返回 + + +
AI绘图
+
+ 作品广场 + + +
+
+ +
+ + +
+
+
+
+ +
+
+
AI绘画
+
用文字或图片描述你想要的画面,AI 帮你画出来
+ + +
+ + +
+ + +
+ + +
+ +
+
点击上传 1 张参考图(图生图必选)
+ + + + +
+ + + +
+ +
+ +
+ +
+
+
+
试试这些主题
+
点击主题可填入上方输入框
+
+ +
+
+
+ +
+
精选作品墙
+
看看其他同学都画出了什么
+
+
+
+ + +
+
+
风格魔法师
+
上传你的照片,让AI把它变成一幅艺术品
+ +
+
+ +
+
点击上传照片
+
支持 JPG / PNG / WEBP,仅上传 1 张
+ + +
+ + +
+ + + +
+
+ 原图 + 原图 +
+
+ 效果图 +
+
+
正在施展风格魔法…
+
+ +
+
+ +
+
+ + +
+
+
涂鸦猜猜乐
+
画一画,让 AI 猜你画了什么
+ +
+
+ + +
+ +
+
+ +
+
+ +
+ + +
不用画得很像哦~简笔画也可以!AI会努力猜你画了什么
+
+
+
+
+
+
+
生成记录
+
历史草稿可在此找回并预览
+
+
+ 预览 + +
+
+
生成后可在这里预览
+
+
+
+ + 打开原图 +
+
+
还没有生成记录,去左边试试吧
+
+
+
+
+
+
+ + + + + diff --git a/scratch-gui/src/playground/ai-huiben.ejs b/scratch-gui/src/playground/ai-huiben.ejs new file mode 100644 index 00000000..4c6a9d81 --- /dev/null +++ b/scratch-gui/src/playground/ai-huiben.ejs @@ -0,0 +1,2124 @@ + + + + + + + AI绘本 - 灵丌AI - 001CODE + + + + +
+ + + + + 返回 + + +
AI绘本
+
+ 作品广场 + + +
+
+ +
+ + +
+ +
+
+
1
+
+
故事主题
+
主题与内容
+
+
+
+
+
2
+
+
角色分镜
+
角色与镜头
+
+
+
+
+
3
+
+
风格设置
+
画面与尺寸
+
+
+
+
+
4
+
+
绘本生成
+
生成结果
+
+
+
+ + +
+
+ +
+
+
故事主题与内容
+
先填写主题,再选择页数点击「扩写镜头」,生成可编辑的分镜脚本
+
+ +
+
+ 扩写镜头 + +
+ +
+
+
+
+ +
+
+
+
试试这些主题
+
点击主题可填入上方输入框
+
+ +
+
+
+
+ + +
+
+ + +
+ +
+
角色分析
+
根据故事内容自动生成,不支持新增角色;可为角色添加或删除标签
+
+
+ +
+
分镜头与画面描述
+
每个镜头包含镜头名称、镜头语言和画面描述
+
+
+
+ + +
+
+
画面风格
+
选择绘本的整体视觉风格
+
+
+ +
+
模板尺寸
+
选择绘本页面的画幅比例
+
+
+
+ + +
+
+
+
📖
+
点击下方按钮 开始生成绘本
+
点击下方「生成绘本」开始创作
+
+ +
+ + + +
+
+
+
+
+
+
+
生成记录
+
历史草稿可在此找回并预览
+
+
+ 预览 + +
+
+
生成后可在这里预览
+
+
+
+ +
+
+
还没有生成记录,去左边试试吧
+
+
+
+
+ +
+
+ + + + + diff --git a/scratch-gui/src/playground/ai-music.ejs b/scratch-gui/src/playground/ai-music.ejs new file mode 100644 index 00000000..e0028522 --- /dev/null +++ b/scratch-gui/src/playground/ai-music.ejs @@ -0,0 +1,1988 @@ + + + + + + + AI音乐 - 灵丌AI - 001CODE + + + + +
+ + + + + 返回 + + +
AI音乐
+
+ 作品广场 + + +
+
+ +
+ + +
+
+
+
+ +
+
+
+
+
选一个音乐主题
+
+
点击你喜欢的主题卡片,AI会根据主题为你作曲
+
+
主题卡片
+ +
+
+ + +
+ +
+
选一种乐器
+
+
+ +
+
选一种心情
+
+
+ +
+
调节音乐参数
+
+
+
+ 节奏 + 120 BPM +
+ +
60120180
+
+
+
+ 时长 + 30 秒 +
+ +
10s35s60s
+
+
+
+ 复杂度 + 适中 +
+ +
简单适中复杂
+
+
+
+ + +
+ + +
+
+
+
+
选一个节拍模板
+
+
点击模板快速加载节拍,也可以在网格上自由编辑
+
+
+ +
+
节拍编辑器
+
点击格子开关声音
+
+
+ +
+
调节节拍参数
+
+
+
+ 速度 + 120 BPM +
+ +
60120180
+
+
+
+ 音量 + 80% +
+ +
0%50%100%
+
+
+
+ 混响 + 轻微 +
+ +
适中最大
+
+
+
+ + + +
+ + +
+
+
+
+
选一首经典旋律
+
+
选一首你熟悉的旋律,AI会给它换上新风格
+
+
经典旋律
+ +
+
+ + +
+ +
+
选一种变装风格
+
+
+ +
+
调节变装参数
+
+
+
+ 强度 + 适中 +
+ +
微调适中大改
+
+
+
+ 速度 + 1.0x +
+ +
0.5x1.0x2.0x
+
+
+
+ 音色 + 适中 +
+ +
原生适中电子
+
+
+
+ + +
+
+ +
+
+
+
音乐作品库
+
点击作品可预览效果
+
+
+ 预览 +
+
+ +
+
+
生成后可在这里预览
+
+
+
+ + +
+
+
加载中…
+
+
+
+
+
+
+ + + + + diff --git a/scratch-gui/src/playground/ai-text.ejs b/scratch-gui/src/playground/ai-text.ejs new file mode 100644 index 00000000..26dc2478 --- /dev/null +++ b/scratch-gui/src/playground/ai-text.ejs @@ -0,0 +1,2178 @@ + + + + + + + AI文本 - 灵丌AI - 001CODE + + + + +
+ + + + + 返回 + + +
AI文本
+
+ 作品广场 + + +
+
+ +
+ + + + +
+
+
💬
+
请先选择角色开始对话
+
从右侧选择系统角色或我的角色
+
+ + + + + +
+
+ +
+ + + +
+ + + + + + + + + + + diff --git a/scratch-gui/src/playground/ai-video.ejs b/scratch-gui/src/playground/ai-video.ejs new file mode 100644 index 00000000..bcca1934 --- /dev/null +++ b/scratch-gui/src/playground/ai-video.ejs @@ -0,0 +1,1897 @@ + + + + + + + AI视频 - 灵丌AI - 001CODE + + + + +
+ + + + + 返回 + + +
AI视频
+
+ 作品广场 + + +
+
+ +
+ + +
+
+
+
+ +
+
+
+
+
选一个场景
+
+
选一个你喜欢的场景,AI会帮你生成一段小视频
+ +
+
固定场景
+ +
+
+ + + +
+ +
+
调节视频参数
+
设置时长、画面风格与镜头运动
+
+
+
+ 时长 + 8 秒 +
+ +
5s10s15s
+
+
+
+ 画面风格 + 偏写实 +
+ +
写实适中卡通
+
+
+
+ 镜头运动 + 缓慢 +
+ +
静止适中快速
+
+
+
+ + +
+ + +
+
+
+
+
上传一张图片
+
+
上传图片后,AI会让它动起来!
+ +
+
+
拖拽或点击上传图片
+
支持 JPG / PNG / WEBP,仅上传 1 张
+ + +
+
+ +
+
选一个动画效果
+
+
+ +
+
调节动画参数
+
+
+
+ 动画速度 + 中等 +
+ +
+
+
+
+ 循环次数 + 3 次 +
+ +
135
+
+
+
+ 特效强度 + 中等 +
+ +
+
+
+
+ + +
+ + +
+
+
+
+
选一种风格
+
+
选一种你喜欢的风格,AI会给你的视频换上新衣服
+ +
+
风格列表
+ +
+
+ + + +
+ +
+
上传要处理的视频
+
支持 MP4 / WebM
+
+
+
点击上传视频
+
支持 MP4 / WebM
+ + + +
+
+ +
+
调节风格参数
+
+
+
+ 风格强度 + 适中 +
+ +
轻度适中重度
+
+
+
+ 色彩饱和度 + 适中 +
+ +
淡雅适中鲜艳
+
+
+
+ 画面亮度 + 正常 +
+ +
正常
+
+
+
+ + +
+
+ +
+
+
+
生成记录
+
点击记录可预览效果
+
+
+ 预览 + 预览 + +
+
+
生成后可在这里预览
+
+
+
+ + +
+
+
加载中…
+
+
+
+
+
+
+ + + + + diff --git a/scratch-gui/src/playground/ai-voice.ejs b/scratch-gui/src/playground/ai-voice.ejs new file mode 100644 index 00000000..2991f6dd --- /dev/null +++ b/scratch-gui/src/playground/ai-voice.ejs @@ -0,0 +1,2473 @@ + + + + + + + AI语音 - 灵丌AI - 001CODE + + + + +
+ + + + + 返回 + + +
AI语音
+
+ 作品广场 + + +
+
+ +
+ + +
+
+
+
+ +
+
+
+
+
语音合成
+
+
把文字变成好听的声音,还能用你自己的声音说话哦!
+ + + +
+ +
+
+
+
快速选择文字
+
点击填入上方输入框
+
+ +
+
+
+ +
+
选择音色
+
想用自己的声音?先在下方「自定义音色」录一段 5~10 秒
+
+
+ +
+
自定义音色(录一段你的声音)
+
录一段 10 秒以内的话,AI 就能模仿你的声音说话啦!建议 5~10 秒,清晰无背景音(必填)
+
+
+
+
录一段你的声音
+
请录制 5~10 秒清晰人声,完成后即可选中「我的声音」
+
+
+
+ + + +
+
+
+ +
+
声音调节
+
拖动滑条,调节语速、语调和情绪(均为必填)
+
+
+
+ 语速 + 正常 +
+
+ +
很慢正常很快
+
+
+
+
+ 语调 + 适中 +
+
+ +
偏低适中很高
+
+
+
+
+ 情绪 + 平静 +
+
+ +
平静生动激昂
+
+
+
+
+ +
+ +
+
+ + +
+
+
+
+
AI 方言
+
+
选一种方言,让AI用地道的地方话帮你说话!
+ + + +
+ +
+
+
+
快速选择句子
+
点击填入上方输入框
+
+ +
+
+
+ +
+
选择方言
+
点击选择一种方言,默认已选中第一种
+
+
+ +
+
声音调节
+
拖动滑条,调节语速与方言浓度
+
+
+
+ 语速 + 1.0x +
+
+ +
0.5x1.0x2.0x
+
+
+
+
+ 方言浓度 + 适中 +
+
+ +
普通话适中超地道
+
+
+
+
+ +
+ +
+
+ + +
+
+
+
+
声音变声
+
+
选一种变声效果,让AI用好玩的声音说话!
+ + + +
+ +
+
+
+
快速选择句子
+
点击填入上方输入框
+
+ +
+
+
+ +
+
选择变声效果
+
点击选择一种效果,默认已选中第一种
+
+
+ +
+
声音调节
+
拖动滑条调节音调、共鸣与混响
+
+
+
+ 音调 + 适中 +
+
+ +
低沉适中高尖
+
+
+
+
+ 共鸣 + 适中 +
+
+ +
适中轰鸣
+
+
+
+
+ 混响 + 轻微 +
+
+ +
适中超大
+
+
+
+
+ +
+ +
+
+
+ +
+
+
+
合成结果
+
历史草稿可在此找回并预览播放
+
+
+ 预览 +
+ +
+
+
+
生成后可在这里预览
+
+
+
+ + +
+
+
还没有合成记录,去左边试试吧
+
+
+
+
+
+
+ + + + + diff --git a/scratch-gui/src/playground/ai.ejs b/scratch-gui/src/playground/ai.ejs new file mode 100644 index 00000000..03322ae7 --- /dev/null +++ b/scratch-gui/src/playground/ai.ejs @@ -0,0 +1,2496 @@ + + + + + + + 灵丌AI - 001CODE 智能编程助手 + + + + + + + + + + + + + +
+
+ + +
+ + + + +
+ +
+
👤
+
请登录
+
登录后查看个人信息、使用时长与 AI 作品库
+ +
+ + +
+
+ +
+
加载中...
+
+ -- +
+
+
+
+
+
+
⏱️
+ 使用:-- +
+ +
+
📚
+ 作品:0 +
+
+
+ + 作品广场 +
+
+
作品分类
+
+
+
+
+
+ + +
+
+ +

系统化 AI 学习路径

+

从入门到精通,四大课程模块满足不同阶段的学习需求

+
+
+
课程体系加载中...
+
+
+ + +
+
+
+ +

全方位 AI 创作工具箱

+

覆盖七大核心领域,打造完整的 AI 创作能力矩阵

+
+ +
+
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + diff --git a/scratch-gui/src/playground/ai.js b/scratch-gui/src/playground/ai.js new file mode 100644 index 00000000..2c13ca23 --- /dev/null +++ b/scratch-gui/src/playground/ai.js @@ -0,0 +1,9 @@ +// ai.html 的 CONFIG 由 head 中的 aiConfig chunk 注入(与 login 同一份 config.js)。 + +if (typeof window.__AI_PAGE_BOOTED__ === 'undefined') { + document.addEventListener('DOMContentLoaded', function () { + if (!window.__AI_PAGE_BOOTED__) { + console.warn('[ai.js] 内联 boot 未执行,请检查 ai.html 是否为最新构建'); + } + }); +} diff --git a/scratch-gui/src/playground/checkStatus.js b/scratch-gui/src/playground/checkStatus.js index 2641c8f1..3058aa44 100644 --- a/scratch-gui/src/playground/checkStatus.js +++ b/scratch-gui/src/playground/checkStatus.js @@ -6,6 +6,9 @@ let timerId = localStorage.getItem('loginStatusCheckTimerId'); async function checkLoginStatus() { const token = localStorage.getItem('access_token'); if (!token) { + try { + localStorage.setItem('returnUrl', window.location.pathname + window.location.search); + } catch (e) {} alert('您尚未登录或登录已过期,请重新登录'); window.location.href = window.location.origin + '/login.html'; return; diff --git a/scratch-gui/src/playground/coming-soon.ejs b/scratch-gui/src/playground/coming-soon.ejs new file mode 100644 index 00000000..bbe375f0 --- /dev/null +++ b/scratch-gui/src/playground/coming-soon.ejs @@ -0,0 +1,360 @@ + + + + + + + 即将上线 - 灵丌AI - 001CODE + + + + + +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+
+ + COMING SOON +
+

灵丌AI 即将上线

+

贯穿青少年科创教育始终,全新的AI学习工具,即将精彩呈现,敬请期待。

+ + +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+ AI创意课程 +
+

AI创意课程体系

+

采用全新创意式项目制学习及评价体系,赋能青少年AI素养培养。

+
+
+
+ AI实践平台 +
+

AI实践平台

+

一站式满足青少年AI素养学习需求,多模态工具助力探究式AI学习。

+
+
+
+ 赛事体系 +
+

赛事体系

+

每一级都有出口,每一步都有回响。

+
+
+
+ + +
+ 公众号二维码 +

扫码关注“灵丌编程”,了解更多资讯

+
+ + + + 返回首页 + +
+ + + + + diff --git a/scratch-gui/src/playground/competition.ejs b/scratch-gui/src/playground/competition.ejs index b8de3dca..9081f10a 100644 --- a/scratch-gui/src/playground/competition.ejs +++ b/scratch-gui/src/playground/competition.ejs @@ -87,8 +87,8 @@
diff --git a/scratch-gui/src/playground/competition_list.ejs b/scratch-gui/src/playground/competition_list.ejs index 395a257e..1d893031 100644 --- a/scratch-gui/src/playground/competition_list.ejs +++ b/scratch-gui/src/playground/competition_list.ejs @@ -5,6 +5,7 @@ 赛事详情 - 灵丌编程(001CODE) - 你身边的青少年编程学习平台 - 图形化、Python、C++ + + + + +
+ + + + + + 返回 + + + +
+ + + 作品广场 + + + + +
+
+ + + +
+ + + + + +
+
+
请选择左侧课件开始学习
+
+
+ + + 新窗口打开 +
+
+
+
简介
+

+
+
+
+
+
+

从左侧选择课件

+

点击目录中的课件,即可在此区域查看 PPT、视频或互动练习内容。

+
+
+

当前仅支持预览

+

预览模式仅可浏览课程目录列表,课件内容请通过「去上课」进入后查看。

+
+
+
+

课件尚未解锁

+

请联系老师解锁相关内容。

+ +
+ + +
+
+
+ + + +
+ + + + + + + diff --git a/scratch-gui/src/playground/devtool-control.js b/scratch-gui/src/playground/devtool-control.js new file mode 100644 index 00000000..a00170ea --- /dev/null +++ b/scratch-gui/src/playground/devtool-control.js @@ -0,0 +1,65 @@ +import disableDevtool from 'disable-devtool'; +import CONFIG from './config.js'; + +const STOP_DEV_KEY = 'stopDev'; + +function isStopped() { + try { + return sessionStorage.getItem(STOP_DEV_KEY) === '1'; + } catch (e) { + return false; + } +} + +/** + * 关闭开发者工具检测,之后可以正常打开 F12。 + * 可在控制台直接执行:stopDev() + */ +export function stopDev() { + try { + sessionStorage.setItem(STOP_DEV_KEY, '1'); + } catch (e) { + // ignore quota / private mode + } + disableDevtool.isSuspend = true; +} + +export function initDisableDevtool(options = {}) { + window.stopDev = stopDev; + + if (isStopped()) { + disableDevtool.isSuspend = true; + } + + if (!CONFIG.disabledev) { + return; + } + + const userIgnore = options.ignore; + disableDevtool({ + ondevtoolopen: () => { + window.location.href = localStorage.getItem('returnUrl'); + }, + interval: 500, + clearLog: true, + disableMenu: true, + ...options, + ignore: () => { + if (isStopped()) { + return true; + } + if (typeof userIgnore === 'function') { + return userIgnore(); + } + return false; + } + }); + + if (isStopped()) { + disableDevtool.isSuspend = true; + } +} + +if (typeof window !== 'undefined') { + window.stopDev = stopDev; +} diff --git a/scratch-gui/src/playground/home.ejs b/scratch-gui/src/playground/home.ejs index 76ccbcc7..87da937b 100644 --- a/scratch-gui/src/playground/home.ejs +++ b/scratch-gui/src/playground/home.ejs @@ -5,6 +5,7 @@ 首页 - 灵丌编程(001CODE) - 你身边的青少年编程学习平台 - 图形化、Python、C++ + + + +
@@ -199,8 +331,8 @@ @@ -778,8 +910,11 @@ } catch (error) { console.error(error); } } - await fetchUserDetails(); - await fetchUserRank(); + const hasAccessToken = !!localStorage.getItem('access_token'); + if (hasAccessToken) { + await fetchUserDetails(); + await fetchUserRank(); + } // Edit Profile Logic let isEditing = false; diff --git a/scratch-gui/src/playground/welcome.js b/scratch-gui/src/playground/welcome.js index a012c432..05bd7448 100644 --- a/scratch-gui/src/playground/welcome.js +++ b/scratch-gui/src/playground/welcome.js @@ -1,6 +1,6 @@ import CONFIG from './config.js'; import RankBadgeGenerator from './rank-badge-generator.js'; -import disableDevtool from 'disable-devtool'; +import { initDisableDevtool } from './devtool-control.js'; // 好友按钮逻辑已移除 @@ -83,18 +83,7 @@ window.addEventListener('DOMContentLoaded', () => { // 检查登录状态 // checkLoginStatus(); // 初始化禁用开发者工具 - if (CONFIG.disabledev) { - disableDevtool({ - ondevtoolopen: () => { - // window.location.href = '/index.html'; - window.location.href = localStorage.getItem('returnUrl'); - - }, - interval: 500, - clearLog: true, - disableMenu: true, - }); - } + initDisableDevtool(); // 设置二维码图片 setQRCodeImage(); @@ -105,6 +94,9 @@ window.addEventListener('DOMContentLoaded', () => { // 初始化权限控制 initPermissionControl(); + // 小屏导航折叠 + initNavbarToggle(); + // 绑定按钮事件 bindButtonEvents(); @@ -129,6 +121,44 @@ if (logoutBtn) { }); } +function initNavbarToggle() { + const wrapper = document.querySelector('.navbar-wrapper'); + const toggle = document.getElementById('navbarToggle'); + const collapse = document.getElementById('navbarCollapse'); + const backdrop = document.getElementById('navbarBackdrop'); + if (!wrapper || !toggle || !collapse) return; + + const setOpen = (open) => { + wrapper.classList.toggle('is-open', open); + toggle.setAttribute('aria-expanded', open ? 'true' : 'false'); + toggle.setAttribute('aria-label', open ? '关闭菜单' : '打开菜单'); + document.body.classList.toggle('nav-open', open); + }; + + toggle.addEventListener('click', (event) => { + event.stopPropagation(); + setOpen(!wrapper.classList.contains('is-open')); + }); + + if (backdrop) { + backdrop.addEventListener('click', () => setOpen(false)); + } + + collapse.addEventListener('click', (event) => { + if (event.target.closest('a, .navbar-logout, #open-personal-info')) { + setOpen(false); + } + }); + + document.addEventListener('keydown', (event) => { + if (event.key === 'Escape') setOpen(false); + }); + + window.addEventListener('resize', () => { + if (window.innerWidth > 960) setOpen(false); + }); +} + // 初始化轮播区域 function initCarouselSection() { const carouselSection = document.getElementById('sec-df5f'); diff --git a/scratch-gui/src/playground/works-plaza.ejs b/scratch-gui/src/playground/works-plaza.ejs new file mode 100644 index 00000000..18a43545 --- /dev/null +++ b/scratch-gui/src/playground/works-plaza.ejs @@ -0,0 +1,1752 @@ + + + + + + + 作品广场 - 灵丌AI - 001CODE + + + + +
+ + + + + 返回 + + +
作品广场
+
+ 作品广场 + + + +
+
+ +
+
+
+

作品广场

+

看看大家用 AI 创作了什么,发现灵感、互相学习

+
+
+ + +
+
+ +
+ + + + + + +
+ +
+ +
+
+ + + + + + diff --git a/scratch-gui/static/css/ai-account-modals.css b/scratch-gui/static/css/ai-account-modals.css new file mode 100644 index 00000000..7d277621 --- /dev/null +++ b/scratch-gui/static/css/ai-account-modals.css @@ -0,0 +1,294 @@ +/* AI 页:个人信息 / 修改密码弹窗(从 welcome-new.css 迁移) */ +.modal-overlay { + position: fixed; + inset: 0; + display: flex; + align-items: center; + justify-content: center; + padding: 24px; + background: rgba(0, 0, 0, 0.45); + z-index: 9999; +} + +.modal-basic-info { + width: 720px; + max-width: calc(100vw - 48px); + background: #FFFFFF; + border-radius: 10px; + box-shadow: 0px 34px 44px -20px rgba(185, 206, 234, 0.25); + padding: 32px; + display: flex; + flex-direction: column; + gap: 16px; +} + +.modal-header { + display: flex; + align-items: center; + gap: 16px; + width: 100%; +} + +.modal-title { + flex: 1; + font-family: Nunito, system-ui, sans-serif; + font-weight: 800; + font-size: 28px; + line-height: 1.2; + color: #1E293B; + text-align: left; + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 4px; +} + +.modal-subtitle { + font-family: "PingFang SC", system-ui, sans-serif; + font-size: 14px; + font-weight: 400; + color: #94A3B8; + letter-spacing: 0.5px; + text-transform: uppercase; +} + +.modal-close { + width: 32px; + height: 32px; + border-radius: 3px; + padding: 2px; + border: 0; + background: transparent; + cursor: pointer; + display: inline-flex; + align-items: center; + justify-content: center; + flex-shrink: 0; +} + +.modal-body { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + gap: 24px; +} + +.modal-actions { + display: flex; + justify-content: center; +} + +.modal-primary-btn { + border: 0; + cursor: pointer; + border-radius: 32px; + background: linear-gradient(90deg, rgba(3, 161, 234, 1) 0%, rgba(32, 91, 175, 1) 100%); + color: #FFFFFF; + padding: 10px 18px; + height: 44px; + font-family: "Noto Sans SC", "PingFang SC", system-ui, sans-serif; + font-weight: 400; + font-size: 14px; + line-height: 22px; + display: inline-flex; + align-items: center; + justify-content: center; + white-space: nowrap; +} + +.modal-password { + width: 450px; + max-width: calc(100vw - 48px); + background: #FFFFFF; + border-radius: 10px; + box-shadow: 0px 34px 44px -20px rgba(185, 206, 234, 0.25); + padding: 32px; + display: flex; + flex-direction: column; + align-items: center; + gap: 32px; +} + +.modal-header-spacer { + width: 32px; + height: 32px; + flex-shrink: 0; +} + +.modal-password .field { + width: 100%; + display: flex; + flex-direction: column; + gap: 15px; +} + +.modal-password .field-label { + font-family: Inter, system-ui, sans-serif; + font-weight: 500; + font-size: 16px; + line-height: 19.36px; + color: #000000; +} + +.input-gradient { + width: 100%; + border-radius: 8px; + padding: 1px; + background: linear-gradient(164deg, rgba(226, 230, 255, 1) 24%, rgba(255, 234, 227, 1) 95%); +} + +.modal-password .field-input { + width: 100%; + height: 44px; + border-radius: 7px; + border: 0; + padding: 0 12px; + background: #F5F6F9; + font-family: "PingFang SC", system-ui, sans-serif; + font-weight: 400; + font-size: 14px; + line-height: 22px; + color: #0F172A; + outline: none; + box-sizing: border-box; +} + +.modal-password .field-input::placeholder { + color: #7D91A1; +} + +.primary-btn { + width: 180px; + height: 48px; + border: 0; + border-radius: 32px; + background: linear-gradient(90deg, rgba(3, 161, 234, 1) 0%, rgba(32, 91, 175, 1) 100%); + color: #FFFFFF; + cursor: pointer; + display: inline-flex; + align-items: center; + justify-content: center; + font-family: "Noto Sans SC", system-ui, sans-serif; + font-weight: 400; + font-size: 14px; + line-height: 20px; + white-space: nowrap; +} + +.profile-body { + width: 100%; + display: flex; + flex-direction: column; + gap: 32px; +} + +.profile-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 24px; + width: 100%; +} + +@media (max-width: 640px) { + .profile-grid { + grid-template-columns: 1fr; + } +} + +.profile-item { + display: flex; + flex-direction: column; + gap: 8px; +} + +.profile-label { + font-family: "PingFang SC", system-ui, sans-serif; + font-size: 14px; + color: #64748B; + font-weight: 500; +} + +.profile-input-wrap { + display: flex; + align-items: center; + background-color: #F8FAFC; + border: 1px solid #E2E8F0; + border-radius: 8px; + height: 48px; + padding: 0 16px; + transition: all 0.2s ease; +} + +.profile-input-wrap:focus-within { + background-color: #FFFFFF; + border-color: #3B82F6; + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); +} + +.profile-icon { + width: 20px; + height: 20px; + color: #94A3B8; + margin-right: 12px; + flex-shrink: 0; +} + +.profile-input-wrap:focus-within .profile-icon { + color: #3B82F6; +} + +.profile-input { + flex: 1; + border: none; + background: transparent; + height: 100%; + font-family: inherit; + font-size: 14px; + color: #1E293B; + outline: none; + width: 100%; +} + +.profile-value { + flex: 1; + font-size: 14px; + color: #1E293B; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +select.profile-input { + appearance: none; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e"); + background-position: right 0 center; + background-repeat: no-repeat; + background-size: 1.5em 1.5em; + padding-right: 2.5rem; +} + +.profile-input-wrap.is-vip { + background: linear-gradient(to right, #FFFBF0, #FFF7E6); + border-color: #FDE68A; +} + +.profile-input-wrap.is-vip .profile-icon { + color: #D97706; +} + +.profile-value-btn { + background: transparent; + border: none; + color: #D97706; + font-weight: 600; + font-size: 14px; + padding: 0; + cursor: default; +} + +.profile-input:disabled { + background-color: transparent; + color: #64748B; + cursor: not-allowed; +} diff --git a/scratch-gui/static/css/welcome-new.css b/scratch-gui/static/css/welcome-new.css index 8464c3ca..cd71ab7a 100644 --- a/scratch-gui/static/css/welcome-new.css +++ b/scratch-gui/static/css/welcome-new.css @@ -60,6 +60,63 @@ body { display: flex; align-items: center; justify-content: space-between; + position: relative; +} + +.navbar-collapse { + display: flex; + align-items: center; + flex: 1; + min-width: 0; +} + +.navbar-toggle { + display: none; + width: 40px; + height: 40px; + margin-left: 12px; + padding: 0; + border: 1px solid #e2e8f0; + border-radius: 10px; + background: #f8fafc; + cursor: pointer; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 5px; + flex-shrink: 0; + appearance: none; + -webkit-appearance: none; +} + +.navbar-toggle:focus-visible { + outline: 2px solid rgba(79, 140, 255, 0.55); + outline-offset: 2px; +} + +.navbar-toggle span { + display: block; + width: 18px; + height: 2px; + background: #1e1a4c; + border-radius: 1px; + transition: transform 0.2s ease, opacity 0.2s ease; +} + +.navbar-wrapper.is-open .navbar-toggle span:nth-child(1) { + transform: translateY(7px) rotate(45deg); +} + +.navbar-wrapper.is-open .navbar-toggle span:nth-child(2) { + opacity: 0; +} + +.navbar-wrapper.is-open .navbar-toggle span:nth-child(3) { + transform: translateY(-7px) rotate(-45deg); +} + +.navbar-backdrop { + display: none; } .navbar-brand { @@ -110,12 +167,24 @@ body { font-weight: 400; font-size: 14px; line-height: 1.43; - color: #0790D9; + color: #1E1A4C; text-decoration: none; cursor: pointer; white-space: nowrap; } +.nav-link--active, +.nav-link[aria-current="page"] { + display: inline-flex; + align-items: center; + padding: 5px 12px; + height: 32px; + border-radius: 3px; + background: #f2f3ff; + color: #4F8CFF; + box-sizing: border-box; +} + .nav-label { color: #1E1A4C; } @@ -232,6 +301,38 @@ body { white-space: nowrap; } +.navbar-login { + display: none; + align-items: center; + justify-content: center; + padding: 8px 24px; + border-radius: 20px; + background: linear-gradient(90deg, rgba(3, 161, 234, 1) 0%, rgba(32, 91, 175, 1) 100%); + color: #ffffff; + font-size: 14px; + font-weight: 600; + line-height: 1.43; + text-decoration: none; + white-space: nowrap; + transition: transform 0.2s ease, box-shadow 0.2s ease; +} + +.navbar-login:hover { + transform: translateY(-1px); + box-shadow: 0 6px 16px rgba(3, 161, 234, 0.35); +} + +/* 未登录游客态:不显示段位与右侧入口,只显示「去登录」 */ +.navbar-wrapper.is-guest #user-rank-badge, +.navbar-wrapper.is-guest .navbar-right .navbar-link, +.navbar-wrapper.is-guest .navbar-right .navbar-account { + display: none; +} + +.navbar-wrapper.is-guest .navbar-login { + display: inline-flex; +} + .glass-container { flex: 1; display: flex; @@ -411,7 +512,7 @@ body { } /* .course-card-image.course-1 { - background-image: url("../images/image-119.png"); + background-image: url("../images/default_compertion.png"); } .course-card-image.course-2 { @@ -555,13 +656,149 @@ body { display: inline-block; } -@media (max-width: 960px) { +@media (max-width: 1200px) { + .navbar-logo { + width: 180px; + } + .navbar-middle { - display: none; + gap: 16px; + margin-left: 16px; + } + + .navbar-right { + gap: 10px; + } +} + +@media (max-width: 960px) { + body.nav-open { + overflow: hidden; } .navbar { - gap: 12px; + gap: 8px; + } + + .navbar-logo { + width: 156px; + height: 44px; + } + + .navbar-toggle { + display: inline-flex; + margin-left: auto; + } + + .navbar-collapse { + display: none; + position: fixed; + top: 64px; + left: 0; + right: 0; + flex: none; + flex-direction: column; + align-items: stretch; + gap: 8px; + max-height: calc(100vh - 64px); + overflow-y: auto; + padding: 12px 16px 20px; + background: #ffffff; + border-top: 1px solid #e2e8f0; + box-shadow: 0 16px 32px rgba(15, 23, 42, 0.12); + z-index: 1001; + } + + .navbar-wrapper.is-open .navbar-collapse { + display: flex; + } + + .navbar-backdrop { + display: none; + position: fixed; + top: 64px; + left: 0; + right: 0; + bottom: 0; + background: rgba(15, 23, 42, 0.32); + z-index: 1000; + } + + .navbar-wrapper.is-open .navbar-backdrop { + display: block; + } + + .navbar-middle, + .navbar-right { + flex-direction: column; + align-items: stretch; + width: 100%; + margin: 0; + gap: 4px; + } + + .navbar-middle { + padding-bottom: 8px; + border-bottom: 1px solid #eef2f7; + } + + .navbar-right { + padding-top: 4px; + justify-content: flex-start; + } + + .nav-link-group, + .navbar-link, + .navbar-account { + width: 100%; + min-height: 44px; + padding: 10px 12px; + border-radius: 10px; + justify-content: flex-start; + } + + .nav-link-group:hover, + .navbar-link:hover, + .navbar-account:hover { + background: #f8fafc; + } + + .navbar-wrapper.is-guest .navbar-login { + width: 100%; + min-height: 44px; + margin-top: 4px; + } + + .navbar-collapse .nav__pill, + .navbar-collapse .nav-ai-pill { + width: 100%; + height: 40px; + justify-content: flex-start; + } + + .navbar-collapse .nav-ai-pill:hover { + transform: none; + } + + .navbar-btn-activate { + justify-content: center; + margin-top: 4px; + } + + .navbar-btn-activate:hover { + background: linear-gradient(135deg, #ffc107 0%, #ff8f00 100%) !important; + transform: none; + box-shadow: 0 4px 12px rgba(255, 143, 0, 0.3); + } +} + +@media (max-width: 480px) { + .container { + padding: 0 12px; + } + + .navbar-logo { + width: 132px; } } diff --git a/scratch-gui/static/images/about-illustration.svg b/scratch-gui/static/images/about-illustration.svg new file mode 100644 index 00000000..1f27f7a9 --- /dev/null +++ b/scratch-gui/static/images/about-illustration.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/scratch-gui/static/images/ai-sparkle.svg b/scratch-gui/static/images/ai-sparkle.svg new file mode 100644 index 00000000..44bffa21 --- /dev/null +++ b/scratch-gui/static/images/ai-sparkle.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/scratch-gui/static/images/aigc/ai-banner1.png b/scratch-gui/static/images/aigc/ai-banner1.png new file mode 100644 index 00000000..f2486cad Binary files /dev/null and b/scratch-gui/static/images/aigc/ai-banner1.png differ diff --git a/scratch-gui/static/images/aigc/ai-banner2.png b/scratch-gui/static/images/aigc/ai-banner2.png new file mode 100644 index 00000000..c3947e9c Binary files /dev/null and b/scratch-gui/static/images/aigc/ai-banner2.png differ diff --git a/scratch-gui/static/images/aigc/ai-banner3.png b/scratch-gui/static/images/aigc/ai-banner3.png new file mode 100644 index 00000000..7e4add5d Binary files /dev/null and b/scratch-gui/static/images/aigc/ai-banner3.png differ diff --git a/scratch-gui/static/images/aigc/ai-fanyi.png b/scratch-gui/static/images/aigc/ai-fanyi.png new file mode 100644 index 00000000..541fbbaa Binary files /dev/null and b/scratch-gui/static/images/aigc/ai-fanyi.png differ diff --git a/scratch-gui/static/images/aigc/ai-home-page1.png b/scratch-gui/static/images/aigc/ai-home-page1.png new file mode 100644 index 00000000..94867d55 Binary files /dev/null and b/scratch-gui/static/images/aigc/ai-home-page1.png differ diff --git a/scratch-gui/static/images/aigc/ai-icon-class.png b/scratch-gui/static/images/aigc/ai-icon-class.png new file mode 100644 index 00000000..f4b3f624 Binary files /dev/null and b/scratch-gui/static/images/aigc/ai-icon-class.png differ diff --git a/scratch-gui/static/images/aigc/ai-icon-locked.png b/scratch-gui/static/images/aigc/ai-icon-locked.png new file mode 100644 index 00000000..4f0d0c24 Binary files /dev/null and b/scratch-gui/static/images/aigc/ai-icon-locked.png differ diff --git a/scratch-gui/static/images/aigc/ai-icon-lockopen.png b/scratch-gui/static/images/aigc/ai-icon-lockopen.png new file mode 100644 index 00000000..99f2b295 Binary files /dev/null and b/scratch-gui/static/images/aigc/ai-icon-lockopen.png differ diff --git a/scratch-gui/static/images/aigc/ai-logo.png b/scratch-gui/static/images/aigc/ai-logo.png new file mode 100644 index 00000000..31d0f701 Binary files /dev/null and b/scratch-gui/static/images/aigc/ai-logo.png differ diff --git a/scratch-gui/static/images/aigc/ai-wenben.png b/scratch-gui/static/images/aigc/ai-wenben.png new file mode 100644 index 00000000..d03fd58e Binary files /dev/null and b/scratch-gui/static/images/aigc/ai-wenben.png differ diff --git a/scratch-gui/static/images/aigc/ai-zuojia.png b/scratch-gui/static/images/aigc/ai-zuojia.png new file mode 100644 index 00000000..116d23ce Binary files /dev/null and b/scratch-gui/static/images/aigc/ai-zuojia.png differ diff --git a/scratch-gui/static/images/aigc/ai_programming_avatar_01.png b/scratch-gui/static/images/aigc/ai_programming_avatar_01.png new file mode 100644 index 00000000..16544667 Binary files /dev/null and b/scratch-gui/static/images/aigc/ai_programming_avatar_01.png differ diff --git a/scratch-gui/static/images/aigc/ai_programming_avatar_02.png b/scratch-gui/static/images/aigc/ai_programming_avatar_02.png new file mode 100644 index 00000000..5cf6de6f Binary files /dev/null and b/scratch-gui/static/images/aigc/ai_programming_avatar_02.png differ diff --git a/scratch-gui/static/images/aigc/ai_programming_avatar_03.png b/scratch-gui/static/images/aigc/ai_programming_avatar_03.png new file mode 100644 index 00000000..07696bc5 Binary files /dev/null and b/scratch-gui/static/images/aigc/ai_programming_avatar_03.png differ diff --git a/scratch-gui/static/images/aigc/ai_programming_avatar_04.png b/scratch-gui/static/images/aigc/ai_programming_avatar_04.png new file mode 100644 index 00000000..25382903 Binary files /dev/null and b/scratch-gui/static/images/aigc/ai_programming_avatar_04.png differ diff --git a/scratch-gui/static/images/aigc/ai_programming_avatar_05.png b/scratch-gui/static/images/aigc/ai_programming_avatar_05.png new file mode 100644 index 00000000..17a28f87 Binary files /dev/null and b/scratch-gui/static/images/aigc/ai_programming_avatar_05.png differ diff --git a/scratch-gui/static/images/aigc/ai_programming_avatar_06.png b/scratch-gui/static/images/aigc/ai_programming_avatar_06.png new file mode 100644 index 00000000..18807006 Binary files /dev/null and b/scratch-gui/static/images/aigc/ai_programming_avatar_06.png differ diff --git a/scratch-gui/static/images/aigc/ai_programming_avatar_07.png b/scratch-gui/static/images/aigc/ai_programming_avatar_07.png new file mode 100644 index 00000000..c026156d Binary files /dev/null and b/scratch-gui/static/images/aigc/ai_programming_avatar_07.png differ diff --git a/scratch-gui/static/images/aigc/ai_programming_avatar_08.png b/scratch-gui/static/images/aigc/ai_programming_avatar_08.png new file mode 100644 index 00000000..47f69a4f Binary files /dev/null and b/scratch-gui/static/images/aigc/ai_programming_avatar_08.png differ diff --git a/scratch-gui/static/images/aigc/ai_programming_avatar_09.png b/scratch-gui/static/images/aigc/ai_programming_avatar_09.png new file mode 100644 index 00000000..ddc8314c Binary files /dev/null and b/scratch-gui/static/images/aigc/ai_programming_avatar_09.png differ diff --git a/scratch-gui/static/images/aigc/ai_programming_avatar_10.png b/scratch-gui/static/images/aigc/ai_programming_avatar_10.png new file mode 100644 index 00000000..daaca72d Binary files /dev/null and b/scratch-gui/static/images/aigc/ai_programming_avatar_10.png differ diff --git a/scratch-gui/static/images/aigc/ai_programming_avatar_11.png b/scratch-gui/static/images/aigc/ai_programming_avatar_11.png new file mode 100644 index 00000000..b83b09c6 Binary files /dev/null and b/scratch-gui/static/images/aigc/ai_programming_avatar_11.png differ diff --git a/scratch-gui/static/images/aigc/ai_programming_avatar_12.png b/scratch-gui/static/images/aigc/ai_programming_avatar_12.png new file mode 100644 index 00000000..3fe51707 Binary files /dev/null and b/scratch-gui/static/images/aigc/ai_programming_avatar_12.png differ diff --git a/scratch-gui/static/images/aigc/icon-ai-huiben.png b/scratch-gui/static/images/aigc/icon-ai-huiben.png new file mode 100644 index 00000000..3119124e Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-ai-huiben.png differ diff --git a/scratch-gui/static/images/aigc/icon-ai-huitu.png b/scratch-gui/static/images/aigc/icon-ai-huitu.png new file mode 100644 index 00000000..201eb7ba Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-ai-huitu.png differ diff --git a/scratch-gui/static/images/aigc/icon-ai-music.png b/scratch-gui/static/images/aigc/icon-ai-music.png new file mode 100644 index 00000000..244eb569 Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-ai-music.png differ diff --git a/scratch-gui/static/images/aigc/icon-ai-shiping.png b/scratch-gui/static/images/aigc/icon-ai-shiping.png new file mode 100644 index 00000000..53d2e0c5 Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-ai-shiping.png differ diff --git a/scratch-gui/static/images/aigc/icon-ai-wenben.png b/scratch-gui/static/images/aigc/icon-ai-wenben.png new file mode 100644 index 00000000..82cfe36b Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-ai-wenben.png differ diff --git a/scratch-gui/static/images/aigc/icon-ai-yuying.png b/scratch-gui/static/images/aigc/icon-ai-yuying.png new file mode 100644 index 00000000..7045ac5b Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-ai-yuying.png differ diff --git a/scratch-gui/static/images/aigc/icon-beat-boom.png b/scratch-gui/static/images/aigc/icon-beat-boom.png new file mode 100644 index 00000000..496b4125 Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-beat-boom.png differ diff --git a/scratch-gui/static/images/aigc/icon-beat-chinese.png b/scratch-gui/static/images/aigc/icon-beat-chinese.png new file mode 100644 index 00000000..158fe0b4 Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-beat-chinese.png differ diff --git a/scratch-gui/static/images/aigc/icon-beat-edm.png b/scratch-gui/static/images/aigc/icon-beat-edm.png new file mode 100644 index 00000000..a87fda6d Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-beat-edm.png differ diff --git a/scratch-gui/static/images/aigc/icon-beat-jazz.png b/scratch-gui/static/images/aigc/icon-beat-jazz.png new file mode 100644 index 00000000..35292971 Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-beat-jazz.png differ diff --git a/scratch-gui/static/images/aigc/icon-beat-latin.png b/scratch-gui/static/images/aigc/icon-beat-latin.png new file mode 100644 index 00000000..382bb5bd Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-beat-latin.png differ diff --git a/scratch-gui/static/images/aigc/icon-beat-march.png b/scratch-gui/static/images/aigc/icon-beat-march.png new file mode 100644 index 00000000..43d32ab4 Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-beat-march.png differ diff --git a/scratch-gui/static/images/aigc/icon-beat-rock.png b/scratch-gui/static/images/aigc/icon-beat-rock.png new file mode 100644 index 00000000..4e0ab659 Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-beat-rock.png differ diff --git a/scratch-gui/static/images/aigc/icon-beat-waltz.png b/scratch-gui/static/images/aigc/icon-beat-waltz.png new file mode 100644 index 00000000..caa48437 Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-beat-waltz.png differ diff --git a/scratch-gui/static/images/aigc/icon-draw-doodle.png b/scratch-gui/static/images/aigc/icon-draw-doodle.png new file mode 100644 index 00000000..0b7adb9a Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-draw-doodle.png differ diff --git a/scratch-gui/static/images/aigc/icon-draw-paint.png b/scratch-gui/static/images/aigc/icon-draw-paint.png new file mode 100644 index 00000000..f1e5b2f8 Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-draw-paint.png differ diff --git a/scratch-gui/static/images/aigc/icon-draw-style.png b/scratch-gui/static/images/aigc/icon-draw-style.png new file mode 100644 index 00000000..f0adc57f Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-draw-style.png differ diff --git a/scratch-gui/static/images/aigc/icon-draw-upload.png b/scratch-gui/static/images/aigc/icon-draw-upload.png new file mode 100644 index 00000000..33308aed Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-draw-upload.png differ diff --git a/scratch-gui/static/images/aigc/icon-empty.png b/scratch-gui/static/images/aigc/icon-empty.png new file mode 100644 index 00000000..2d322182 Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-empty.png differ diff --git a/scratch-gui/static/images/aigc/icon-inst-drums.png b/scratch-gui/static/images/aigc/icon-inst-drums.png new file mode 100644 index 00000000..3f80ae83 Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-inst-drums.png differ diff --git a/scratch-gui/static/images/aigc/icon-inst-guitar.png b/scratch-gui/static/images/aigc/icon-inst-guitar.png new file mode 100644 index 00000000..33e9ca9a Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-inst-guitar.png differ diff --git a/scratch-gui/static/images/aigc/icon-inst-piano.png b/scratch-gui/static/images/aigc/icon-inst-piano.png new file mode 100644 index 00000000..ce10a299 Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-inst-piano.png differ diff --git a/scratch-gui/static/images/aigc/icon-inst-synth.png b/scratch-gui/static/images/aigc/icon-inst-synth.png new file mode 100644 index 00000000..a78a9b60 Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-inst-synth.png differ diff --git a/scratch-gui/static/images/aigc/icon-inst-trumpet.png b/scratch-gui/static/images/aigc/icon-inst-trumpet.png new file mode 100644 index 00000000..6a8a8822 Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-inst-trumpet.png differ diff --git a/scratch-gui/static/images/aigc/icon-inst-violin.png b/scratch-gui/static/images/aigc/icon-inst-violin.png new file mode 100644 index 00000000..78fc830c Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-inst-violin.png differ diff --git a/scratch-gui/static/images/aigc/icon-music-beat.png b/scratch-gui/static/images/aigc/icon-music-beat.png new file mode 100644 index 00000000..3592fb5f Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-music-beat.png differ diff --git a/scratch-gui/static/images/aigc/icon-music-compose.png b/scratch-gui/static/images/aigc/icon-music-compose.png new file mode 100644 index 00000000..1d67a615 Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-music-compose.png differ diff --git a/scratch-gui/static/images/aigc/icon-music-library.png b/scratch-gui/static/images/aigc/icon-music-library.png new file mode 100644 index 00000000..d01dac78 Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-music-library.png differ diff --git a/scratch-gui/static/images/aigc/icon-music-melody.png b/scratch-gui/static/images/aigc/icon-music-melody.png new file mode 100644 index 00000000..5296c3fb Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-music-melody.png differ diff --git a/scratch-gui/static/images/aigc/icon-video-image.png b/scratch-gui/static/images/aigc/icon-video-image.png new file mode 100644 index 00000000..8f6c0b2e Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-video-image.png differ diff --git a/scratch-gui/static/images/aigc/icon-video-style.png b/scratch-gui/static/images/aigc/icon-video-style.png new file mode 100644 index 00000000..bdc52b5b Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-video-style.png differ diff --git a/scratch-gui/static/images/aigc/icon-video-text.png b/scratch-gui/static/images/aigc/icon-video-text.png new file mode 100644 index 00000000..ffb54498 Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-video-text.png differ diff --git a/scratch-gui/static/images/aigc/icon-video-upload.png b/scratch-gui/static/images/aigc/icon-video-upload.png new file mode 100644 index 00000000..6762ec3e Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-video-upload.png differ diff --git a/scratch-gui/static/images/aigc/icon-voice-change.png b/scratch-gui/static/images/aigc/icon-voice-change.png new file mode 100644 index 00000000..4869ee05 Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-voice-change.png differ diff --git a/scratch-gui/static/images/aigc/icon-voice-dialect.png b/scratch-gui/static/images/aigc/icon-voice-dialect.png new file mode 100644 index 00000000..2d5c08c5 Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-voice-dialect.png differ diff --git a/scratch-gui/static/images/aigc/icon-voice-mic.png b/scratch-gui/static/images/aigc/icon-voice-mic.png new file mode 100644 index 00000000..fb6a99d1 Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-voice-mic.png differ diff --git a/scratch-gui/static/images/aigc/icon-voice-tts.png b/scratch-gui/static/images/aigc/icon-voice-tts.png new file mode 100644 index 00000000..2f3ef600 Binary files /dev/null and b/scratch-gui/static/images/aigc/icon-voice-tts.png differ diff --git a/scratch-gui/static/images/aigc/icon2.png b/scratch-gui/static/images/aigc/icon2.png new file mode 100644 index 00000000..baf5838d Binary files /dev/null and b/scratch-gui/static/images/aigc/icon2.png differ diff --git a/scratch-gui/static/images/aigc/icon3.png b/scratch-gui/static/images/aigc/icon3.png new file mode 100644 index 00000000..aaa60f83 Binary files /dev/null and b/scratch-gui/static/images/aigc/icon3.png differ diff --git a/scratch-gui/static/images/aigc/icon_book.png b/scratch-gui/static/images/aigc/icon_book.png new file mode 100644 index 00000000..69a1d118 Binary files /dev/null and b/scratch-gui/static/images/aigc/icon_book.png differ diff --git a/scratch-gui/static/images/aigc/iocn1.png b/scratch-gui/static/images/aigc/iocn1.png new file mode 100644 index 00000000..faf2e788 Binary files /dev/null and b/scratch-gui/static/images/aigc/iocn1.png differ diff --git a/scratch-gui/static/images/aigc/kecheng1.png b/scratch-gui/static/images/aigc/kecheng1.png new file mode 100644 index 00000000..fee5e284 Binary files /dev/null and b/scratch-gui/static/images/aigc/kecheng1.png differ diff --git a/scratch-gui/static/images/aigc/kecheng2.png b/scratch-gui/static/images/aigc/kecheng2.png new file mode 100644 index 00000000..8a13558a Binary files /dev/null and b/scratch-gui/static/images/aigc/kecheng2.png differ diff --git a/scratch-gui/static/images/aigc/kecheng3.png b/scratch-gui/static/images/aigc/kecheng3.png new file mode 100644 index 00000000..76704c6a Binary files /dev/null and b/scratch-gui/static/images/aigc/kecheng3.png differ diff --git a/scratch-gui/static/images/aigc/kecheng4.png b/scratch-gui/static/images/aigc/kecheng4.png new file mode 100644 index 00000000..68f31cf5 Binary files /dev/null and b/scratch-gui/static/images/aigc/kecheng4.png differ diff --git a/scratch-gui/static/images/aigc/lingqi-ai-logo.png b/scratch-gui/static/images/aigc/lingqi-ai-logo.png new file mode 100644 index 00000000..a7476211 Binary files /dev/null and b/scratch-gui/static/images/aigc/lingqi-ai-logo.png differ diff --git a/scratch-gui/static/images/aigc/logo.png b/scratch-gui/static/images/aigc/logo.png new file mode 100644 index 00000000..f6d291a0 Binary files /dev/null and b/scratch-gui/static/images/aigc/logo.png differ diff --git a/scratch-gui/static/images/aigc/scene-aurora.png b/scratch-gui/static/images/aigc/scene-aurora.png new file mode 100644 index 00000000..f337688d Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-aurora.png differ diff --git a/scratch-gui/static/images/aigc/scene-bamboo.png b/scratch-gui/static/images/aigc/scene-bamboo.png new file mode 100644 index 00000000..2cce2f0d Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-bamboo.png differ diff --git a/scratch-gui/static/images/aigc/scene-blackhole.png b/scratch-gui/static/images/aigc/scene-blackhole.png new file mode 100644 index 00000000..e570fb4d Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-blackhole.png differ diff --git a/scratch-gui/static/images/aigc/scene-candy.png b/scratch-gui/static/images/aigc/scene-candy.png new file mode 100644 index 00000000..444a3ecb Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-candy.png differ diff --git a/scratch-gui/static/images/aigc/scene-cloud-castle.png b/scratch-gui/static/images/aigc/scene-cloud-castle.png new file mode 100644 index 00000000..c5eba412 Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-cloud-castle.png differ diff --git a/scratch-gui/static/images/aigc/scene-cyber.png b/scratch-gui/static/images/aigc/scene-cyber.png new file mode 100644 index 00000000..6f094a12 Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-cyber.png differ diff --git a/scratch-gui/static/images/aigc/scene-desert.png b/scratch-gui/static/images/aigc/scene-desert.png new file mode 100644 index 00000000..08590e65 Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-desert.png differ diff --git a/scratch-gui/static/images/aigc/scene-dino.png b/scratch-gui/static/images/aigc/scene-dino.png new file mode 100644 index 00000000..5047c681 Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-dino.png differ diff --git a/scratch-gui/static/images/aigc/scene-dragon.png b/scratch-gui/static/images/aigc/scene-dragon.png new file mode 100644 index 00000000..56329584 Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-dragon.png differ diff --git a/scratch-gui/static/images/aigc/scene-fairytale.png b/scratch-gui/static/images/aigc/scene-fairytale.png new file mode 100644 index 00000000..b3030a0a Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-fairytale.png differ diff --git a/scratch-gui/static/images/aigc/scene-forest.png b/scratch-gui/static/images/aigc/scene-forest.png new file mode 100644 index 00000000..3a285fed Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-forest.png differ diff --git a/scratch-gui/static/images/aigc/scene-ice.png b/scratch-gui/static/images/aigc/scene-ice.png new file mode 100644 index 00000000..13a9a2bd Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-ice.png differ diff --git a/scratch-gui/static/images/aigc/scene-meadow.png b/scratch-gui/static/images/aigc/scene-meadow.png new file mode 100644 index 00000000..4533dfab Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-meadow.png differ diff --git a/scratch-gui/static/images/aigc/scene-moonbase.png b/scratch-gui/static/images/aigc/scene-moonbase.png new file mode 100644 index 00000000..5b470f24 Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-moonbase.png differ diff --git a/scratch-gui/static/images/aigc/scene-nightmarket.png b/scratch-gui/static/images/aigc/scene-nightmarket.png new file mode 100644 index 00000000..194690c9 Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-nightmarket.png differ diff --git a/scratch-gui/static/images/aigc/scene-ocean.png b/scratch-gui/static/images/aigc/scene-ocean.png new file mode 100644 index 00000000..c6b4b262 Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-ocean.png differ diff --git a/scratch-gui/static/images/aigc/scene-pirate.png b/scratch-gui/static/images/aigc/scene-pirate.png new file mode 100644 index 00000000..3e24f574 Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-pirate.png differ diff --git a/scratch-gui/static/images/aigc/scene-rainbow.png b/scratch-gui/static/images/aigc/scene-rainbow.png new file mode 100644 index 00000000..4102d2be Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-rainbow.png differ diff --git a/scratch-gui/static/images/aigc/scene-rainforest.png b/scratch-gui/static/images/aigc/scene-rainforest.png new file mode 100644 index 00000000..aeb555be Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-rainforest.png differ diff --git a/scratch-gui/static/images/aigc/scene-robotfactory.png b/scratch-gui/static/images/aigc/scene-robotfactory.png new file mode 100644 index 00000000..715f63e8 Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-robotfactory.png differ diff --git a/scratch-gui/static/images/aigc/scene-ruins.png b/scratch-gui/static/images/aigc/scene-ruins.png new file mode 100644 index 00000000..2c8cc2a6 Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-ruins.png differ diff --git a/scratch-gui/static/images/aigc/scene-sakura.png b/scratch-gui/static/images/aigc/scene-sakura.png new file mode 100644 index 00000000..03760187 Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-sakura.png differ diff --git a/scratch-gui/static/images/aigc/scene-skytrain.png b/scratch-gui/static/images/aigc/scene-skytrain.png new file mode 100644 index 00000000..225c4461 Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-skytrain.png differ diff --git a/scratch-gui/static/images/aigc/scene-space.png b/scratch-gui/static/images/aigc/scene-space.png new file mode 100644 index 00000000..c7e8e9db Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-space.png differ diff --git a/scratch-gui/static/images/aigc/scene-sportsday.png b/scratch-gui/static/images/aigc/scene-sportsday.png new file mode 100644 index 00000000..fc741bd2 Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-sportsday.png differ diff --git a/scratch-gui/static/images/aigc/scene-starcamp.png b/scratch-gui/static/images/aigc/scene-starcamp.png new file mode 100644 index 00000000..a6e1fba6 Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-starcamp.png differ diff --git a/scratch-gui/static/images/aigc/scene-steampunk.png b/scratch-gui/static/images/aigc/scene-steampunk.png new file mode 100644 index 00000000..28b96d5e Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-steampunk.png differ diff --git a/scratch-gui/static/images/aigc/scene-volcano.png b/scratch-gui/static/images/aigc/scene-volcano.png new file mode 100644 index 00000000..793b467f Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-volcano.png differ diff --git a/scratch-gui/static/images/aigc/scene-waterpark.png b/scratch-gui/static/images/aigc/scene-waterpark.png new file mode 100644 index 00000000..db859cf7 Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-waterpark.png differ diff --git a/scratch-gui/static/images/aigc/scene-wormhole.png b/scratch-gui/static/images/aigc/scene-wormhole.png new file mode 100644 index 00000000..5d59d1d1 Binary files /dev/null and b/scratch-gui/static/images/aigc/scene-wormhole.png differ diff --git a/scratch-gui/static/images/aigc/theme-adventure.png b/scratch-gui/static/images/aigc/theme-adventure.png new file mode 100644 index 00000000..4a6ffabc Binary files /dev/null and b/scratch-gui/static/images/aigc/theme-adventure.png differ diff --git a/scratch-gui/static/images/aigc/theme-arcade.png b/scratch-gui/static/images/aigc/theme-arcade.png new file mode 100644 index 00000000..c35396c2 Binary files /dev/null and b/scratch-gui/static/images/aigc/theme-arcade.png differ diff --git a/scratch-gui/static/images/aigc/theme-beach.png b/scratch-gui/static/images/aigc/theme-beach.png new file mode 100644 index 00000000..4f39c60e Binary files /dev/null and b/scratch-gui/static/images/aigc/theme-beach.png differ diff --git a/scratch-gui/static/images/aigc/theme-birthday.png b/scratch-gui/static/images/aigc/theme-birthday.png new file mode 100644 index 00000000..cb2eb124 Binary files /dev/null and b/scratch-gui/static/images/aigc/theme-birthday.png differ diff --git a/scratch-gui/static/images/aigc/theme-cafe.png b/scratch-gui/static/images/aigc/theme-cafe.png new file mode 100644 index 00000000..56fd10a2 Binary files /dev/null and b/scratch-gui/static/images/aigc/theme-cafe.png differ diff --git a/scratch-gui/static/images/aigc/theme-campus.png b/scratch-gui/static/images/aigc/theme-campus.png new file mode 100644 index 00000000..b17debdd Binary files /dev/null and b/scratch-gui/static/images/aigc/theme-campus.png differ diff --git a/scratch-gui/static/images/aigc/theme-cheer.png b/scratch-gui/static/images/aigc/theme-cheer.png new file mode 100644 index 00000000..6b558f1c Binary files /dev/null and b/scratch-gui/static/images/aigc/theme-cheer.png differ diff --git a/scratch-gui/static/images/aigc/theme-circus.png b/scratch-gui/static/images/aigc/theme-circus.png new file mode 100644 index 00000000..84492883 Binary files /dev/null and b/scratch-gui/static/images/aigc/theme-circus.png differ diff --git a/scratch-gui/static/images/aigc/theme-dream.png b/scratch-gui/static/images/aigc/theme-dream.png new file mode 100644 index 00000000..b937ebd9 Binary files /dev/null and b/scratch-gui/static/images/aigc/theme-dream.png differ diff --git a/scratch-gui/static/images/aigc/theme-exam.png b/scratch-gui/static/images/aigc/theme-exam.png new file mode 100644 index 00000000..37e2b852 Binary files /dev/null and b/scratch-gui/static/images/aigc/theme-exam.png differ diff --git a/scratch-gui/static/images/aigc/theme-fireplace.png b/scratch-gui/static/images/aigc/theme-fireplace.png new file mode 100644 index 00000000..d25389b1 Binary files /dev/null and b/scratch-gui/static/images/aigc/theme-fireplace.png differ diff --git a/scratch-gui/static/images/aigc/theme-graduation.png b/scratch-gui/static/images/aigc/theme-graduation.png new file mode 100644 index 00000000..181eb49d Binary files /dev/null and b/scratch-gui/static/images/aigc/theme-graduation.png differ diff --git a/scratch-gui/static/images/aigc/theme-lullaby.png b/scratch-gui/static/images/aigc/theme-lullaby.png new file mode 100644 index 00000000..eaca5d27 Binary files /dev/null and b/scratch-gui/static/images/aigc/theme-lullaby.png differ diff --git a/scratch-gui/static/images/aigc/theme-midautumn.png b/scratch-gui/static/images/aigc/theme-midautumn.png new file mode 100644 index 00000000..333859ea Binary files /dev/null and b/scratch-gui/static/images/aigc/theme-midautumn.png differ diff --git a/scratch-gui/static/images/aigc/theme-rainy.png b/scratch-gui/static/images/aigc/theme-rainy.png new file mode 100644 index 00000000..3be6b999 Binary files /dev/null and b/scratch-gui/static/images/aigc/theme-rainy.png differ diff --git a/scratch-gui/static/images/aigc/theme-reunion.png b/scratch-gui/static/images/aigc/theme-reunion.png new file mode 100644 index 00000000..b8a079b6 Binary files /dev/null and b/scratch-gui/static/images/aigc/theme-reunion.png differ diff --git a/scratch-gui/static/images/aigc/theme-wedding.png b/scratch-gui/static/images/aigc/theme-wedding.png new file mode 100644 index 00000000..9cf9f854 Binary files /dev/null and b/scratch-gui/static/images/aigc/theme-wedding.png differ diff --git a/scratch-gui/static/images/aigc/work-fox-autumn.png b/scratch-gui/static/images/aigc/work-fox-autumn.png new file mode 100644 index 00000000..aac6e5a2 Binary files /dev/null and b/scratch-gui/static/images/aigc/work-fox-autumn.png differ diff --git a/scratch-gui/static/images/aigc/work-ink-mountain.png b/scratch-gui/static/images/aigc/work-ink-mountain.png new file mode 100644 index 00000000..bde4c4b8 Binary files /dev/null and b/scratch-gui/static/images/aigc/work-ink-mountain.png differ diff --git a/scratch-gui/static/images/aigc/work-oil-rabbit.png b/scratch-gui/static/images/aigc/work-oil-rabbit.png new file mode 100644 index 00000000..fd92bb3b Binary files /dev/null and b/scratch-gui/static/images/aigc/work-oil-rabbit.png differ diff --git a/scratch-gui/static/images/aigc/work-pixel-ocean.png b/scratch-gui/static/images/aigc/work-pixel-ocean.png new file mode 100644 index 00000000..5888063c Binary files /dev/null and b/scratch-gui/static/images/aigc/work-pixel-ocean.png differ diff --git a/scratch-gui/static/images/aigc/work-sky-islands.png b/scratch-gui/static/images/aigc/work-sky-islands.png new file mode 100644 index 00000000..deba4f72 Binary files /dev/null and b/scratch-gui/static/images/aigc/work-sky-islands.png differ diff --git a/scratch-gui/static/images/aigc/work-watercolor-astro.png b/scratch-gui/static/images/aigc/work-watercolor-astro.png new file mode 100644 index 00000000..685effca Binary files /dev/null and b/scratch-gui/static/images/aigc/work-watercolor-astro.png differ diff --git a/scratch-gui/static/images/default_compertion.png b/scratch-gui/static/images/default_compertion.png new file mode 100644 index 00000000..6a872c11 Binary files /dev/null and b/scratch-gui/static/images/default_compertion.png differ diff --git a/scratch-gui/static/images/w b/scratch-gui/static/images/w new file mode 100644 index 00000000..5aa1b602 Binary files /dev/null and b/scratch-gui/static/images/w differ diff --git a/scratch-gui/static/images/wang.jpg b/scratch-gui/static/images/wang.jpg new file mode 100644 index 00000000..a1ba2f31 Binary files /dev/null and b/scratch-gui/static/images/wang.jpg differ diff --git a/scratch-gui/static/js/nav-responsive.js b/scratch-gui/static/js/nav-responsive.js new file mode 100644 index 00000000..308b2656 --- /dev/null +++ b/scratch-gui/static/js/nav-responsive.js @@ -0,0 +1,55 @@ +// 响应式导航(home / ai / competition_list / aboutus 共用): +// 页面在 header 内放置