diff --git a/Www/ejs/MainWindow/MainWindow.ejs b/Www/ejs/MainWindow/MainWindow.ejs index 2cc0fd24..048c1600 100644 --- a/Www/ejs/MainWindow/MainWindow.ejs +++ b/Www/ejs/MainWindow/MainWindow.ejs @@ -11,58 +11,19 @@ - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + diff --git a/Www/ejs/SettingWindow/SettingWindow.ejs b/Www/ejs/SettingWindow/SettingWindow.ejs index 3445ad2d..88b9a814 100644 --- a/Www/ejs/SettingWindow/SettingWindow.ejs +++ b/Www/ejs/SettingWindow/SettingWindow.ejs @@ -17,36 +17,22 @@ - + - + - - - - - - - - - - - - - - - - - + + + diff --git a/Www/gulpfile.js b/Www/gulpfile.js index 5d07f9e6..15a05502 100644 --- a/Www/gulpfile.js +++ b/Www/gulpfile.js @@ -44,46 +44,61 @@ gulp.task("svg", async () => { // scss -> css gulp.task("scss", async () => { await sleep(1); - return gulp.src("./scss/**/*.scss") // 指定要處理的 Scss 檔案目錄 + gulp.src("./scss/MainWindow/MainWindow.scss") // 指定要處理的 Scss 檔案目錄 .pipe(sass({ // outputStyle: "compressed", // 壓縮 })) .pipe(gulp.dest("./css")) // 指定編譯後的 css 檔案目錄 .pipe(gulp.dest(output2 + "/css")) + gulp.src("./scss/SettingWindow/SettingWindow.scss") + .pipe(sass({ + })) + .pipe(gulp.dest("./css")) + .pipe(gulp.dest(output2 + "/css")) }); // ejs -> html -gulp.task("ejs-main", async () => { +gulp.task("ejs", async () => { await sleep(1); - return gulp.src("./ejs/MainWindow/MainWindow.ejs") + gulp.src("./ejs/MainWindow/MainWindow.ejs") .pipe(ejs({ readFile: readFile }, { async: true })) .pipe(rename({ extname: ".html" })) // 修改輸出的副檔名 .pipe(gulp.dest("./")) .pipe(gulp.dest(output2 + "/")) -}); -gulp.task("ejs-setting", async () => { - await sleep(1); - return gulp.src("./ejs/SettingWindow/SettingWindow.ejs") + + gulp.src("./ejs/SettingWindow/SettingWindow.ejs") .pipe(ejs({ readFile: readFile }, { async: true })) .pipe(rename({ extname: ".html" })) .pipe(gulp.dest("./")) .pipe(gulp.dest(output2 + "/")) - }); // ts -> js gulp.task("ts", async () => { await sleep(1); - return gulp.src("./ts/**/*.ts") - .pipe(gulpEsbuild({ - // minify: true, // 壓縮 - // outfile: "bundle.js", - // bundle: true, - // loader: { ".tsx": "tsx", }, - })) - .pipe(gulp.dest("./js")) - .pipe(gulp.dest(output2 + "/js")) + + var fileMappings = [ + { path: "./ts/MainWindow/MainWindow.ts", bundle: true }, + { path: "./ts/SettingWindow/SettingWindow.ts", bundle: true }, + { path: "./ts/TiefseeviewWorker.ts", bundle: true }, + { path: "./ts/TiefseeviewWorkerSub.ts", bundle: true }, + { path: "./ts/LibIframe.ts", bundle: false }, + ]; + + for (var i = 0; i < fileMappings.length; i++) { + + gulp.src(fileMappings[i].path) + .pipe(gulpEsbuild({ + // minify: true, // 壓縮 + outfile: path.basename(fileMappings[i].path, ".ts") + ".js", + bundle: fileMappings[i].bundle, + // loader: { ".tsx": "tsx", }, + })) + .pipe(gulp.dest("./js")) + .pipe(gulp.dest(output2 + "/js")) + } + }); // 把檔案複製到開發資料夾。 (有非 ts、scss、ejs 的資源需要複製到開發資料夾時使用 @@ -117,17 +132,16 @@ gulp.task("build-rust", (done) => { }); // 打包 - 單次 -gulp.task("build", gulp.series("scss", "ts", "svg", "ejs-main", "ejs-setting", "build-rust", +gulp.task("build", gulp.series("scss", "ts", "svg", "ejs", "build-rust", "copy-files")); // copy-files 必須放在最後 // 打包 - 持續監控檔案變化 -gulp.task("watch", gulp.series("scss", "ts", "svg", "ejs-main", "ejs-setting", () => { +gulp.task("watch", gulp.series("scss", "ts", "svg", "ejs", () => { gulp.watch("./scss/**/*.scss", gulp.series("scss")); gulp.watch("./ts/**/*.ts", gulp.series("ts")); - gulp.watch("./ejs/MainWindow/*.ejs", gulp.series("ejs-main")); - gulp.watch("./ejs/SettingWindow/*.ejs", gulp.series("ejs-setting")); + gulp.watch("./ejs/**/*.ejs", gulp.series("ejs")); - gulp.watch("./img/default/*.svg", gulp.series("ejs-main")); // svg 圖示 + gulp.watch("./img/default/*.svg", gulp.series("ejs")); // svg 有可能會被 ejs 引用,所以也要重新執行 ejs gulp.watch("./img/default/*.svg", gulp.series("svg")); })); diff --git a/Www/scss/BaseStyle.scss b/Www/scss/BaseStyle.scss deleted file mode 100644 index 9d37e30c..00000000 --- a/Www/scss/BaseStyle.scss +++ /dev/null @@ -1,151 +0,0 @@ -body, -input, -textarea, -button, -option, -optgroup { - // font-family: "Noto Sans TC","Noto Sans CJK TC Light"; - font-family: "Segoe UI", "Microsoft JhengHei UI"; - font-size: 15px; - font-weight: var(--fontWeight); -} - -select option, -select optgroup { - background: var(--color-black); -} - -//---------------------------------------------------------------- - -//滾動條樣式 (一般,寬度10px - -/*整體背景*/ -.base-scrollbar::-webkit-scrollbar { - width: 10px; - height: 10px; -} - -//滾動條軌道(移入時 -.base-scrollbar::-webkit-scrollbar-track:hover { - background-color: var(--color-black60); -} - -//拖曳區塊 -.base-scrollbar::-webkit-scrollbar-thumb { - background-color: var(--color-white40); - - //產生透明框線並且剪裁掉 - border: 3px solid rgba(0, 0, 0, 0); - background-clip: content-box; - min-height: 50px; -} - -//右下角交匯處 -.base-scrollbar::-webkit-scrollbar-corner { - background-color: rgba(0, 0, 0, 0); -} - -//---------------------------------------------------------------- - -//滾動條樣式 (大型、寬度16px - -//整體背景 -.base-scrollbar-big::-webkit-scrollbar { - width: 16px; - height: 10px; -} - -//滾動條軌道(移入時 -.base-scrollbar-big::-webkit-scrollbar-track:hover { - background-color: var(--color-black60); - //產生透明框線並且剪裁掉 - border-left: 6px solid rgba(0, 0, 0, 0); - border-right: 0px solid rgba(0, 0, 0, 0); - background-clip: content-box; -} - -/*拖曳區塊*/ -.base-scrollbar-big::-webkit-scrollbar-thumb { - background-color: var(--color-white40); - //產生透明框線並且剪裁掉 - border-left: 9px solid rgba(0, 0, 0, 0); - border-right: 3px solid rgba(0, 0, 0, 0); - border-top: 3px solid rgba(0, 0, 0, 0); - border-bottom: 3px solid rgba(0, 0, 0, 0); - background-clip: content-box; - min-height: 50px; -} - -//右下角交匯處 -.base-scrollbar-big::-webkit-scrollbar-corner { - background-color: rgba(0, 0, 0, 0); -} - -//---------------------------------------------------------------- - -// checkbox 樣式 - -.base-checkbox { - appearance: none; - margin: 0 3px; - font: inherit; - color: currentColor; - width: 15px; - height: 15px; - border: 1px solid var(--color-white40); - border-radius: 4px; - display: grid; - place-content: center; -} - -.base-checkbox::before { - content: ""; - width: 10px; - height: 10px; - clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%); - transform: scale(0); - transform-origin: bottom left; - transition: 0.1s transform ease-in-out; - box-shadow: inset 10px 10px var(--color-blue); -} - -.base-checkbox:checked::before { - transform: scale(1); -} - -//---------------------------------------------------------------- - -// radio 樣式 -.base-radio { - appearance: none; - //margin: 0; - width: 14px; - height: 14px; - border: 1px solid var(--color-white); - border-radius: 50%; - position: relative; - margin: 0 4px; - //margin-top: 1px; - //transform: translateY(1px); -} -.base-radio:before { - content: ""; - position: absolute; - border-radius: 4px; - width: 6px; - height: 6px; - // top: 3px; - // left: 3px; - top: 0; - left: 0; - right: 0; - bottom: 0; - margin: auto; - background-color: var(--color-blue); - transform: scale(0); - //transform-origin: bottom left; - transition: 0.1s transform ease-in-out; -} -.base-radio:checked::before { - transform: scale(1); -} diff --git a/Www/scss/BaseWindow.scss b/Www/scss/BaseWindow.scss deleted file mode 100644 index 9ede9ad8..00000000 --- a/Www/scss/BaseWindow.scss +++ /dev/null @@ -1,233 +0,0 @@ -@import "./BaseStyle"; - -:root { - /** 可拖曳的邊框 */ - --window-border: 4px; - /** 可拖曳的四個角落 */ - --window-border-corner: 20px; - /** 視窗圓角 */ - --window-border-radius: 0px; - - --color-window-border: rgba(255, 255, 255, 0.25); - --color-window-background: rgba(31, 39, 43, 0.97); - - //一般文字 - --fontWeight: 400; - //粗體字 - --fontWeightBold: 500; - - //區塊顏色 - --color-black: rgba(0, 0, 0, 1); - --color-black80: rgba(0, 0, 0, 0.8); - --color-black60: rgba(0, 0, 0, 0.6); - --color-black40: rgba(0, 0, 0, 0.4); - --color-black20: rgba(0, 0, 0, 0.2); - - //未使用 - --color-grey: rgba(30, 30, 30, 1); - --color-grey80: rgba(30, 30, 30, 0.8); - --color-grey60: rgba(30, 30, 30, 0.6); - --color-grey40: rgba(30, 30, 30, 0.4); - --color-grey20: rgba(30, 30, 30, 0.2); - - //文字顏色、圖示顏色 - --color-white: rgb(255, 255, 255); - --color-white80: rgba(255, 255, 255, 0.8); - --color-white60: rgba(255, 255, 255, 0.6); - --color-white40: rgba(255, 255, 255, 0.4); - --color-white30: rgba(255, 255, 255, 0.3); - --color-white20: rgba(255, 255, 255, 0.2); - --color-white10: rgba(255, 255, 255, 0.1); - - //用於醒目的顏色 - --color-blue: rgb(0, 200, 255); - --color-blue80: rgba(0, 200, 255, 0.8); - --color-blue60: rgba(0, 200, 255, 0.6); - --color-blue40: rgba(0, 200, 255, 0.4); - --color-blue20: rgba(0, 200, 255, 0.2); -} - -* { - box-sizing: border-box; -} - -html, -body { - margin: 0; - padding: 0; - height: 100%; -} - -body { - display: flex; - overflow: hidden; -} - -/* 視窗本體 */ -.window { - /* transition: transform 0.2s; - transform: translateY(10px) scale(0.98); */ - flex: 1; - position: fixed; - top: 0px; - left: 0px; - right: 1.5px; - bottom: 1.5px; - overflow: hidden; - background-color: var(--color-window-background); - border-radius: var(--window-border-radius); - border: 1px solid var(--color-window-border); - - //margin-right: 1.5px; - //margin-bottom: 1.5px; - display: flex; - flex-direction: column; -} - -// 視窗最大化時 -.window.maximized { - right: 0px !important; - bottom: 0px !important; - border: none; - border-radius: 0px; -} -.window.maximized .window-border { - display: none; -} -// win11 圓角 -.window.windowRoundedCorners { - right: 0.5px; - bottom: 0.5px; - border: none; - border-radius: 0px; -} -/*---------------------------*/ - -/* #region window-titlebar 標題列*/ - -/*標題列*/ -.window-titlebar { - height: 30px; - background-color: rgba(0, 0, 0, 0); - display: flex; - justify-content: space-between; - - .titlebar-text { - height: 100%; - color: var(--color-white); - display: flex; - align-items: center; - padding: 0 8px; - flex: 1; - user-select: none; - overflow: hidden; - - app-region: drag; //讓視窗允許拖曳 - } - .titlebar-text span { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - .titlebar-toolbar { - display: flex; - } - .titlebar-toolbar-btn { - height: 100%; - width: 38px; - margin-left: 1px; - display: flex; - justify-content: center; - align-items: center; - user-select: none; - /* border-radius: 4px; */ - } - - .titlebar-toolbar-btn:hover { - background-color: var(--color-white10); - cursor: pointer; - } - .titlebar-toolbar-btn svg { - width: 25px; - height: 25px; - pointer-events: none; - } -} -/* #endregion */ - -/*---------------------------*/ - -/* #region window-border 改變視窗大小的框 */ - -.window-border { - position: fixed; - z-index: 9999; - user-select: none; - app-region: no-drag; //讓視窗不允許拖曳 -} -.window-CT { - height: var(--window-border); - top: 0; - left: var(--window-border-corner); - right: var(--window-border); - cursor: n-resize; -} - -.window-RC { - width: var(--window-border); - top: var(--window-border); - right: 0; - bottom: var(--window-border-corner); - cursor: w-resize; -} - -.window-CB { - height: var(--window-border); - bottom: 0; - left: var(--window-border-corner); - right: var(--window-border-corner); - cursor: n-resize; -} - -.window-LC { - width: var(--window-border); - top: var(--window-border-corner); - left: 0; - bottom: var(--window-border-corner); - cursor: w-resize; -} - -.window-LT { - width: var(--window-border-corner); - height: var(--window-border-corner); - left: 0; - top: 0; - cursor: nw-resize; -} - -.window-RT { - width: var(--window-border); - height: var(--window-border); - right: 0; - top: 0; - cursor: ne-resize; -} - -.window-LB { - width: var(--window-border-corner); - height: var(--window-border-corner); - left: 0; - bottom: 0; - cursor: ne-resize; -} - -.window-RB { - width: var(--window-border-corner); - height: var(--window-border-corner); - right: 0; - bottom: 0; - cursor: nw-resize; -} - -/* #endregion */ diff --git a/Www/scss/MainWindow/MainWindow.scss b/Www/scss/MainWindow/MainWindow.scss index fa97c782..1f106d39 100644 --- a/Www/scss/MainWindow/MainWindow.scss +++ b/Www/scss/MainWindow/MainWindow.scss @@ -1,3 +1,9 @@ +@import "../BaseWindow"; +@import "../Menu"; +@import "../Msgbox"; +@import "../Toast"; +@import "../Tiefseeview"; + @import "./LargeBtn"; @import "./Dragbar"; @import "./MainDirList"; @@ -7,46 +13,44 @@ @import "./LoadingSetting"; @import "./BulkView"; -//------------------------------- - :root { - //圖示粗細 - --svgWeight: 0px; + //圖示粗細 + --svgWeight: 0px; } .titlebar-toolbar-btn svg, .main-toolbar-btn svg, .menu-hor-icon svg, .menu-grid-item svg { - stroke: var(--color-white); - stroke-width: var(--svgWeight); + stroke: var(--color-white); + stroke-width: var(--svgWeight); } //------------------------------- // 標題列按鈕展開下拉選單時 .titlebar-toolbar-btn.menuActive { - background-color: var(--color-white20); + background-color: var(--color-white20); } //------------------------------- //內容區塊 .window-body { - flex: 1; - display: flex; - height: 0; + flex: 1; + display: flex; + height: 0; } //------------------------------- .main-content { - display: flex; - flex-direction: column; - flex: 1; - width: 100%; - height: 100%; - position: relative; + display: flex; + flex-direction: column; + flex: 1; + width: 100%; + height: 100%; + position: relative; } //容器 - 上 @@ -59,28 +63,28 @@ //容器 - 中 (用於放 左中右容器) .main-C { - display: flex; - flex: 1 1 auto; - overflow: hidden; + display: flex; + flex: 1 1 auto; + overflow: hidden; } //容器 - 左 .main-L, .main-L2 { - height: 100%; - position: relative; + height: 100%; + position: relative; } //容器 - 右 .main-R { - height: 100%; - position: relative; + height: 100%; + position: relative; } //容器 - 中 (用於顯示主內容) .main-V { - flex: 1; - position: relative; + flex: 1; + position: relative; } //同時顯示檔案面板跟資料夾面板時,減少兩個項目之間的距離 @@ -91,132 +95,132 @@ //------------------------------- .mView-tiefseeview { - z-index: 1; - height: 100%; - width: 100%; + z-index: 1; + height: 100%; + width: 100%; } .mView-iframe { - height: 100%; - width: 100%; - border: none; - user-select: none; - position: relative; + height: 100%; + width: 100%; + border: none; + user-select: none; + position: relative; } .mView-text { - height: 100%; - width: 100%; - border: none; - color: var(--color-white); - background-color: rgba(0, 0, 0, 0); - padding: 10px; - outline: none; - resize: none; //右下角的拖曳方塊 + height: 100%; + width: 100%; + border: none; + color: var(--color-white); + background-color: rgba(0, 0, 0, 0); + padding: 10px; + outline: none; + resize: none; //右下角的拖曳方塊 } //------------------------------- //歡迎畫面 .mView-welcome { - height: 100%; - width: 100%; - display: flex; - justify-content: center; - align-items: center; - color: var(--color-white); - user-select: none; - /* pointer-events: none; */ - - .mView-welcome-logo { - max-width: 150px; - margin: auto; - margin-bottom: 30px; - display: block; - pointer-events: none; - } - .mView-welcome-text { - text-align: center; - font-size: 20px; - pointer-events: none; - } + height: 100%; + width: 100%; + display: flex; + justify-content: center; + align-items: center; + color: var(--color-white); + user-select: none; + /* pointer-events: none; */ + + .mView-welcome-logo { + max-width: 150px; + margin: auto; + margin-bottom: 30px; + display: block; + pointer-events: none; + } + .mView-welcome-text { + text-align: center; + font-size: 20px; + pointer-events: none; + } } //------------------------------- #loadingWindow { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - //display: flex; - display: none; - align-items: center; - justify-content: center; - z-index: 1000; - - img { - max-width: 300px; - width: 100%; - pointer-events: none; - user-select: none; - } + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + //display: flex; + display: none; + align-items: center; + justify-content: center; + z-index: 1000; + + img { + max-width: 300px; + width: 100%; + pointer-events: none; + user-select: none; + } } //------------------------------- //搭配 js函數「updateDomVisibility()」,用於隱藏元素 .js-showType-none { - display: none !important; + display: none !important; } //------------------------------- //全螢幕 body[fullScreen="true"] { - .window-titlebar { - position: fixed; - top: -70px; - left: 0; - right: 0; - transition: top 0.3s; - z-index: 100; - background-color: var(--color-black80); - //backdrop-filter: saturate(180%) blur(20px); - } - .main-T { - position: fixed; - top: -40px; - left: 0; - right: 0; - transition: top 0.3s; - z-index: 100; - background-color: var(--color-black80); - //backdrop-filter: saturate(180%) blur(20px); - } - .titlebar-text { - app-region: no-drag; //讓視窗不允許拖曳 - } - - //顯示「結束全螢幕」的按鈕 - .titlebar-toolbar-exitFullScreen { - display: flex !important; - } - //隱藏「最大化、視窗化、最小化、關閉」 - .titlebar-toolbar-minimized, - .titlebar-toolbar-normal, - .titlebar-toolbar-maximized, - .titlebar-toolbar-close { - display: none !important; - } + .window-titlebar { + position: fixed; + top: -70px; + left: 0; + right: 0; + transition: top 0.3s; + z-index: 100; + background-color: var(--color-black80); + //backdrop-filter: saturate(180%) blur(20px); + } + .main-T { + position: fixed; + top: -40px; + left: 0; + right: 0; + transition: top 0.3s; + z-index: 100; + background-color: var(--color-black80); + //backdrop-filter: saturate(180%) blur(20px); + } + .titlebar-text { + app-region: no-drag; //讓視窗不允許拖曳 + } + + //顯示「結束全螢幕」的按鈕 + .titlebar-toolbar-exitFullScreen { + display: flex !important; + } + //隱藏「最大化、視窗化、最小化、關閉」 + .titlebar-toolbar-minimized, + .titlebar-toolbar-normal, + .titlebar-toolbar-maximized, + .titlebar-toolbar-close { + display: none !important; + } } //滑鼠移動到最上面時,顯示標題列與工具列 body[fullScreen="true"][showTitlebar="true"] { - .window-titlebar { - top: 0px; - } - .main-T { - top: 30px; - } + .window-titlebar { + top: 0px; + } + .main-T { + top: 30px; + } } diff --git a/Www/scss/MainWindow/_BulkView.scss b/Www/scss/MainWindow/_BulkView.scss index d4529bcc..e0e9930a 100644 --- a/Www/scss/MainWindow/_BulkView.scss +++ b/Www/scss/MainWindow/_BulkView.scss @@ -1,370 +1,354 @@ .bulkView { - display: flex; - flex-direction: column; - overflow-y: scroll; - overflow-x: hidden; - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; + display: flex; + flex-direction: column; + overflow-y: scroll; + overflow-x: hidden; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; } //滾動條的容器 .bulkView-scroll-content { - margin-right: 10px; + margin-right: 10px; } //滾動條樣式 .bulkView { - //position: relative; - - &::-webkit-scrollbar { - display: none; - } - - /*垂直滾動條*/ - .scroll-y { - width: 20px; - position: absolute; - right: 0px; - z-index: 1; - } - - /*背景*/ - .scroll-y .scroll-bg { - height: 100%; - width: 10px; - background-color: var(--color-black60); - position: absolute; - right: 0; - top: 0; - bottom: 0; - opacity: 0; - } - - /*拖曳區域*/ - .scroll-y .scroll-box { - width: 10px; - background-color: var(--color-white40); - position: absolute; - right: 0; - border: 3px solid rgba(0, 0, 0, 0); - background-clip: content-box; - } - - .scroll-y:hover { - cursor: pointer; - } - - /*移入與拖曳時-背景*/ - .scroll-y:hover .scroll-bg, - .scroll-y[action="true"] .scroll-bg { - opacity: 1; - } - - /*移入與拖曳時-拖曳區域*/ - .scroll-y:hover .scroll-box, - .scroll-y[action="true"] .scroll-box { - } + //position: relative; + + &::-webkit-scrollbar { + display: none; + } + + /*垂直滾動條*/ + .scroll-y { + width: 20px; + position: absolute; + right: 0px; + z-index: 1; + } + + /*背景*/ + .scroll-y .scroll-bg { + height: 100%; + width: 10px; + background-color: var(--color-black60); + position: absolute; + right: 0; + top: 0; + bottom: 0; + opacity: 0; + } + + /*拖曳區域*/ + .scroll-y .scroll-box { + width: 10px; + background-color: var(--color-white40); + position: absolute; + right: 0; + border: 3px solid rgba(0, 0, 0, 0); + background-clip: content-box; + } + + .scroll-y:hover { + cursor: pointer; + } + + /*移入與拖曳時-背景*/ + .scroll-y:hover .scroll-bg, + .scroll-y[action="true"] .scroll-bg { + opacity: 1; + } + + /*移入與拖曳時-拖曳區域*/ + .scroll-y:hover .scroll-box, + .scroll-y[action="true"] .scroll-box { + } } .bulkView-content { - display: flex; - flex-wrap: wrap; - margin-bottom: 10px; - margin-left: 5px; - outline: none; - /* padding: 10px; */ - /* padding-top:10px; */ - /* padding-left:10px; */ - position: relative; - flex-shrink: 0; + display: flex; + flex-wrap: wrap; + margin-bottom: 10px; + margin-left: 5px; + outline: none; + /* padding: 10px; */ + /* padding-top:10px; */ + /* padding-left:10px; */ + position: relative; + flex-shrink: 0; } /* #region 附加選項 */ .bulkView-content[show*="fileName"] .bulkView-fileName { - display: block; + display: block; } .bulkView-content[show*="number"] .bulkView-number { - display: block; + display: block; } .bulkView-content[show*="imageSize"] .bulkView-imageSize { - display: block; + display: block; } .bulkView-content[show*="fileSize"] .bulkView-fileSize { - display: block; + display: block; } .bulkView-content[show*="lastWriteDate"] .bulkView-lastWriteDate { - display: block; + display: block; } .bulkView-content[show*="lastWriteTime"] .bulkView-lastWriteTime { - display: block; + display: block; } //排列方向 .bulkView-content[columns="2"][align="right"] { - flex-direction: row-reverse; + flex-direction: row-reverse; } //瀑布流-垂直 -.bulkView-content[waterfall="vertical"]:not([columns="1"], [columns="2"]) - .bulkView-item { - position: absolute; - left: -9999px; +.bulkView-content[waterfall="vertical"]:not([columns="1"], [columns="2"]) .bulkView-item { + position: absolute; + left: -9999px; } // 瀑布流-水平,tag不允許換行 .bulkView-content[waterfall="horizontal"] .bulkView-header2 { - flex-wrap: nowrap; + flex-wrap: nowrap; } //鎖定寬度 @for $i from 1 through 10 { - .bulkView-content[fixedWidth="#{$i*10}"] .bulkView-img { - width: $i * 10%; - } + .bulkView-content[fixedWidth="#{$i*10}"] .bulkView-img { + width: $i * 10%; + } } //無間距模式 -.bulkView-content:not([gaplessMode="off"]):is([columns="1"], [columns="2"]) - .bulkView-item - .bulkView-header, -.bulkView-content:not([gaplessMode="off"]):is([columns="1"], [columns="2"]) - .bulkView-item - .bulkView-header2 { - display: none; -} -.bulkView-content:not([gaplessMode="off"]):is([columns="1"], [columns="2"]) - .bulkView-item { - padding-top: 0px; - padding-bottom: 0px; - border: none !important; - border-radius: 0; +.bulkView-content:not([gaplessMode="off"]):is([columns="1"], [columns="2"]) .bulkView-item .bulkView-header, +.bulkView-content:not([gaplessMode="off"]):is([columns="1"], [columns="2"]) .bulkView-item .bulkView-header2 { + display: none; +} +.bulkView-content:not([gaplessMode="off"]):is([columns="1"], [columns="2"]) .bulkView-item { + padding-top: 0px; + padding-bottom: 0px; + border: none !important; + border-radius: 0; } //下面的距離 -.bulkView-content[gaplessMode="0"]:is([columns="1"], [columns="2"]) - .bulkView-item { - margin-bottom: -1px !important; +.bulkView-content[gaplessMode="0"]:is([columns="1"], [columns="2"]) .bulkView-item { + margin-bottom: -1px !important; } @for $i from 1 through 10 { - .bulkView-content[gaplessMode="#{$i*10}"]:is([columns="1"], [columns="2"]) - .bulkView-item { - margin-bottom: $i * 10px !important; - } + .bulkView-content[gaplessMode="#{$i*10}"]:is([columns="1"], [columns="2"]) .bulkView-item { + margin-bottom: $i * 10px !important; + } } //雙欄時,讓左右的圖片合併 -.bulkView-content[columns="2"][align="left"]:not([gaplessMode="off"]) - .bulkView-item:nth-child(odd) - .bulkView-center { - justify-content: end; -} -.bulkView-content[columns="2"][align="left"]:not([gaplessMode="off"]) - .bulkView-item:nth-child(even) - .bulkView-center { - justify-content: start; -} -.bulkView-content[columns="2"][align="right"]:not([gaplessMode="off"]) - .bulkView-item:nth-child(odd) - .bulkView-center { - justify-content: start; -} -.bulkView-content[columns="2"][align="right"]:not([gaplessMode="off"]) - .bulkView-item:nth-child(even) - .bulkView-center { - justify-content: end; +.bulkView-content[columns="2"][align="left"]:not([gaplessMode="off"]) .bulkView-item:nth-child(odd) .bulkView-center { + justify-content: end; +} +.bulkView-content[columns="2"][align="left"]:not([gaplessMode="off"]) .bulkView-item:nth-child(even) .bulkView-center { + justify-content: start; +} +.bulkView-content[columns="2"][align="right"]:not([gaplessMode="off"]) .bulkView-item:nth-child(odd) .bulkView-center { + justify-content: start; +} +.bulkView-content[columns="2"][align="right"]:not([gaplessMode="off"]) .bulkView-item:nth-child(even) .bulkView-center { + justify-content: end; } /* #endregion */ .bulkView-item { - border: 1px solid rgba(0, 0, 0, 0); - min-width: 10px; - min-height: 10px; - box-sizing: border-box; - border-radius: 8px; - color: var(--color-white); - padding-top: 5px; - padding-bottom: 5px; - overflow: hidden; - //border: 1px solid var(--color-white40); - user-select: none; + border: 1px solid rgba(0, 0, 0, 0); + min-width: 10px; + min-height: 10px; + box-sizing: border-box; + border-radius: 8px; + color: var(--color-white); + padding-top: 5px; + padding-bottom: 5px; + overflow: hidden; + //border: 1px solid var(--color-white40); + user-select: none; } .bulkView-item:hover { - border: 1px solid var(--color-white10); + border: 1px solid var(--color-white10); } .bulkView-header { - display: flex; - margin-left: 5px; - margin-right: 5px; + display: flex; + margin-left: 5px; + margin-right: 5px; } .bulkView-number { - margin-right: 5px; - margin-bottom: 5px; - color: var(--color-blue); - font-weight: var(--fontWeightBold); - display: none; + margin-right: 5px; + margin-bottom: 5px; + color: var(--color-blue); + font-weight: var(--fontWeightBold); + display: none; } .bulkView-fileName { - display: none; - flex: 1; - margin-bottom: 5px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - text-align: left; + display: none; + flex: 1; + margin-bottom: 5px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + text-align: left; } .bulkView-header2 { - margin: 0 5px; - margin-top: 0px; - display: flex; - flex-wrap: wrap; + margin: 0 5px; + margin-top: 0px; + display: flex; + flex-wrap: wrap; } .bulkView-tag { - display: none; - margin-right: 5px; - border: 1px solid var(--color-white20); - padding: 3px 5px; - border-radius: 5px; - margin-bottom: 5px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + display: none; + margin-right: 5px; + border: 1px solid var(--color-white20); + padding: 3px 5px; + border-radius: 5px; + margin-bottom: 5px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .bulkView-center { - display: flex; - align-items: flex-start; - justify-content: center; - position: relative; + display: flex; + align-items: flex-start; + justify-content: center; + position: relative; } .bulkView-loading { - background-image: url("./../../img/loading.svg"); - background-position: center; - background-repeat: no-repeat; - background-size: auto 100px; - min-height: 100px; + background-image: url("./../../img/loading.svg"); + background-position: center; + background-repeat: no-repeat; + background-size: auto 100px; + min-height: 100px; } .bulkView-img { - opacity: 0; - pointer-events: none; - max-width: calc(100% - 10px); - // margin-bottom: 5px; - //max-height: calc(100% - 5px); - /* margin-top: 5px; */ + opacity: 0; + pointer-events: none; + max-width: calc(100% - 10px); + // margin-bottom: 5px; + //max-height: calc(100% - 5px); + /* margin-top: 5px; */ } //避免圖片載入前顯示圖片邊框 .bulkView-img[src] { - opacity: 1; + opacity: 1; } //按鈕 - 重新載入 .bulkView-reload { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - margin: auto; - width: 60px; - height: 60px; - border-radius: 10px; - background-color: var(--color-black40); - box-shadow: 0px 0px 5px var(--color-blue40); - backdrop-filter: saturate(180%) blur(20px); -} -.bulkView-reload svg { - width: 30px; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - margin: auto; -} -.bulkView-center:hover .bulkView-reload{ - border: 1px solid var(--color-blue); + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + margin: auto; + width: 60px; + height: 60px; + border-radius: 10px; + background-color: var(--color-black40); + box-shadow: 0px 0px 5px var(--color-blue40); + backdrop-filter: saturate(180%) blur(20px); +} +.bulkView-reload svg { + width: 30px; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + margin: auto; +} +.bulkView-center:hover .bulkView-reload { + border: 1px solid var(--color-blue); } //分頁器 .bulkView-pagination { - display: none; - flex-direction: column; - text-align: center; - margin-bottom: 10px; - - .bulkView-pagination-box { - height: 60px; - // border: 1px solid var(--color-white40); - - display: inline-flex; - align-items: center; - overflow: hidden; - user-select: none; - } - - //上下一頁按鈕 - .bulkView-pagination-prev, - .bulkView-pagination-next { - height: 100%; - width: 50px; - border-radius: 5px; - display: flex; - align-items: center; - - color: var(--color-white); - - flex: 1; - //opacity: 0; - } - .bulkView-pagination-prev { - justify-content: flex-end; - } - .bulkView-pagination-next { - justify-content: flex-start; - } - .bulkView-pagination-prev svg, - .bulkView-pagination-next svg { - width: 25px; - margin: 8px; - } - - .bulkView-pagination-prev:hover, - .bulkView-pagination-next:hover, - .bulkView-pagination-select:hover { - //justify-content: center; - cursor: pointer; - opacity: 1; - background-color: var(--color-white10); - // border: 1px solid var(--color-white10); - } - - //無法點擊的狀態 - .bulkView-pagination-prev[freeze="true"], - .bulkView-pagination-next[freeze="true"] { - pointer-events: none; - opacity: 0.4; - } - - //下拉選單 - .bulkView-pagination-select { - color: var(--color-white); - height: 35px; - border-radius: 5px; - background-color: rgba(0, 0, 0, 0); - border: none; - padding-left: 10px; - outline: none; - border-left: 1px solid var(--color-white40); - border: 1px solid var(--color-white40); - padding: 0 5px; + display: none; + flex-direction: column; text-align: center; - } + margin-bottom: 10px; + + .bulkView-pagination-box { + height: 60px; + // border: 1px solid var(--color-white40); + + display: inline-flex; + align-items: center; + overflow: hidden; + user-select: none; + } + + //上下一頁按鈕 + .bulkView-pagination-prev, + .bulkView-pagination-next { + height: 100%; + width: 50px; + border-radius: 5px; + display: flex; + align-items: center; + + color: var(--color-white); + + flex: 1; + //opacity: 0; + } + .bulkView-pagination-prev { + justify-content: flex-end; + } + .bulkView-pagination-next { + justify-content: flex-start; + } + .bulkView-pagination-prev svg, + .bulkView-pagination-next svg { + width: 25px; + margin: 8px; + } + + .bulkView-pagination-prev:hover, + .bulkView-pagination-next:hover, + .bulkView-pagination-select:hover { + //justify-content: center; + cursor: pointer; + opacity: 1; + background-color: var(--color-white10); + // border: 1px solid var(--color-white10); + } + + //無法點擊的狀態 + .bulkView-pagination-prev[freeze="true"], + .bulkView-pagination-next[freeze="true"] { + pointer-events: none; + opacity: 0.4; + } + + //下拉選單 + .bulkView-pagination-select { + color: var(--color-white); + height: 35px; + border-radius: 5px; + background-color: rgba(0, 0, 0, 0); + border: none; + padding-left: 10px; + outline: none; + border-left: 1px solid var(--color-white40); + border: 1px solid var(--color-white40); + padding: 0 5px; + text-align: center; + } } .bulkView-pagination[active="true"] { - display: flex; + display: flex; } diff --git a/Www/scss/MainWindow/_Dragbar.scss b/Www/scss/MainWindow/_Dragbar.scss index 99436863..3bed7085 100644 --- a/Www/scss/MainWindow/_Dragbar.scss +++ b/Www/scss/MainWindow/_Dragbar.scss @@ -1,25 +1,25 @@ /* #region 拖曳條 */ .dragbar-v { - width: 4px; - height: 600px; - background-color: rgba(0, 0, 0, 0); - top: 40px; - left: 60px; - position: absolute; - z-index: 10; - transform: translate(-2px, -1px); //讓拖曳條在中間 - transition: background-color 0.2s; + width: 4px; + height: 600px; + background-color: rgba(0, 0, 0, 0); + top: 40px; + left: 60px; + position: absolute; + z-index: 10; + transform: translate(-2px, -1px); //讓拖曳條在中間 + transition: background-color 0.2s; } //滑鼠移入時 .dragbar-v:hover { - background-color: var(--color-blue); - transition-delay: 0.2s; //滑鼠停留一段時間才顯示 - cursor: e-resize; + background-color: var(--color-blue); + transition-delay: 0.2s; //滑鼠停留一段時間才顯示 + cursor: e-resize; } //拖曳時 .dragbar-v[active="true"] { - background-color: var(--color-blue); + background-color: var(--color-blue); } /* #endregion */ diff --git a/Www/scss/MainWindow/_LargeBtn.scss b/Www/scss/MainWindow/_LargeBtn.scss index 8363b5d1..ecdbb29d 100644 --- a/Www/scss/MainWindow/_LargeBtn.scss +++ b/Www/scss/MainWindow/_LargeBtn.scss @@ -1,107 +1,104 @@ /* #region 在下面或兩側的 大型切換按鈕 */ .largeBtn { - - position: absolute; - display: flex; - - opacity: 0; - z-index: 5; - user-select: none; - - .box { - /* backdrop-filter: saturate(180%) blur(20px); */ position: absolute; - border-radius: 5px; - background-color: var(--color-black40); - border: 1px solid var(--color-white10); - - width: 41px; - height: 41px; display: flex; - align-items: center; - justify-content: center; - } - + opacity: 0; + z-index: 5; + user-select: none; + + .box { + /* backdrop-filter: saturate(180%) blur(20px); */ + position: absolute; + border-radius: 5px; + background-color: var(--color-black40); + border: 1px solid var(--color-white10); + + width: 41px; + height: 41px; + display: flex; + align-items: center; + justify-content: center; + } } .largeBtn:hover { - cursor: pointer; - opacity: 1; + cursor: pointer; + opacity: 1; } .largeBtn:active { } .largeBtn:active svg { - transform: scaleX(0.85); - transition:transform 0.1s !important; + transform: scaleX(0.85); + transition: transform 0.1s !important; } .largeBtn svg { - height: 25px; - transition:transform 0.5s ; + height: 25px; + transition: transform 0.5s; } //暫時隱藏 .largeBtn[hide="true"] { - display: none !important; + display: none !important; } //左右兩側 .largeBtn[data-style="leftRight-L"] { - top: 0px; - bottom: 0px; - left: 0px; - width: 60px; - justify-content: start; - align-items: center; + top: 0px; + bottom: 0px; + left: 0px; + width: 60px; + justify-content: start; + align-items: center; } .largeBtn[data-style="leftRight-R"] { - top: 0px; - bottom: 0px; - right: 0px; - width: 60px; - justify-content: end; - align-items: center; + top: 0px; + bottom: 0px; + right: 0px; + width: 60px; + justify-content: end; + align-items: center; } //左右兩側2(內縮) .largeBtn[data-style="leftRight2-L"] { - top: 20px; - bottom: 20px; - left: 20px; - width: 60px; - justify-content: start; - align-items: center; + top: 20px; + bottom: 20px; + left: 20px; + width: 60px; + justify-content: start; + align-items: center; } .largeBtn[data-style="leftRight2-R"] { - top: 20px; - bottom: 20px; - right: 20px; - width: 60px; - justify-content: end; - align-items: center; + top: 20px; + bottom: 20px; + right: 20px; + width: 60px; + justify-content: end; + align-items: center; } //下面 .largeBtn[data-style="bottom-L"] { - bottom: 20px; - left: 20px; - right: 50%; - height: 60px; - justify-content: start; - align-items: end; + bottom: 20px; + left: 20px; + right: 50%; + height: 60px; + justify-content: start; + align-items: end; } .largeBtn[data-style="bottom-R"] { - bottom: 20px; - left: 50%; - right: 20px; - height: 60px; - justify-content: end; - align-items: end; + bottom: 20px; + left: 50%; + right: 20px; + height: 60px; + justify-content: end; + align-items: end; } //不顯示 .largeBtn[data-style="none-L"] { - display: none; + display: none; } .largeBtn[data-style="none-R"] { - display: none; + display: none; } /* #endregion */ diff --git a/Www/scss/MainWindow/_LoadingSetting.scss b/Www/scss/MainWindow/_LoadingSetting.scss index 08147eeb..74bb08c3 100644 --- a/Www/scss/MainWindow/_LoadingSetting.scss +++ b/Www/scss/MainWindow/_LoadingSetting.scss @@ -1,62 +1,61 @@ // 開啟setting視窗前的loading畫面 #loadingSetting[active="true"] { - display: block; + display: block; } #loadingSetting { - display: none; - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - - .loadingSetting-box { - width: 90px; - height: 90px; - border-radius: 10px; - backdrop-filter: saturate(180%) blur(20px); - position: absolute; + display: none; + position: fixed; top: 0; left: 0; right: 0; bottom: 0; - margin: auto; - background-color: var(--color-black80); - display: flex; - align-items: center; - justify-content: center; - } - .loadingSetting-box svg { - width: 50px; - height: 50px; - position: relative; - // background: #FFF; - border-radius: 50%; - transform: rotate(45deg); - animation: loadingSetting-rotate 2s linear infinite; - } - - //旋轉動畫 - @keyframes loadingSetting-rotate { - 0% { - transform: rotate(45deg); - } - 30%, - 50%, - 70% { - transform: rotate(230deg); - } - 40%, - 60%, - 80% { - transform: rotate(240deg); + .loadingSetting-box { + width: 90px; + height: 90px; + border-radius: 10px; + backdrop-filter: saturate(180%) blur(20px); + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + margin: auto; + background-color: var(--color-black80); + display: flex; + align-items: center; + justify-content: center; } - 100% { - transform: rotate(245deg); + + .loadingSetting-box svg { + width: 50px; + height: 50px; + position: relative; + // background: #FFF; + border-radius: 50%; + transform: rotate(45deg); + animation: loadingSetting-rotate 2s linear infinite; } - } + //旋轉動畫 + @keyframes loadingSetting-rotate { + 0% { + transform: rotate(45deg); + } + 30%, + 50%, + 70% { + transform: rotate(230deg); + } + 40%, + 60%, + 80% { + transform: rotate(240deg); + } + 100% { + transform: rotate(245deg); + } + } } diff --git a/Www/scss/MainWindow/_MainDirList.scss b/Www/scss/MainWindow/_MainDirList.scss index ab2c4c97..12f22c33 100644 --- a/Www/scss/MainWindow/_MainDirList.scss +++ b/Www/scss/MainWindow/_MainDirList.scss @@ -1,146 +1,146 @@ /* #region 資料夾預覽視窗 */ :root { - --dirList-width: 200px; + --dirList-width: 200px; } .main-dirList { - display: none; - - overflow-x: hidden; - height: 100%; - width: var(--dirList-width); - - .main-dirListBody { - overflow: hidden; - padding-top: 3px; - } - - .dirList-item { - padding-left: 6px; - margin-right: 6px; - user-select: none; - margin-bottom: 6px; - white-space: nowrap; - position: relative; - cursor: pointer; - } - - .dirList-item:hover::before { - //outline: 2px solid var(--color-white40); - //outline-offset: 2px; - position: absolute; - top: -3px; - left: 3px; - right: -3px; - bottom: -3px; - border: 2px solid var(--color-white40); - pointer-events: none; - z-index: 1; - content: ""; - border-radius: 7px; - } - - //選中 - .dirList-item[active="true"]::before { - //outline: 2px solid var(--color-blue); - //outline-offset: 2px; - position: absolute; - top: -3px; - left: 3px; - right: -3px; - bottom: -3px; - border: 2px solid var(--color-blue); - pointer-events: none; - z-index: 1; - content: ""; - border-radius: 7px; - } - - // - .dirList-title { - display: flex; - flex-direction: row; - font-size: 14px; - } - - //編號 - .dirList-no { - margin-bottom: 2px; - line-height: 14px; - height: 14px; - - overflow: hidden; - font-weight: var(--fontWeightBold); - color: var(--color-blue); - margin-right: 3px; - } - - //檔名 - .dirList-name { - margin-bottom: 2px; - line-height: 14px; - height: 14px; - - overflow: hidden; - text-align: center; - flex: 1; - white-space: nowrap; - color: var(--color-white); - } - - .dirList-imgbox { - display: flex; - flex-direction: row; - } - - //圖片 - .dirList-img { - margin-right: 3px; - background-size: cover; - background-repeat: no-repeat; - background-position: center center; - border-radius: 4px; - img { - width: 100%; - height: 100%; - object-fit: cover; - pointer-events: none; - user-select: none; + display: none; + + overflow-x: hidden; + height: 100%; + width: var(--dirList-width); + + .main-dirListBody { + overflow: hidden; + padding-top: 3px; + } + + .dirList-item { + padding-left: 6px; + margin-right: 6px; + user-select: none; + margin-bottom: 6px; + white-space: nowrap; + position: relative; + cursor: pointer; + } + + .dirList-item:hover::before { + //outline: 2px solid var(--color-white40); + //outline-offset: 2px; + position: absolute; + top: -3px; + left: 3px; + right: -3px; + bottom: -3px; + border: 2px solid var(--color-white40); + pointer-events: none; + z-index: 1; + content: ""; + border-radius: 7px; + } + + //選中 + .dirList-item[active="true"]::before { + //outline: 2px solid var(--color-blue); + //outline-offset: 2px; + position: absolute; + top: -3px; + left: 3px; + right: -3px; + bottom: -3px; + border: 2px solid var(--color-blue); + pointer-events: none; + z-index: 1; + content: ""; + border-radius: 7px; + } + + // + .dirList-title { + display: flex; + flex-direction: row; + font-size: 14px; + } + + //編號 + .dirList-no { + margin-bottom: 2px; + line-height: 14px; + height: 14px; + + overflow: hidden; + font-weight: var(--fontWeightBold); + color: var(--color-blue); + margin-right: 3px; + } + + //檔名 + .dirList-name { + margin-bottom: 2px; + line-height: 14px; + height: 14px; + + overflow: hidden; + text-align: center; + flex: 1; + white-space: nowrap; + color: var(--color-white); + } + + .dirList-imgbox { + display: flex; + flex-direction: row; + } + + //圖片 + .dirList-img { + margin-right: 3px; + background-size: cover; + background-repeat: no-repeat; + background-position: center center; + border-radius: 4px; + img { + width: 100%; + height: 100%; + object-fit: cover; + pointer-events: none; + user-select: none; + } + } + .dirList-img__1 { + width: calc((var(--dirList-width) - 1 * 3px) / 1); + height: calc((var(--dirList-width) - 1 * 3px) / 1); + } + .dirList-img__2 { + width: calc((var(--dirList-width) - 2 * 3px) / 2); + height: calc((var(--dirList-width) - 2 * 3px) / 2); + } + .dirList-img__3 { + width: calc((var(--dirList-width) - 3 * 3px) / 3); + height: calc((var(--dirList-width) - 3 * 3px) / 3); + } + .dirList-img__4 { + width: calc((var(--dirList-width) - 4 * 3px) / 4); + height: calc((var(--dirList-width) - 4 * 3px) / 4); + } + .dirList-img__5 { + width: calc((var(--dirList-width) - 5 * 3px) / 5); + height: calc((var(--dirList-width) - 5 * 3px) / 5); + } + + .dirList-img:last-child { + margin-right: 0px; } - } - .dirList-img__1 { - width: calc((var(--dirList-width) - 1 * 3px) / 1); - height: calc((var(--dirList-width) - 1 * 3px) / 1); - } - .dirList-img__2 { - width: calc((var(--dirList-width) - 2 * 3px) / 2); - height: calc((var(--dirList-width) - 2 * 3px) / 2); - } - .dirList-img__3 { - width: calc((var(--dirList-width) - 3 * 3px) / 3); - height: calc((var(--dirList-width) - 3 * 3px) / 3); - } - .dirList-img__4 { - width: calc((var(--dirList-width) - 4 * 3px) / 4); - height: calc((var(--dirList-width) - 4 * 3px) / 4); - } - .dirList-img__5 { - width: calc((var(--dirList-width) - 5 * 3px) / 5); - height: calc((var(--dirList-width) - 5 * 3px) / 5); - } - - .dirList-img:last-child { - margin-right: 0px; - } } //啟用 .main-dirList[active="true"] { - display: block; + display: block; } //暫時隱藏 .main-dirList[hide="true"] { - display: none !important; + display: none !important; } /* #endregion */ diff --git a/Www/scss/MainWindow/_MainExif.scss b/Www/scss/MainWindow/_MainExif.scss index cd449bd7..9fef3eb3 100644 --- a/Www/scss/MainWindow/_MainExif.scss +++ b/Www/scss/MainWindow/_MainExif.scss @@ -1,87 +1,87 @@ /* #region exif 視窗 */ :root { - --mainExif-width: 240px; - --mainExifMaxLine: 2; //顯示的最大行數 + --mainExif-width: 240px; + --mainExifMaxLine: 2; //顯示的最大行數 } .mainExif { - display: none; - //display: flex; - width: var(--mainExif-width); - height: 100%; - flex-direction: column; - - .mainExifTop { - width: 100%; - display: flex; - align-items: center; - - // 上面的頁籤按鈕 - .mainExifTabs { - flex: 1; - width: 100%; - height: 38px; - margin-bottom: -3px; - justify-content: center; - overflow-x: visible; - overflow-y: hidden; - position: relative; - display: none; - - // 頁籤按鈕下面的水平線 - &::before { - content: ""; - position: absolute; - bottom: 3px; - left: 0; - right: 0; - height: 1px; - background-color: var(--color-blue20); - } - - &[active="true"] { - display: flex; - } + display: none; + //display: flex; + width: var(--mainExif-width); + height: 100%; + flex-direction: column; - .mainExifTabsContent { - display: flex; - flex-direction: row; - } - position: relative; - - .mainExifTabsItem { - flex-shrink: 1; - //flex: 1; - padding: 0 10px; - white-space: nowrap; + .mainExifTop { + width: 100%; display: flex; align-items: center; - justify-content: center; - height: 35px; - border-radius: 5px; - position: relative; - color: var(--color-white); - user-select: none; - - &[active="true"] { - //border: 1px solid var(--color-blue20); - //background-color: var(--color-white10); color: var(--color-blue); - //border-bottom: 3px solid var(--color-blue); - color: var(--color-blue); - svg * { - stroke: var(--color-blue) !important; - } - } - &[active="true"]::after { - position: absolute; - content: ""; - width: 100%; - height: 3px; - bottom: 0px; - background-color: var(--color-blue); - } - /*&[mark="true"] { + // 上面的頁籤按鈕 + .mainExifTabs { + flex: 1; + width: 100%; + height: 38px; + margin-bottom: -3px; + justify-content: center; + overflow-x: visible; + overflow-y: hidden; + position: relative; + display: none; + + // 頁籤按鈕下面的水平線 + &::before { + content: ""; + position: absolute; + bottom: 3px; + left: 0; + right: 0; + height: 1px; + background-color: var(--color-blue20); + } + + &[active="true"] { + display: flex; + } + + .mainExifTabsContent { + display: flex; + flex-direction: row; + } + position: relative; + + .mainExifTabsItem { + flex-shrink: 1; + //flex: 1; + padding: 0 10px; + white-space: nowrap; + display: flex; + align-items: center; + justify-content: center; + height: 35px; + border-radius: 5px; + position: relative; + color: var(--color-white); + user-select: none; + + &[active="true"] { + //border: 1px solid var(--color-blue20); + //background-color: var(--color-white10); color: var(--color-blue); + //border-bottom: 3px solid var(--color-blue); + color: var(--color-blue); + svg * { + stroke: var(--color-blue) !important; + } + } + &[active="true"]::after { + position: absolute; + content: ""; + width: 100%; + height: 3px; + bottom: 0px; + + background-color: var(--color-blue); + } + /*&[mark="true"] { color: var(--color-white); } &[mark="true"]::before { @@ -94,143 +94,269 @@ border-radius: 50%; //background-color: var(--color-blue); }*/ - &:last-child { - border-right: none; + &:last-child { + border-right: none; + } + &:hover { + cursor: pointer; + background-color: var(--color-white10); + } + } + } + } + + // 相關檔案 + .mainExifRelated { + padding: 0 5px; + margin-top: 5px; + padding-bottom: 20px; + overflow-y: auto; + overflow-x: hidden; + flex: 1; + + // 用於 contenteditable 的調整 + outline: none; + caret-color: transparent; + img::selection { + background: transparent; + } + } + + /* #region 拖曳條 */ + + // 標題 + .mainExifRelatedTitle { + color: var(--color-blue); + + //height: 35px; + border: 1px solid var(--color-blue40); + border-radius: 8px; + padding: 5px; + + margin-top: 5px; + margin-bottom: 5px; + + display: flex; + align-items: center; + justify-content: end; + font-weight: var(--fontWeightBold); + cursor: pointer; + position: relative; + user-select: none; + + word-wrap: break-word; + word-break: break-all; + + span { + //position: absolute; + margin-left: 25px; + pointer-events: none; + flex: 1; } + } + // 標題右邊的按鈕 + .mainExifRelatedTitleBtnList { + position: absolute; + top: 3px; + right: 3px; + bottom: 0; + display: flex; + } + .mainExifRelatedTitleBtn { + width: 24px; + height: 24px; + background-color: var(--color-black80); + border: 1px solid var(--color-blue40); + border-radius: 4px; + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + transition: 0s opacity; + z-index: 1; + + // 移入按鈕時,顯示按鈕 &:hover { - cursor: pointer; - background-color: var(--color-white10); + cursor: pointer; + transition: 0s opacity !important; + opacity: 1 !important; + } + & svg { + width: 18px; + height: 18px; + pointer-events: none; + user-select: none; } - } } - } - - // 相關檔案 - .mainExifRelated { - padding: 0 5px; - margin-top: 5px; - padding-bottom: 20px; - overflow-y: auto; - overflow-x: hidden; - flex: 1; - - // 用於 contenteditable 的調整 - outline: none; - caret-color: transparent; - img::selection { - background: transparent; + // 移入整個項目時,顯示半透明的按鈕 + .mainExifRelatedBox:hover .mainExifRelatedTitleBtn { + opacity: 0.3; + transition: 0.3s opacity; + } + + .mainExifRelatedBox .mainExifRelatedTitle::after { + content: ""; + position: absolute; + width: 8px; + height: 8px; + border-right: 1px solid var(--color-blue); + border-bottom: 1px solid var(--color-blue); + pointer-events: none; + transition: all 0.1s; + } + // 標題左邊的箭頭 + .mainExifRelatedBox[open="false"] .mainExifRelatedTitle::after { + left: 11px; + top: 8px; + transform: rotate(45deg); + } + .mainExifRelatedBox[open="true"] .mainExifRelatedTitle::after { + left: 11px; + top: 14px; + transform: rotate(225deg); } - } - /* #region 拖曳條 */ + // 折疊內容 + .mainExifRelatedContent { + transition: all 0.1s; + overflow: hidden; + + .mainExifRelatedText { + padding-bottom: 20px; + span { + color: var(--color-white); + margin: 0 5px; - // 標題 - .mainExifRelatedTitle { - color: var(--color-blue); + word-wrap: break-word; + word-break: break-all; - //height: 35px; - border: 1px solid var(--color-blue40); - border-radius: 8px; - padding: 5px; + // 行數太多時結尾以...呈現 + overflow: hidden; + -webkit-line-clamp: var(--mainExifMaxLine); + -webkit-box-orient: vertical; + display: -webkit-box; - margin-top: 5px; - margin-bottom: 5px; + // 允許顯示空白跟換行 + white-space: pre-wrap; + } + } - display: flex; - align-items: center; - justify-content: end; - font-weight: var(--fontWeightBold); - cursor: pointer; - position: relative; - user-select: none; - - word-wrap: break-word; - word-break: break-all; - - span { - //position: absolute; - margin-left: 25px; - pointer-events: none; - flex: 1; + .mainExifRelatedImg { + padding-bottom: 20px; + text-align: center; + margin: 0 5px; + user-select: none; + img { + max-width: 100%; + max-height: 400px; + margin: auto; + pointer-events: none; + } + } } - } - // 標題右邊的按鈕 - .mainExifRelatedTitleBtnList { - position: absolute; - top: 3px; - right: 3px; - bottom: 0; - display: flex; - } - .mainExifRelatedTitleBtn { - width: 24px; - height: 24px; - background-color: var(--color-black80); - border: 1px solid var(--color-blue40); - border-radius: 4px; - display: flex; - align-items: center; - justify-content: center; - opacity: 0; - transition: 0s opacity; - z-index: 1; - - // 移入按鈕時,顯示按鈕 - &:hover { - cursor: pointer; - transition: 0s opacity !important; - opacity: 1 !important; + + //按鈕 - 新增 + .mainExifRelatedBtnAdd { + height: 35px; + border-radius: 5px; + margin: auto; + color: var(--color-blue); + border: 1px solid var(--color-blue40); + display: flex; + align-items: center; + justify-content: center; + max-width: 100px; + margin-top: 5px; + user-select: none; + cursor: pointer; } - & svg { - width: 18px; - height: 18px; - pointer-events: none; - user-select: none; + /* #endregion */ + + //資訊 + .mainExifList { + padding-left: 5px; + padding-bottom: 20px; + overflow-y: auto; + overflow-x: hidden; + flex: 1; + + // 用於 contenteditable 的調整 + outline: none; + caret-color: transparent; + img::selection { + background: transparent; + } } - } - // 移入整個項目時,顯示半透明的按鈕 - .mainExifRelatedBox:hover .mainExifRelatedTitleBtn { - opacity: 0.3; - transition: 0.3s opacity; - } - - .mainExifRelatedBox .mainExifRelatedTitle::after { - content: ""; - position: absolute; - width: 8px; - height: 8px; - border-right: 1px solid var(--color-blue); - border-bottom: 1px solid var(--color-blue); - pointer-events: none; - transition: all 0.1s; - } - // 標題左邊的箭頭 - .mainExifRelatedBox[open="false"] .mainExifRelatedTitle::after { - left: 11px; - top: 8px; - transform: rotate(45deg); - } - .mainExifRelatedBox[open="true"] .mainExifRelatedTitle::after { - left: 11px; - top: 14px; - transform: rotate(225deg); - } - - // 折疊內容 - .mainExifRelatedContent { - transition: all 0.1s; - overflow: hidden; - - .mainExifRelatedText { - padding-bottom: 20px; - span { - color: var(--color-white); - margin: 0 5px; + .mainExifItem { + flex-wrap: wrap; + flex-direction: row; + align-items: center; + padding: 3px 0; + + // 水平線 + &::before { + content: ""; + height: 1px; + background-color: var(--color-blue20); + position: absolute; + top: 0; + left: 0; + right: 5px; + } + // 第一個項目不顯示水平線 + &:first-child::before { + display: none; + } word-wrap: break-word; - word-break: break-all; + //word-break: break-all; + font-size: 14px; + position: relative; + } - // 行數太多時結尾以...呈現 + // 匯出 + .btnExport { + width: 25px; + height: 25px; + position: absolute; + top: 0; + bottom: 0; + right: 0px; + margin: auto; + border-radius: 4px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + border: 1px solid var(--color-blue20); + + &:hover { + cursor: pointer; + background-color: var(--color-white10); + } + &:active { + background-color: var(--color-white30); + } + svg { + width: 25px; + height: 25px; + pointer-events: none; + } + } + + .mainExifName { + flex: 1; + min-width: 100px; //寬度不足100時,會自動換行 + color: var(--color-blue); + margin-right: 3px; + font-weight: var(--fontWeightBold); + } + .mainExifValue { + flex: 1; + min-width: 100px; + color: var(--color-white); + + // 限制顯示的最大行數 overflow: hidden; -webkit-line-clamp: var(--mainExifMaxLine); -webkit-box-orient: vertical; @@ -238,370 +364,244 @@ // 允許顯示空白跟換行 white-space: pre-wrap; - } - } - - .mainExifRelatedImg { - padding-bottom: 20px; - text-align: center; - margin: 0 5px; - user-select: none; - img { - max-width: 100%; - max-height: 400px; - margin: auto; - pointer-events: none; - } - } - } - - //按鈕 - 新增 - .mainExifRelatedBtnAdd { - height: 35px; - border-radius: 5px; - margin: auto; - color: var(--color-blue); - border: 1px solid var(--color-blue40); - display: flex; - align-items: center; - justify-content: center; - max-width: 100px; - margin-top: 5px; - user-select: none; - cursor: pointer; - } - /* #endregion */ - - //資訊 - .mainExifList { - padding-left: 5px; - padding-bottom: 20px; - overflow-y: auto; - overflow-x: hidden; - flex: 1; - - // 用於 contenteditable 的調整 - outline: none; - caret-color: transparent; - img::selection { - background: transparent; } - } - .mainExifItem { - flex-wrap: wrap; - flex-direction: row; - align-items: center; - padding: 3px 0; - - // 水平線 - &::before { - content: ""; - height: 1px; - background-color: var(--color-blue20); - position: absolute; - top: 0; - left: 0; - right: 5px; - } - // 第一個項目不顯示水平線 - &:first-child::before { - display: none; + // 不顯示空白跟換行 + .mainExifValue__nowrap { + white-space: normal; } - word-wrap: break-word; - //word-break: break-all; - font-size: 14px; - position: relative; - } - - // 匯出 - .btnExport { - width: 25px; - height: 25px; - position: absolute; - top: 0; - bottom: 0; - right: 0px; - margin: auto; - border-radius: 4px; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - border: 1px solid var(--color-blue20); + // Civitai resources 的圖片 + .mainExifImgList { + display: none; - &:hover { - cursor: pointer; - background-color: var(--color-white10); - } - &:active { - background-color: var(--color-white30); - } - svg { - width: 25px; - height: 25px; - pointer-events: none; - } - } - - .mainExifName { - flex: 1; - min-width: 100px; //寬度不足100時,會自動換行 - color: var(--color-blue); - margin-right: 3px; - font-weight: var(--fontWeightBold); - } - .mainExifValue { - flex: 1; - min-width: 100px; - color: var(--color-white); - - // 限制顯示的最大行數 - overflow: hidden; - -webkit-line-clamp: var(--mainExifMaxLine); - -webkit-box-orient: vertical; - display: -webkit-box; - - // 允許顯示空白跟換行 - white-space: pre-wrap; - } - // 不顯示空白跟換行 - .mainExifValue__nowrap { - white-space: normal; - } - - // Civitai resources 的圖片 - .mainExifImgList { - display: none; + &[active="true"] { + display: flex; + } - &[active="true"] { - display: flex; + .mainExifImgItem { + height: 150px; + max-width: 150px; + width: 100%; + margin-top: 3px; + margin-right: 4px; + border-radius: 6px; + background-color: var(--color-white10); + overflow: hidden; + + img { + width: 100%; + height: 100%; + object-fit: cover; + pointer-events: none; + user-select: none; + } + // 沒有圖片時,隱藏 + img:not([src]) { + opacity: 0; + } + + &:last-child { + margin-right: 0; + } + + &:hover { + cursor: pointer; + outline: 1px solid var(--color-blue); + outline-offset: -1px; // outline 內縮 + } + } } - .mainExifImgItem { - height: 150px; - max-width: 150px; - width: 100%; - margin-top: 3px; - margin-right: 4px; - border-radius: 6px; - background-color: var(--color-white10); - overflow: hidden; - - img { + // google map + .mainExifMap { + position: relative; + width: 100%; + height: 200px; + background-color: rgb(232, 234, 237); + border-radius: 7px; + overflow: hidden; + } + .mainExifMap::after { + z-index: 0; + content: "Map Loading"; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + height: 30px; + text-align: center; + font-size: 20px; + margin: auto; + display: block; + color: #333; + } + .mainExifMapIframe { + position: absolute; + z-index: 1; width: 100%; height: 100%; - object-fit: cover; - pointer-events: none; + border: none; + overflow: hidden; user-select: none; - } - // 沒有圖片時,隱藏 - img:not([src]) { - opacity: 0; - } + } - &:last-child { - margin-right: 0; - } + // 右上角的按鈕群 + .mainExifBtns { + position: absolute; + top: 0; + right: 0; + display: flex; + flex-direction: row; - &:hover { - cursor: pointer; - outline: 1px solid var(--color-blue); - outline-offset: -1px; // outline 內縮 - } - } - } - - // google map - .mainExifMap { - position: relative; - width: 100%; - height: 200px; - background-color: rgb(232, 234, 237); - border-radius: 7px; - overflow: hidden; - } - .mainExifMap::after { - z-index: 0; - content: "Map Loading"; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - height: 30px; - text-align: center; - font-size: 20px; - margin: auto; - display: block; - color: #333; - } - .mainExifMapIframe { - position: absolute; - z-index: 1; - width: 100%; - height: 100%; - border: none; - overflow: hidden; - user-select: none; - } - - // 右上角的按鈕群 - .mainExifBtns { - position: absolute; - top: 0; - right: 0; - display: flex; - flex-direction: row; - - .btn { - width: 24px; - height: 24px; - background-color: var(--color-black80); - border: 1px solid var(--color-blue40); - border-radius: 4px; - display: flex; - align-items: center; - justify-content: center; - opacity: 0; - transition: 0s opacity; - } - // 移入按鈕時,顯示按鈕 - .btn:hover { - cursor: pointer; - transition: 0s opacity !important; - opacity: 1 !important; + .btn { + width: 24px; + height: 24px; + background-color: var(--color-black80); + border: 1px solid var(--color-blue40); + border-radius: 4px; + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + transition: 0s opacity; + } + // 移入按鈕時,顯示按鈕 + .btn:hover { + cursor: pointer; + transition: 0s opacity !important; + opacity: 1 !important; + } + .btn svg { + pointer-events: none; + width: 18px; + height: 18px; + } } - .btn svg { - pointer-events: none; - width: 18px; - height: 18px; + // 移入整個項目時,顯示半透明的按鈕 + .mainExifItem:hover .mainExifBtns .btn { + opacity: 0.3; + transition: 0.3s opacity; } - } - // 移入整個項目時,顯示半透明的按鈕 - .mainExifItem:hover .mainExifBtns .btn { - opacity: 0.3; - transition: 0.3s opacity; - } } //寬度足夠時,橫向排列 .mainExif--horizontal .mainExifItem { - display: flex; + display: flex; } //啟用 .mainExif[active="true"] { - display: flex; + display: flex; } //暫時隱藏 .mainExif[hide="true"] { - display: none !important; + display: none !important; } /* #endregion */ // 側邊的文字編輯器 .textEditor { - position: fixed; - left: 0; - right: 0; - bottom: 0; - top: 35px; - //backdrop-filter: saturate(180%) blur(5px); - transform: translateX(420px); - transition: all 0.1s; - opacity: 0; - pointer-events: none; - - &[active="true"] { - transform: translateX(0px); - opacity: 1; - pointer-events: initial; - } - - .textEditor-box { position: fixed; + left: 0; + right: 0; + bottom: 0; top: 35px; - bottom: 5px; - right: 5px; - max-width: 400px; - width: calc(100% - 40px); - margin-left: 60px; - - background-color: var(--color-black80); - border-radius: 8px; - box-shadow: 0px 0px 3px var(--color-blue40); - border: 1px solid var(--color-blue40); - backdrop-filter: saturate(180%) blur(20px); + //backdrop-filter: saturate(180%) blur(5px); + transform: translateX(420px); + transition: all 0.1s; + opacity: 0; + pointer-events: none; - display: flex; - flex-direction: column; - } + &[active="true"] { + transform: translateX(0px); + opacity: 1; + pointer-events: initial; + } - //上面的按鈕群 - .textEditor-toolbar { - display: flex; - flex-direction: row; - margin: 5px; - - .textEditor-toolbarItem { - height: 35px; - width: 35px; - border-radius: 5px; - display: flex; - justify-content: center; - align-items: center; - user-select: none; - &:hover { - background-color: var(--color-white10); - cursor: pointer; - } - svg { - width: 25px; - } + .textEditor-box { + position: fixed; + top: 35px; + bottom: 5px; + right: 5px; + max-width: 400px; + width: calc(100% - 40px); + margin-left: 60px; + + background-color: var(--color-black80); + border-radius: 8px; + box-shadow: 0px 0px 3px var(--color-blue40); + border: 1px solid var(--color-blue40); + backdrop-filter: saturate(180%) blur(20px); + + display: flex; + flex-direction: column; } - //右上角的關閉 - .textEditor-toolbarItem__close { - margin-left: auto; + //上面的按鈕群 + .textEditor-toolbar { + display: flex; + flex-direction: row; + margin: 5px; + + .textEditor-toolbarItem { + height: 35px; + width: 35px; + border-radius: 5px; + display: flex; + justify-content: center; + align-items: center; + user-select: none; + &:hover { + background-color: var(--color-white10); + cursor: pointer; + } + svg { + width: 25px; + } + } - // X圖示 - &::after { - content: ""; - height: 15px; - width: 2px; - background-color: var(--color-blue); - position: absolute; - transform: rotate(45deg); - } - &::before { - content: ""; - height: 2px; - width: 15px; - background-color: var(--color-blue); - position: absolute; - transform: rotate(45deg); - } + //右上角的關閉 + .textEditor-toolbarItem__close { + margin-left: auto; + + // X圖示 + &::after { + content: ""; + height: 15px; + width: 2px; + background-color: var(--color-blue); + position: absolute; + transform: rotate(45deg); + } + &::before { + content: ""; + height: 2px; + width: 15px; + background-color: var(--color-blue); + position: absolute; + transform: rotate(45deg); + } + } } - } - .textEditor-content { - flex: 1; - display: flex; - } - .textEditor-textarea { - background-color: rgba(0, 0, 0, 0); - color: var(--color-white); - border: 1px solid var(--color-white40); - outline: none; - border-radius: 8px; - margin: 8px; - padding: 5px; - margin-top: 0; - flex: 1; - overflow-y: auto; - overflow-x: hidden; - resize: none; //右下角的拖曳方塊 - } + .textEditor-content { + flex: 1; + display: flex; + } + .textEditor-textarea { + background-color: rgba(0, 0, 0, 0); + color: var(--color-white); + border: 1px solid var(--color-white40); + outline: none; + border-radius: 8px; + margin: 8px; + padding: 5px; + margin-top: 0; + flex: 1; + overflow-y: auto; + overflow-x: hidden; + resize: none; //右下角的拖曳方塊 + } } diff --git a/Www/scss/MainWindow/_MainFileList.scss b/Www/scss/MainWindow/_MainFileList.scss index 90069af7..51d54153 100644 --- a/Www/scss/MainWindow/_MainFileList.scss +++ b/Www/scss/MainWindow/_MainFileList.scss @@ -1,112 +1,112 @@ /* #region 檔案預覽視窗 */ :root { - --fileList-width: 120px; + --fileList-width: 120px; } .main-fileList { - display: none; - - overflow-x: hidden; - height: 100%; - width: var(--fileList-width); - - .main-fileListBody { - overflow: hidden; - padding-top: 3px; - } - - .fileList-item { - padding-left: 6px; - margin-right: 6px; - user-select: none; - margin-bottom: 6px; - white-space: nowrap; - position: relative; - cursor: pointer; - } - - .fileList-item:hover::before { - position: absolute; - top: -3px; - left: 3px; - right: -3px; - bottom: -3px; - border: 2px solid var(--color-white40); - pointer-events: none; - z-index: 1; - content: ""; - border-radius: 7px; - } - - //選中 - .fileList-item[active="true"]::before { - position: absolute; - top: -3px; - left: 3px; - right: -3px; - bottom: -3px; - border: 2px solid var(--color-blue); - pointer-events: none; - z-index: 1; - content: ""; - border-radius: 7px; - } - - .fileList-title { - display: flex; - flex-direction: row; - font-size: 14px; - } - - //編號 - .fileList-no { - margin-bottom: 2px; - line-height: 14px; - height: 14px; - overflow: hidden; - font-weight: var(--fontWeightBold); - color: var(--color-blue); - margin-right: 3px; - } - - //檔名 - .fileList-name { - margin-bottom: 2px; - line-height: 14px; - height: 14px; - overflow: hidden; - text-align: center; - flex: 1; - white-space: nowrap; - color: var(--color-white); - } - - //圖片 - .fileList-img { - width: calc(var(--fileList-width) - 12px); - height: calc(var(--fileList-width) - 12px); - background-size: cover; - background-repeat: no-repeat; - background-position: center center; - overflow: hidden; - border-radius: 4px; - img { - width: 100%; - height: 100%; - object-fit: cover; - pointer-events: none; - user-select: none; + display: none; + + overflow-x: hidden; + height: 100%; + width: var(--fileList-width); + + .main-fileListBody { + overflow: hidden; + padding-top: 3px; + } + + .fileList-item { + padding-left: 6px; + margin-right: 6px; + user-select: none; + margin-bottom: 6px; + white-space: nowrap; + position: relative; + cursor: pointer; + } + + .fileList-item:hover::before { + position: absolute; + top: -3px; + left: 3px; + right: -3px; + bottom: -3px; + border: 2px solid var(--color-white40); + pointer-events: none; + z-index: 1; + content: ""; + border-radius: 7px; + } + + //選中 + .fileList-item[active="true"]::before { + position: absolute; + top: -3px; + left: 3px; + right: -3px; + bottom: -3px; + border: 2px solid var(--color-blue); + pointer-events: none; + z-index: 1; + content: ""; + border-radius: 7px; + } + + .fileList-title { + display: flex; + flex-direction: row; + font-size: 14px; + } + + //編號 + .fileList-no { + margin-bottom: 2px; + line-height: 14px; + height: 14px; + overflow: hidden; + font-weight: var(--fontWeightBold); + color: var(--color-blue); + margin-right: 3px; + } + + //檔名 + .fileList-name { + margin-bottom: 2px; + line-height: 14px; + height: 14px; + overflow: hidden; + text-align: center; + flex: 1; + white-space: nowrap; + color: var(--color-white); + } + + //圖片 + .fileList-img { + width: calc(var(--fileList-width) - 12px); + height: calc(var(--fileList-width) - 12px); + background-size: cover; + background-repeat: no-repeat; + background-position: center center; + overflow: hidden; + border-radius: 4px; + img { + width: 100%; + height: 100%; + object-fit: cover; + pointer-events: none; + user-select: none; + } } - } } //啟用 .main-fileList[active="true"] { - display: block; + display: block; } //暫時隱藏 .main-fileList[hide="true"] { - display: none !important; + display: none !important; } /* #endregion */ @@ -116,57 +116,57 @@ // 滾動條樣式 (小型、用於檔案預覽視窗 .base-scrollbar-mini { - position: relative; + position: relative; - &::-webkit-scrollbar { - display: none; - } - - /*垂直滾動條*/ - .scroll-y { - width: 10px; - position: absolute; - right: 0px; - z-index: 1; - } - - /*背景*/ - .scroll-y .scroll-bg { - height: 100%; - width: 10px; - background-color: var(--color-black60); - position: absolute; - right: 0; - top: 0; - bottom: 0; - opacity: 0; - } - - /*拖曳區域*/ - .scroll-y .scroll-box { - width: 3px; - background-color: var(--color-white40); - position: absolute; - right: 0; - border-top: 3px solid rgba(0, 0, 0, 0); - border-bottom: 3px solid rgba(0, 0, 0, 0); - background-clip: content-box; - } - - .scroll-y:hover { - cursor: pointer; - } - - /*移入與拖曳時-背景*/ - .scroll-y:hover .scroll-bg, - .scroll-y[action="true"] .scroll-bg { - opacity: 1; - backdrop-filter: saturate(180%) blur(20px); - } - - /*移入與拖曳時-拖曳區域*/ - .scroll-y:hover .scroll-box, - .scroll-y[action="true"] .scroll-box { - width: 7px !important; - } + &::-webkit-scrollbar { + display: none; + } + + /*垂直滾動條*/ + .scroll-y { + width: 10px; + position: absolute; + right: 0px; + z-index: 1; + } + + /*背景*/ + .scroll-y .scroll-bg { + height: 100%; + width: 10px; + background-color: var(--color-black60); + position: absolute; + right: 0; + top: 0; + bottom: 0; + opacity: 0; + } + + /*拖曳區域*/ + .scroll-y .scroll-box { + width: 3px; + background-color: var(--color-white40); + position: absolute; + right: 0; + border-top: 3px solid rgba(0, 0, 0, 0); + border-bottom: 3px solid rgba(0, 0, 0, 0); + background-clip: content-box; + } + + .scroll-y:hover { + cursor: pointer; + } + + /*移入與拖曳時-背景*/ + .scroll-y:hover .scroll-bg, + .scroll-y[action="true"] .scroll-bg { + opacity: 1; + backdrop-filter: saturate(180%) blur(20px); + } + + /*移入與拖曳時-拖曳區域*/ + .scroll-y:hover .scroll-box, + .scroll-y[action="true"] .scroll-box { + width: 7px !important; + } } diff --git a/Www/scss/MainWindow/_MainToolbar.scss b/Www/scss/MainWindow/_MainToolbar.scss index f689fc06..54b86f2c 100644 --- a/Www/scss/MainWindow/_MainToolbar.scss +++ b/Www/scss/MainWindow/_MainToolbar.scss @@ -1,205 +1,205 @@ /* #region main-toolbar 工具列 */ .main-toolbar { - height: 35px; - color: var(--color-white); - overflow-x: visible; - overflow-y: hidden; - margin-bottom: 3px; + height: 35px; + color: var(--color-white); + overflow-x: visible; + overflow-y: hidden; + margin-bottom: 3px; } .toolbar-content { - display: flex; - position: absolute; - left: 0; - min-width: 100%; + display: flex; + position: absolute; + left: 0; + min-width: 100%; } // ---------- // 滾動條樣式 .main-toolbar__scrollbar { - position: relative; - - &::-webkit-scrollbar { - display: none; - } - - // 水平滾動條 - .scroll-x { - height: 3px; - position: absolute; - bottom: 0px; - z-index: 1; - } - - // 背景 - .scroll-x .scroll-bg { - height: 3px; - width: 100%; - background-color: var(--color-black60); - position: absolute; - margin: auto; - left: 0; - right: 0; - //top: 0; - bottom: 0; - opacity: 0; - } - - // 拖曳區域 - .scroll-x .scroll-box { - height: 3px; - background-color: var(--color-white40); - position: absolute; - bottom: 0px; - // border: 3px solid rgba(0, 0, 0, 0); - // background-clip: content-box; - } - - .scroll-x:hover { - cursor: pointer; - } - - // 移入與拖曳時-背景 - .scroll-x:hover .scroll-bg, - .scroll-x[action="true"] .scroll-bg { - opacity: 1; - } - - // 移入與拖曳時-拖曳區域 - .scroll-x:hover .scroll-box, - .scroll-x[action="true"] .scroll-box { - } + position: relative; + + &::-webkit-scrollbar { + display: none; + } + + // 水平滾動條 + .scroll-x { + height: 3px; + position: absolute; + bottom: 0px; + z-index: 1; + } + + // 背景 + .scroll-x .scroll-bg { + height: 3px; + width: 100%; + background-color: var(--color-black60); + position: absolute; + margin: auto; + left: 0; + right: 0; + //top: 0; + bottom: 0; + opacity: 0; + } + + // 拖曳區域 + .scroll-x .scroll-box { + height: 3px; + background-color: var(--color-white40); + position: absolute; + bottom: 0px; + // border: 3px solid rgba(0, 0, 0, 0); + // background-clip: content-box; + } + + .scroll-x:hover { + cursor: pointer; + } + + // 移入與拖曳時-背景 + .scroll-x:hover .scroll-bg, + .scroll-x[action="true"] .scroll-bg { + opacity: 1; + } + + // 移入與拖曳時-拖曳區域 + .scroll-x:hover .scroll-box, + .scroll-x[action="true"] .scroll-box { + } } // ---------- .main-toolbar-group { - display: none; - margin-left: 3px; - margin-bottom: 3px; - flex: 1; + display: none; + margin-left: 3px; + margin-bottom: 3px; + flex: 1; } .main-toolbar-group[active="true"] { - display: flex; - align-items: center; + display: flex; + align-items: center; } // ---------- // 垂直線 .main-toolbar-hr { - width: 1px; - min-width: 1px; - height: 29px; - display: flex; - align-items: center; - justify-content: center; - background-color: var(--color-white20); - margin: 0 3px; + width: 1px; + min-width: 1px; + height: 29px; + display: flex; + align-items: center; + justify-content: center; + background-color: var(--color-white20); + margin: 0 3px; } // ---------- // 純文字資訊 .main-toolbar-txt { - height: 35px; - font-size: 15px; - line-height: 17px; - display: flex; - align-items: center; - user-select: none; - white-space: nowrap; - padding-right: 5px; - margin-left: 12px; - position: relative; + height: 35px; + font-size: 15px; + line-height: 17px; + display: flex; + align-items: center; + user-select: none; + white-space: nowrap; + padding-right: 5px; + margin-left: 12px; + position: relative; } // 純文字資訊-左邊的垂直線 .main-toolbar-txt::after { - position: absolute; - content: ""; - background-color: var(--color-white20); - height: 29px; - width: 1px; - top: 0; - bottom: 0; - left: -9px; - margin: auto; + position: absolute; + content: ""; + background-color: var(--color-white20); + height: 29px; + width: 1px; + top: 0; + bottom: 0; + left: -9px; + margin: auto; } // ---------- // 按鈕 .main-toolbar-btn { - min-width: 35px; - height: 35px; - display: flex; - align-items: center; - justify-content: center; - border-radius: 4px; - font-size: 15px; - user-select: none; - flex-shrink: 0; // 避免壓縮 - &:hover { - cursor: pointer; - background-color: var(--color-white10); - } - &:active { - background-color: var(--color-white30); - } - svg, - img { - width: 25px; - height: 25px; - pointer-events: none; - } + min-width: 35px; + height: 35px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 4px; + font-size: 15px; + user-select: none; + flex-shrink: 0; // 避免壓縮 + &:hover { + cursor: pointer; + background-color: var(--color-white10); + } + &:active { + background-color: var(--color-white30); + } + svg, + img { + width: 25px; + height: 25px; + pointer-events: none; + } } // 開啟選單時 .main-toolbar-btn.menuActive { - background-color: var(--color-white20) !important; + background-color: var(--color-white20) !important; } // ---------- // 置中 #main-toolbar[toolbarAlign="center"] .main-toolbar-group::before { - content: ""; - margin-left: auto; - display: block; - order: -1; + content: ""; + margin-left: auto; + display: block; + order: -1; } .main-toolbar-group::after { - content: ""; - margin-left: auto; - display: block; - order: 2000; + content: ""; + margin-left: auto; + display: block; + order: 2000; } // ---------- // 返回按鈕 .main-toolbar-back { - // min-width: 50px; - position: relative; - margin-right: 4px; - display: none; + // min-width: 50px; + position: relative; + margin-right: 4px; + display: none; } .main-toolbar-back[active="true"] { - display: flex; + display: flex; } // 返回按鈕-右邊的垂直線 .main-toolbar-back::after { - position: absolute; - content: ""; - background-color: var(--color-white20); - height: 29px; - width: 1px; - top: 0; - bottom: 0; - right: -4px; - margin: auto; + position: absolute; + content: ""; + background-color: var(--color-white20); + height: 29px; + width: 1px; + top: 0; + bottom: 0; + right: -4px; + margin: auto; } /* #endregion */ diff --git a/Www/scss/Menu.scss b/Www/scss/Menu.scss deleted file mode 100644 index d1dc298a..00000000 --- a/Www/scss/Menu.scss +++ /dev/null @@ -1,239 +0,0 @@ -.menu { - background-color: rgba(0, 0, 0, 0); - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - z-index: 100; - //pointer-events: none; - display: none; - //opacity: 0; - //transition: opacity 5s; - //transform: translateY(-5px); - app-region: no-drag; //讓視窗不允許拖曳 -} - -.menu[active="true"] { - //pointer-events: inherit; - display: block; - //transition: opacity 5s; - //opacity: 1; - //transform: translateY(0px) !important; -} - -.menu-content { - position: absolute; - overflow-y: auto; - overflow-x: hidden; - //display: flex; - //flex-direction: column; - //align-items: start; -} -.menu-box { - margin-left: 5px; - margin-right: 4px; - margin-top: 5px; - - margin-bottom: 5px; - background-color: var(--color-black80); - padding: 5px; - border-radius: 8px; - - box-shadow: 0px 0px 3px var(--color-blue40); - border: 1px solid var(--color-blue40); - backdrop-filter: saturate(180%) blur(20px); -} - -.menu-grid { - display: flex; - flex-direction: row; -} -.menu-grid-item { - min-width: 35px; - height: 35px; - max-width: 50px; - flex: 1; - border-radius: 5px; - user-select: none; - display: flex; - justify-content: center; - align-items: center; - //overflow: hidden; -} -.menu-grid-item:hover { - background-color: var(--color-white10); - cursor: pointer; -} -.menu-grid-item svg { - width: 25px; -} -.menu-grid-txt { - //width: 30px; - font-size: 12px; - color: var(--color-white); - padding: 3px 0; - //word-wrap: break-word; - //word-break: break-all; - white-space: nowrap; - text-align: center; - //transform:scaleX(0.6) -} -.menu-grid-hr { - height: 35px; - width: 1px; - background-color: var(--color-white10); - margin: 0px 3px; -} - -/* 水平項目 */ -.menu-hor-item { - max-width: 330px; - padding: 4px 4px; - padding-right: 35px; - color: var(--color-white); - border-radius: 5px; - user-select: none; - display: flex; - align-items: center; -} -.menu-hor-item:hover { - background-color: var(--color-white10); - cursor: pointer; -} - -//標題 -.menu-hor-title { - padding: 5px 5px; - //padding-left: 30px; - padding-right: 33px; - color: var(--color-blue); - user-select: none; -} -//文字框 -.menu-text { - height: 33px; - color: var(--color-blue); - border: none; - outline: none; - background-color: rgba(0, 0, 0, 0); - width: 100%; - user-select: all; -} - -/*圖示*/ -.menu-hor-icon { - width: 25px; - height: 25px; - flex-shrink: 0; - //margin-left: 3px; - margin-right: 4px; - display: flex; - align-items: center; -} -.menu-hor-icon svg { - max-width: 25px; - max-height: 25px; -} -.menu-hor-icon img { - max-width: 25px; - max-height: 25px; -} -/*文字*/ -.menu-hor-txt { - line-height: 25px; - /*寬度不足時出現「...」*/ - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - -/*水平線*/ -.menu-hor-hr { - height: 1px; - background-color: var(--color-white10); - margin: 5px 0; -} - -/*滾動條樣式*/ -.menu-content::-webkit-scrollbar { - background-color: var(--color-black60); - width: 10px; -} - -.menu-content::-webkit-scrollbar-track { - background-color: rgba(0, 0, 0, 0); -} - -.menu-content::-webkit-scrollbar-thumb { - background-color: var(--color-white40); - //產生透明框線並且剪裁掉 - border: 3px solid rgba(0, 0, 0, 0); - background-clip: content-box; -} - -#menu-bulkView { - min-width: 200px; - user-select: none; - - .menu-bulkView-box { - margin-bottom: 10px; - } - .menu-bulkView-title { - color: var(--color-white); - } - .menu-bulkView-select { - background-color: rgba(0, 0, 0, 0); - color: var(--color-white); - min-height: 35px; - border: 1px solid var(--color-white40); - border-radius: 5px; - padding: 0 5px; - width: 100%; - cursor: pointer; - } - - .menu-bulkView-checkbox { - cursor: pointer; - display: flex; - align-items: center; - height: 24px; - } - .menu-bulkView-checkbox:hover { - background-color: var(--color-white10); - } - .menu-bulkView-checkbox span { - color: var(--color-white); - } -} - -//--------- - -// 大量瀏覽模式的 每行圖片數 -.menu-bulkView-columns { - display: flex; - border-radius: 5px; - border: 1px solid var(--color-white40); - overflow: hidden; - min-width: 220px; -} -.menu-bulkView-columns-item { - flex: 1; - height: 35px; - color: var(--color-white); - display: flex; - align-items: center; - justify-content: center; - border-right: 1px solid var(--color-white40); - cursor: pointer; -} -.menu-bulkView-columns-item:hover { - background-color: var(--color-white10); -} -.menu-bulkView-columns-item:last-child { - border-right: none; -} -.menu-bulkView-columns-item[active="true"] { - // outline: 1px solid var(--color-blue); - background-color: var(--color-white20); -} diff --git a/Www/scss/Msgbox.scss b/Www/scss/Msgbox.scss deleted file mode 100644 index c76c521f..00000000 --- a/Www/scss/Msgbox.scss +++ /dev/null @@ -1,155 +0,0 @@ -.msgbox { - position: fixed; - top: 30px; - left: 0; - right: 0; - bottom: 0; - display: flex; - align-items: center; - justify-content: center; - z-index: 99; - padding-bottom: 30px; -} -@media screen and (max-width: 300px) { - .msgbox-box { - min-width: 100% !important; - } -} -.msgbox-box { - min-width: 300px; - max-width: 500px; - margin: 10px; - border-radius: 8px; - background-color: var(--color-black80); - box-shadow: 0px 0px 3px var(--color-blue40); - border: 1px solid var(--color-blue40); - backdrop-filter: saturate(180%) blur(20px); - display: flex; - flex-direction: column; - color: var(--color-white); - overflow: hidden; - position: relative; - - /*用於顯示時的動畫*/ - transition: all 0.1s; - transition-timing-function: cubic-bezier(0.6, 0.3, 0.33, 1.67); - opacity: 0.8; - transform: scaleY(1.05) translateY(0px); -} -.msgbox-box[active="true"] { - opacity: 1; - transform: scaleY(1) translateY(0px); -} - -.msgbox-txt { - //display: flex; - /* align-items: center; */ - margin: 40px; - flex: 1; - overflow-x: hidden; - overflow-y: auto; - max-height: 100px; -} - -/*文字輸入框*/ -.msgbox-input { - background-color: rgba(0, 0, 0, 0); - color: var(--color-white); - min-height: 35px; - border: 1px solid var(--color-white40); - border-radius: 5px; - padding: 0 5px; - /* width: 100%; */ - display: block; - margin-left: 40px; - margin-right: 40px; - margin-bottom: 20px; - flex: 1; -} - -.msgbox-bottom { - display: flex; - justify-content: center; - margin: 0px 10px 20px 10px; -} - -//按鈕 -.msgbox-btn { - min-width: 80px; - height: 35px; - padding: 0 10px; - margin: 0px 10px; - display: inline-flex; - align-items: center; - justify-content: center; - color: var(--color-white); - background-color: var(--color-white20); - border: none; - height: 35px; - border-radius: 5px; - user-select: none; -} -.msgbox-btn:hover { - background-color: var(--color-white30); - cursor: pointer; -} - -/*右上角的 X */ -.msgbox-close { - position: absolute; - width: 30px; - height: 30px; - display: flex; - align-items: center; - justify-content: center; - top: 0px; - right: 0px; -} - -.msgbox-close:hover { - background-color: var(--color-white10); - cursor: pointer; -} - -.msgbox-close::after { - content: ""; - height: 15px; - width: 2px; - background-color: var(--color-blue); - position: absolute; - transform: rotate(45deg); -} - -.msgbox-close::before { - content: ""; - height: 2px; - width: 15px; - background-color: var(--color-blue); - position: absolute; - transform: rotate(45deg); -} - -/* radio */ -.msgbox-radioList { - margin-bottom: 20px; - margin-left: 30px; - margin-right: 30px; -} - -.msgbox-radio { - min-height: 30px; - display: flex; - align-items: center; - padding-left: 3px; - border-radius: 5px; -} -.msgbox-radio:hover { - cursor: pointer; - background-color: var(--color-white10); -} - -//標題 -.msgbox-title { - font-size: 20px; - margin-bottom: 8px; -} diff --git a/Www/scss/SettingWindow/SettingWindow.scss b/Www/scss/SettingWindow/SettingWindow.scss index 4fc823d8..764b604c 100644 --- a/Www/scss/SettingWindow/SettingWindow.scss +++ b/Www/scss/SettingWindow/SettingWindow.scss @@ -1,287 +1,291 @@ +@import "../BaseWindow"; +@import "../Msgbox"; + + :root { - --color-primary: rgb(10, 178, 255); - --color-success: rgb(85, 255, 75); - --color-warning: rgb(255, 221, 0); - --color-danger: rgb(255, 75, 75); - --color-link: rgb(0, 200, 255); + --color-primary: rgb(10, 178, 255); + --color-success: rgb(85, 255, 75); + --color-warning: rgb(255, 221, 0); + --color-danger: rgb(255, 75, 75); + --color-link: rgb(0, 200, 255); } .color-primary { - color: var(--color-primary); + color: var(--color-primary); } .color-success { - color: var(--color-success); + color: var(--color-success); } .color-warning { - color: var(--color-warning); + color: var(--color-warning); } .color-danger { - color: var(--color-danger); + color: var(--color-danger); } .link { - color: var(--color-link); + color: var(--color-link); } .link:hover { - cursor: pointer; - text-decoration: underline; + cursor: pointer; + text-decoration: underline; } //隱藏 的箭頭 input::-webkit-outer-spin-button, input::-webkit-inner-spin-button { - -webkit-appearance: none; - margin: 0; + -webkit-appearance: none; + margin: 0; } .window { - display: flex; - flex-direction: row; - border-radius: 7px; + display: flex; + flex-direction: row; + border-radius: 7px; } .window-left { - flex-shrink: 0; - border-right: 1px solid var(--color-window-border); - // box-shadow: 0px 0px 10px rgb(0 0 0 / 60%); + flex-shrink: 0; + border-right: 1px solid var(--color-window-border); + // box-shadow: 0px 0px 10px rgb(0 0 0 / 60%); } .window-right { - display: flex; - flex-direction: column; - flex: 1; - position: relative; - // background-color: var(--color-black20); + display: flex; + flex-direction: column; + flex: 1; + position: relative; + // background-color: var(--color-black20); } .pagetab { - margin: 0px; - padding: 15px 0px; - overflow-y: auto; - overflow-x: hidden; - height: 100%; - - .page-tabsBtn { - min-width: 160px; - max-width: 250px; - padding: 0px 15px; - height: 35px; - line-height: 35px; - color: var(--color-white); - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - user-select: none; - position: relative; - border-radius: 5px; - margin: 3px 4px; - //margin-bottom: 3px; - } - .page-tabsBtn:hover { - background-color: var(--color-white10); - cursor: pointer; - } - .page-tabsBtn[active="true"] { - background-color: var(--color-white10); - /* color:var(--color-blue); */ - } - .page-tabsBtn[active="true"]::after { - width: 3px; - content: ""; - position: absolute; - top: 8px; - bottom: 8px; - left: 4px; - background-color: var(--color-blue); - color: var(--color-blue); - border-radius: 5px; - } - .page-tabsHr { - background-color: var(--color-white10); - height: 1px; - margin: 4px 10px; - } + margin: 0px; + padding: 15px 0px; + overflow-y: auto; + overflow-x: hidden; + height: 100%; + + .page-tabsBtn { + min-width: 160px; + max-width: 250px; + padding: 0px 15px; + height: 35px; + line-height: 35px; + color: var(--color-white); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + user-select: none; + position: relative; + border-radius: 5px; + margin: 3px 4px; + //margin-bottom: 3px; + } + .page-tabsBtn:hover { + background-color: var(--color-white10); + cursor: pointer; + } + .page-tabsBtn[active="true"] { + background-color: var(--color-white10); + /* color:var(--color-blue); */ + } + .page-tabsBtn[active="true"]::after { + width: 3px; + content: ""; + position: absolute; + top: 8px; + bottom: 8px; + left: 4px; + background-color: var(--color-blue); + color: var(--color-blue); + border-radius: 5px; + } + .page-tabsHr { + background-color: var(--color-white10); + height: 1px; + margin: 4px 10px; + } } // 左上角的logo資訊 .logobox { - display: flex; - margin: 10px 0px; - align-items: center; - pointer-events: none; - user-select: none; - - .logobox-img { - width: 36px; - margin-right: 5px; - } + display: flex; + margin: 10px 0px; + align-items: center; + pointer-events: none; + user-select: none; - .logobox-text { - color: var(--color-white); - line-height: 15px; - } + .logobox-img { + width: 36px; + margin-right: 5px; + } - .logobox-text-title { - font-size: 18px; - } + .logobox-text { + color: var(--color-white); + line-height: 15px; + } + + .logobox-text-title { + font-size: 18px; + } - .logobox-text-subtitle { - font-size: 14px; - color: var(--color-white40); - } + .logobox-text-subtitle { + font-size: 14px; + color: var(--color-white40); + } } /**************/ .window-body { - flex: 1; - overflow: auto; - position: absolute; - left: 0; - right: 0px; - top: 30px; - bottom: 0px; + flex: 1; + overflow: auto; + position: absolute; + left: 0; + right: 0px; + top: 30px; + bottom: 0px; } .page-tabsPage { - max-width: 600px; - padding-top: 0px; - padding-left: 20px; - padding-right: 20px; - padding-bottom: 30px; + max-width: 600px; + padding-top: 0px; + padding-left: 20px; + padding-right: 20px; + padding-bottom: 30px; - display: none; + display: none; } .page-title { - font-size: 24px; - color: var(--color-white); - margin-bottom: 20px; - margin-top: -5px; + font-size: 24px; + color: var(--color-white); + margin-bottom: 20px; + margin-top: -5px; } .page-tabsPage[active="true"] { - display: block !important; + display: block !important; } .page-hr { - height: 1px; - background-color: var(--color-white20); - margin: 10px 0; + height: 1px; + background-color: var(--color-white20); + margin: 10px 0; } /**************/ .box { - margin-bottom: 40px; + margin-bottom: 40px; - .box-title { - color: var(--color-white); - font-size: 20px; - margin-bottom: 0px; - } + .box-title { + color: var(--color-white); + font-size: 20px; + margin-bottom: 0px; + } - .text-title { - color: var(--color-white); - margin-bottom: 3px; - margin-top: 10px; - display: flex; - align-items: center; - } - .text-title__60 { - color: var(--color-white60); - } - - .text-content { - max-width: 250px; - display: flex; - } + .text-title { + color: var(--color-white); + margin-bottom: 3px; + margin-top: 10px; + display: flex; + align-items: center; + } + .text-title__60 { + color: var(--color-white60); + } - .collapseBox { - border-left: 1px solid var(--color-white40); - padding-left: 15px; - padding-bottom: 5px; - margin-left: 15px; + .text-content { + max-width: 250px; + display: flex; + } - display: none; - &[active="true"] { - display: block; + .collapseBox { + border-left: 1px solid var(--color-white40); + padding-left: 15px; + padding-bottom: 5px; + margin-left: 15px; + + display: none; + &[active="true"] { + display: block; + } } - } } .text-input { - background-color: rgba(0, 0, 0, 0); - color: var(--color-white); - min-height: 35px; - border: 1px solid var(--color-white40); - border-radius: 5px; - padding: 0 5px; - width: 100%; - display: block; - flex: 1; + background-color: rgba(0, 0, 0, 0); + color: var(--color-white); + min-height: 35px; + border: 1px solid var(--color-white40); + border-radius: 5px; + padding: 0 5px; + width: 100%; + display: block; + flex: 1; } /******************/ // 擴充套件清單 .pluginLiet { - margin-top: 5px; - max-width: 800px; - // background-color: var(--color-white10); - // box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.6); - padding: 10px; - border-radius: 5px; - border: 1px solid var(--color-white40); - - .pluginLiet-item { - color: var(--color-white); - display: flex; - border-bottom: 1px solid var(--color-white40); - padding-bottom: 10px; - margin-bottom: 10px; - } - .pluginLiet-item:last-child { - border-bottom: none; - padding-bottom: 0px; - margin-bottom: 0px; - } - - .pluginLiet-L { - flex: 1; - } - .pluginLiet-R { - margin-left: 10px; - padding-left: 10px; - display: flex; - align-items: center; - justify-content: center; - border-left: 1px solid var(--color-white40); - max-width: 60px; - } - .pluginLiet-title { - font-size: 18px; - } - .pluginLiet-text { - color: var(--color-white60); - } - .pluginLiet-status { - } + margin-top: 5px; + max-width: 800px; + // background-color: var(--color-white10); + // box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.6); + padding: 10px; + border-radius: 5px; + border: 1px solid var(--color-white40); + + .pluginLiet-item { + color: var(--color-white); + display: flex; + border-bottom: 1px solid var(--color-white40); + padding-bottom: 10px; + margin-bottom: 10px; + } + .pluginLiet-item:last-child { + border-bottom: none; + padding-bottom: 0px; + margin-bottom: 0px; + } + + .pluginLiet-L { + flex: 1; + } + .pluginLiet-R { + margin-left: 10px; + padding-left: 10px; + display: flex; + align-items: center; + justify-content: center; + border-left: 1px solid var(--color-white40); + max-width: 60px; + } + .pluginLiet-title { + font-size: 18px; + } + .pluginLiet-text { + color: var(--color-white60); + } + .pluginLiet-status { + } } /******************/ .btn { - color: var(--color-white); - background-color: var(--color-white20); - border: none; - height: 35px; - padding: 0 10px; - border-radius: 5px; - display: inline-flex; - align-items: center; - justify-content: center; - margin-right: 5px; - margin-top: 5px; + color: var(--color-white); + background-color: var(--color-white20); + border: none; + height: 35px; + padding: 0 10px; + border-radius: 5px; + display: inline-flex; + align-items: center; + justify-content: center; + margin-right: 5px; + margin-top: 5px; } .btn:hover { - cursor: pointer; - background-color: var(--color-white30); + cursor: pointer; + background-color: var(--color-white30); } /*------------------*/ @@ -289,77 +293,77 @@ input::-webkit-inner-spin-button { /* #region switch*/ .switch { - position: relative; - display: inline-block; - width: 50px; - height: 24px; - cursor: pointer; + position: relative; + display: inline-block; + width: 50px; + height: 24px; + cursor: pointer; - input { - opacity: 0; - width: 0; - height: 0; - } + input { + opacity: 0; + width: 0; + height: 0; + } - .slider { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - /* background-color: #ccc; */ - -webkit-transition: 0.4s; - transition: 0.4s; - border: 1px solid var(--color-white40); - user-select: none; // 禁止選取 - } + .slider { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + /* background-color: #ccc; */ + -webkit-transition: 0.4s; + transition: 0.4s; + border: 1px solid var(--color-white40); + user-select: none; // 禁止選取 + } - .slider:before { - position: absolute; - content: ""; - height: 12px; - width: 12px; - left: 6px; - top: 0; - bottom: 0px; - margin: auto; - background-color: var(--color-white); - -webkit-transition: 0.3s; - transition: 0.3s; - } - - input:checked + .slider { - background-color: var(--color-primary); - border: 1px solid var(--color-primary); - } - input:checked + .slider:before { - background-color: var(--color-white); - /* border: 1px solid var(--color-blue); */ - } - - input:checked + .slider:before { - transform: translateX(26px); - } + .slider:before { + position: absolute; + content: ""; + height: 12px; + width: 12px; + left: 6px; + top: 0; + bottom: 0px; + margin: auto; + background-color: var(--color-white); + -webkit-transition: 0.3s; + transition: 0.3s; + } + + input:checked + .slider { + background-color: var(--color-primary); + border: 1px solid var(--color-primary); + } + input:checked + .slider:before { + background-color: var(--color-white); + /* border: 1px solid var(--color-blue); */ + } + + input:checked + .slider:before { + transform: translateX(26px); + } } /* Rounded sliders */ .slider.round { - border-radius: 24px; + border-radius: 24px; } .slider.round:before { - border-radius: 50%; + border-radius: 50%; } .radio-group { } .radio-group label { - display: block; - /* line-height: 20px; */ - min-height: 30px; - display: flex; - align-items: center; - color: var(--color-white); + display: block; + /* line-height: 20px; */ + min-height: 30px; + display: flex; + align-items: center; + color: var(--color-white); } /* #endregion */ @@ -370,165 +374,165 @@ input::-webkit-inner-spin-button { // 問號 .img-help { - display: inline-block; - cursor: pointer; - width: 18px; - height: 18px; - min-width: 18px; - margin-left: 5px; + display: inline-block; + cursor: pointer; + width: 18px; + height: 18px; + min-width: 18px; + margin-left: 5px; } .img-help svg { - pointer-events: none; + pointer-events: none; } .img-help svg path { - fill: var(--color-primary); + fill: var(--color-primary); } .tippy-box[data-theme~="tippyMyTheme"] { - // 自訂主題 - box-sizing: content-box; - transition: all 0.15s cubic-bezier(0.49, 0.37, 0.45, 1.4) !important; - background-color: var(--color-black); - //backdrop-filter: saturate(180%) blur(20px); - border: 1px solid var(--color-blue40); - box-shadow: 0px 0px 3px var(--color-blue40); - border-radius: 8px; + // 自訂主題 + box-sizing: content-box; + transition: all 0.15s cubic-bezier(0.49, 0.37, 0.45, 1.4) !important; + background-color: var(--color-black); + //backdrop-filter: saturate(180%) blur(20px); + border: 1px solid var(--color-blue40); + box-shadow: 0px 0px 3px var(--color-blue40); + border-radius: 8px; } .tippy-box[data-animation="tippyMyAnimation"][data-state="hidden"] { - //自訂動畫 - opacity: 0; - transform: scale(0.92); - //padding: 5px; - //margin:-5px; - transition: all 0s !important; //滑鼠離開後立即關閉 + //自訂動畫 + opacity: 0; + transform: scale(0.92); + //padding: 5px; + //margin:-5px; + transition: all 0s !important; //滑鼠離開後立即關閉 } //#endregion // 自訂工具列 .toolbarList { - margin-left: 30px; - - .toolbarList-item { - display: flex; - align-items: center; - background-color: var(--color-white10); - padding: 5px; - border-radius: 5px; - color: var(--color-white); - position: relative; - margin-bottom: 5px; - user-select: none; - cursor: ns-resize; - - input { - position: absolute; - top: 0; - bottom: 0; - left: -25px; - margin: auto; - } - svg { - height: 25px; - margin-right: 5px; + margin-left: 30px; + + .toolbarList-item { + display: flex; + align-items: center; + background-color: var(--color-white10); + padding: 5px; + border-radius: 5px; + color: var(--color-white); + position: relative; + margin-bottom: 5px; + user-select: none; + cursor: ns-resize; + + input { + position: absolute; + top: 0; + bottom: 0; + left: -25px; + margin: auto; + } + svg { + height: 25px; + margin-right: 5px; + } } - } } // 佈局順序 .layoutOrder-list { - .layoutOrder-item { - min-height: 35px; - display: flex; - align-items: center; - background-color: var(--color-white10); - padding-left: 10px; - border-radius: 5px; - color: var(--color-white); - position: relative; - margin-bottom: 5px; - user-select: none; - cursor: ns-resize; - } + .layoutOrder-item { + min-height: 35px; + display: flex; + align-items: center; + background-color: var(--color-white10); + padding-left: 10px; + border-radius: 5px; + color: var(--color-white); + position: relative; + margin-bottom: 5px; + user-select: none; + cursor: ns-resize; + } } // radio 水平排列 .radioList-h { - display: flex; - flex-wrap: wrap; - - .radioList-item { - width: 110px; - margin-right: 10px; display: flex; - flex-direction: column; - color: #fff; - align-items: flex-start; - flex-shrink: 0; - //margin-bottom: 10px; - padding: 5px 0; - border-radius: 5px; - } + flex-wrap: wrap; + + .radioList-item { + width: 110px; + margin-right: 10px; + display: flex; + flex-direction: column; + color: #fff; + align-items: flex-start; + flex-shrink: 0; + //margin-bottom: 10px; + padding: 5px 0; + border-radius: 5px; + } - .radioList-item:hover { - cursor: pointer; - background-color: var(--color-white10); - } - .radioList-item input[type="radio"] { - margin-bottom: 5px; - margin-left: 5px; - } - .radioList-item span { - margin: auto; - margin-top: 3px; - text-align: center; - // margin-left: 5px; - } - .radioList-item img { - margin: 0 5px; - width: 70px; - margin: auto; - } - .radioList-item:hover { - cursor: pointer; - } + .radioList-item:hover { + cursor: pointer; + background-color: var(--color-white10); + } + .radioList-item input[type="radio"] { + margin-bottom: 5px; + margin-left: 5px; + } + .radioList-item span { + margin: auto; + margin-top: 3px; + text-align: center; + // margin-left: 5px; + } + .radioList-item img { + margin: 0 5px; + width: 70px; + margin: auto; + } + .radioList-item:hover { + cursor: pointer; + } } // radio 垂直排列 .radioList-v { - label { - display: block; - position: relative; - min-height: 30px; - border-radius: 5px; - } - label:hover { - cursor: pointer; - background-color: var(--color-white10); - } - label span { - } - label input[type="radio"] { - left: 2px; - top: 8px; - position: absolute; - } - .radioList-content { - margin-left: 24px; - padding-top: 3px; - flex-direction: column; - color: #fff; - align-items: flex-start; - flex-shrink: 0; - } - .img-help { - //提示的問號 - transform: translateY(3px); - } + label { + display: block; + position: relative; + min-height: 30px; + border-radius: 5px; + } + label:hover { + cursor: pointer; + background-color: var(--color-white10); + } + label span { + } + label input[type="radio"] { + left: 2px; + top: 8px; + position: absolute; + } + .radioList-content { + margin-left: 24px; + padding-top: 3px; + flex-direction: column; + color: #fff; + align-items: flex-start; + flex-shrink: 0; + } + .img-help { + //提示的問號 + transform: translateY(3px); + } } //--------------------- // 如果是商店APP版,就隱藏區塊 body[showType="storeApp"] [show-not="storeApp"] { - display: none; + display: none; } diff --git a/Www/scss/Tiefseeview.scss b/Www/scss/Tiefseeview.scss deleted file mode 100644 index ebdfb12f..00000000 --- a/Www/scss/Tiefseeview.scss +++ /dev/null @@ -1,231 +0,0 @@ -.tiefseeview { - overflow: hidden; - position: relative; - - // 用於縮放 dpi - .tiefseeview-dpizoom { - position: relative; - top: 0; - left: 0; - right: 0; - bottom: 0; - width: 100%; - height: 100%; - zoom: 1; - } - - // 實際佔位,用於設定 left、top - .tiefseeview-container { - pointer-events: none; - position: absolute; - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; - } - - // 放圖片的容器,用於套用旋轉 - .tiefseeview-data { - // 縮放是以圖片寬度為基準 - // width: 100%; - } - - // 圖片 - .view-img { - // width: 100%; - // height: 100%; - } - .view-bigimg { - position: relative; - } - .view-bigimg-canvas { - position: absolute; - } - .view-bigimg-bg { - position: absolute; - left: 0; - top: 0; - } - - .tiefseeview-loading { - background-position: center center; - background-size: 200px; - // background-size:100%; - z-index: 100; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-repeat: no-repeat; - } -} - -// -------- - -// 垂直滾動條 -.tiefseeview .scroll-y { - width: 20px; - position: absolute; - right: 0px; - top: 0px; - bottom: 0px; - z-index: 5; - - // 背景 - .scroll-bg { - height: 100%; - width: 10px; - background-color: var(--color-black60); - position: absolute; - // margin: auto; - // left: 0; - right: 0; - top: 0; - bottom: 0; - opacity: 0; - } - - // 拖曳區域 - .scroll-box { - width: 10px; - background-color: var(--color-white40); - position: absolute; - // margin: auto; - // left: 0; - right: 0; - // box-shadow: 0px 0px 3px 1px var(--color-black10); - // transform: scaleX(0.4); - border: 3px solid rgba(0, 0, 0, 0); - background-clip: content-box; - } - - &:hover { - cursor: pointer; - } - - // 移入與拖曳時-背景 - &:hover .scroll-bg, - &[action="true"] .scroll-bg { - opacity: 1; - backdrop-filter: saturate(180%) blur(20px); - } - - // 移入與拖曳時-拖曳區域 - &:hover .scroll-box, - &[action="true"] .scroll-box { - // background-color: rgba(255, 255, 255, 0.8); - // transform: scaleX(1); - } -} - -// -------- - -// 水平滾動條 -.tiefseeview .scroll-x { - height: 20px; - position: absolute; - right: 0px; - left: 0px; - bottom: 0px; - z-index: 5; - - // 背景 - .scroll-bg { - height: 10px; - width: 100%; - background-color: var(--color-black60); - position: absolute; - margin: auto; - left: 0; - right: 0; - // top: 0; - bottom: 0; - opacity: 0; - } - - // 拖曳區域 - .scroll-box { - height: 10px; - background-color: var(--color-white40); - position: absolute; - // top: 0; - bottom: 0px; - // margin: auto 0; - // box-shadow: 0px 0px 3px 1px var(--color-black10); - // transform: scaleY(0.4); - border: 3px solid rgba(0, 0, 0, 0); - background-clip: content-box; - } - - &:hover { - cursor: pointer; - } - - // 移入與拖曳時-背景 - &:hover .scroll-bg, - &[action="true"] .scroll-bg { - opacity: 1; - backdrop-filter: saturate(180%) blur(20px); - } - - // 移入與拖曳時-拖曳區域 - &:hover .scroll-box, - &[action="true"] .scroll-box { - // background-color: rgba(255, 255, 255, 0.8); - // transform: scaleY(1); - } -} - -// -------- - -// 剪裁 -.tiefseeview { - // 拖曳點 - .tiefseeview-clip { - position: absolute; - overflow: hidden; - top: 0; - left: 0; - right: 0; - bottom: 0; - width: 20px; - height: 20px; - border-radius: 50%; - z-index: 3; - background-color: #fff; - box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.5); - } - // 左上角 - .tiefseeview-clip-lt { - cursor: nw-resize; - } - // 右上角 - .tiefseeview-clip-rt { - cursor: ne-resize; - } - // 左下角 - .tiefseeview-clip-lb { - cursor: sw-resize; - } - // 右下角 - .tiefseeview-clip-rb { - cursor: se-resize; - } - // 中間的拖曳區塊 - .tiefseeview-clip-c { - cursor: move; - position: absolute; - z-index: 1; - } - // 周圍的半透明黑色區塊 - .tiefseeview-clip-svg { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - z-index: 2; - pointer-events: none; - } -} diff --git a/Www/scss/Toast.scss b/Www/scss/Toast.scss deleted file mode 100644 index 91fc1537..00000000 --- a/Www/scss/Toast.scss +++ /dev/null @@ -1,94 +0,0 @@ -.toastList { - position: fixed; - bottom: 0; - right: 0; - max-height: 50vh; - overflow-y: auto; - display: flex; - flex-direction: column; - align-items: flex-end; - z-index: 999; - - @keyframes toastStart { - from { - transform: translateY(-5px); - } - - to { - transform: translateY(0px); - } - } - - .toastItem { - border-radius: 8px; - background-color: var(--color-black80); - box-shadow: 0px 0px 3px var(--color-blue40); - border: 1px solid var(--color-blue40); - backdrop-filter: saturate(180%) blur(20px); - - display: flex; - margin-top: 10px; - margin-left: 10px; - margin-right: 10px; - overflow: hidden; - flex-shrink: 0; - - //動畫 - animation-name: toastStart; - animation-iteration-count: 1; - animation-duration: 0.15s; - animation-timing-function: ease-out; - } - - .toastItem:last-child { - margin-bottom: 10px; - } - - .toastText { - padding: 12px; - flex: 1; - max-width: 300px; - color: var(--color-white); - font-size: 15px; - } - - //關閉按鈕 - .toastClose { - width: 23px; - // height: 23px; - position: relative; - cursor: pointer; - } - - .toastClose:hover { - background-color: var(--color-white30); - } - - .toastClose::before { - background-color: var(--color-blue); - position: absolute; - content: ""; - height: 1px; - width: 14px; - top: 0; - left: 0; - right: 0; - bottom: 0; - margin: auto; - transform: rotate(45deg); - } - - .toastClose::after { - background-color: var(--color-blue); - position: absolute; - content: ""; - height: 14px; - width: 1px; - top: 0; - left: 0; - right: 0; - bottom: 0; - margin: auto; - transform: rotate(45deg); - } -} diff --git a/Www/scss/_BaseStyle.scss b/Www/scss/_BaseStyle.scss new file mode 100644 index 00000000..68c6e277 --- /dev/null +++ b/Www/scss/_BaseStyle.scss @@ -0,0 +1,151 @@ +body, +input, +textarea, +button, +option, +optgroup { + // font-family: "Noto Sans TC","Noto Sans CJK TC Light"; + font-family: "Segoe UI", "Microsoft JhengHei UI"; + font-size: 15px; + font-weight: var(--fontWeight); +} + +select option, +select optgroup { + background: var(--color-black); +} + +//---------------------------------------------------------------- + +//滾動條樣式 (一般,寬度10px + +/*整體背景*/ +.base-scrollbar::-webkit-scrollbar { + width: 10px; + height: 10px; +} + +//滾動條軌道(移入時 +.base-scrollbar::-webkit-scrollbar-track:hover { + background-color: var(--color-black60); +} + +//拖曳區塊 +.base-scrollbar::-webkit-scrollbar-thumb { + background-color: var(--color-white40); + + //產生透明框線並且剪裁掉 + border: 3px solid rgba(0, 0, 0, 0); + background-clip: content-box; + min-height: 50px; +} + +//右下角交匯處 +.base-scrollbar::-webkit-scrollbar-corner { + background-color: rgba(0, 0, 0, 0); +} + +//---------------------------------------------------------------- + +//滾動條樣式 (大型、寬度16px + +//整體背景 +.base-scrollbar-big::-webkit-scrollbar { + width: 16px; + height: 10px; +} + +//滾動條軌道(移入時 +.base-scrollbar-big::-webkit-scrollbar-track:hover { + background-color: var(--color-black60); + //產生透明框線並且剪裁掉 + border-left: 6px solid rgba(0, 0, 0, 0); + border-right: 0px solid rgba(0, 0, 0, 0); + background-clip: content-box; +} + +/*拖曳區塊*/ +.base-scrollbar-big::-webkit-scrollbar-thumb { + background-color: var(--color-white40); + //產生透明框線並且剪裁掉 + border-left: 9px solid rgba(0, 0, 0, 0); + border-right: 3px solid rgba(0, 0, 0, 0); + border-top: 3px solid rgba(0, 0, 0, 0); + border-bottom: 3px solid rgba(0, 0, 0, 0); + background-clip: content-box; + min-height: 50px; +} + +//右下角交匯處 +.base-scrollbar-big::-webkit-scrollbar-corner { + background-color: rgba(0, 0, 0, 0); +} + +//---------------------------------------------------------------- + +// checkbox 樣式 + +.base-checkbox { + appearance: none; + margin: 0 3px; + font: inherit; + color: currentColor; + width: 15px; + height: 15px; + border: 1px solid var(--color-white40); + border-radius: 4px; + display: grid; + place-content: center; +} + +.base-checkbox::before { + content: ""; + width: 10px; + height: 10px; + clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%); + transform: scale(0); + transform-origin: bottom left; + transition: 0.1s transform ease-in-out; + box-shadow: inset 10px 10px var(--color-blue); +} + +.base-checkbox:checked::before { + transform: scale(1); +} + +//---------------------------------------------------------------- + +// radio 樣式 +.base-radio { + appearance: none; + //margin: 0; + width: 14px; + height: 14px; + border: 1px solid var(--color-white); + border-radius: 50%; + position: relative; + margin: 0 4px; + //margin-top: 1px; + //transform: translateY(1px); +} +.base-radio:before { + content: ""; + position: absolute; + border-radius: 4px; + width: 6px; + height: 6px; + // top: 3px; + // left: 3px; + top: 0; + left: 0; + right: 0; + bottom: 0; + margin: auto; + background-color: var(--color-blue); + transform: scale(0); + //transform-origin: bottom left; + transition: 0.1s transform ease-in-out; +} +.base-radio:checked::before { + transform: scale(1); +} diff --git a/Www/scss/_BaseWindow.scss b/Www/scss/_BaseWindow.scss new file mode 100644 index 00000000..58b851dc --- /dev/null +++ b/Www/scss/_BaseWindow.scss @@ -0,0 +1,233 @@ +@import "./BaseStyle"; + +:root { + /** 可拖曳的邊框 */ + --window-border: 4px; + /** 可拖曳的四個角落 */ + --window-border-corner: 20px; + /** 視窗圓角 */ + --window-border-radius: 0px; + + --color-window-border: rgba(255, 255, 255, 0.25); + --color-window-background: rgba(31, 39, 43, 0.97); + + //一般文字 + --fontWeight: 400; + //粗體字 + --fontWeightBold: 500; + + //區塊顏色 + --color-black: rgba(0, 0, 0, 1); + --color-black80: rgba(0, 0, 0, 0.8); + --color-black60: rgba(0, 0, 0, 0.6); + --color-black40: rgba(0, 0, 0, 0.4); + --color-black20: rgba(0, 0, 0, 0.2); + + //未使用 + --color-grey: rgba(30, 30, 30, 1); + --color-grey80: rgba(30, 30, 30, 0.8); + --color-grey60: rgba(30, 30, 30, 0.6); + --color-grey40: rgba(30, 30, 30, 0.4); + --color-grey20: rgba(30, 30, 30, 0.2); + + //文字顏色、圖示顏色 + --color-white: rgb(255, 255, 255); + --color-white80: rgba(255, 255, 255, 0.8); + --color-white60: rgba(255, 255, 255, 0.6); + --color-white40: rgba(255, 255, 255, 0.4); + --color-white30: rgba(255, 255, 255, 0.3); + --color-white20: rgba(255, 255, 255, 0.2); + --color-white10: rgba(255, 255, 255, 0.1); + + //用於醒目的顏色 + --color-blue: rgb(0, 200, 255); + --color-blue80: rgba(0, 200, 255, 0.8); + --color-blue60: rgba(0, 200, 255, 0.6); + --color-blue40: rgba(0, 200, 255, 0.4); + --color-blue20: rgba(0, 200, 255, 0.2); +} + +* { + box-sizing: border-box; +} + +html, +body { + margin: 0; + padding: 0; + height: 100%; +} + +body { + display: flex; + overflow: hidden; +} + +/* 視窗本體 */ +.window { + /* transition: transform 0.2s; + transform: translateY(10px) scale(0.98); */ + flex: 1; + position: fixed; + top: 0px; + left: 0px; + right: 1.5px; + bottom: 1.5px; + overflow: hidden; + background-color: var(--color-window-background); + border-radius: var(--window-border-radius); + border: 1px solid var(--color-window-border); + + //margin-right: 1.5px; + //margin-bottom: 1.5px; + display: flex; + flex-direction: column; +} + +// 視窗最大化時 +.window.maximized { + right: 0px !important; + bottom: 0px !important; + border: none; + border-radius: 0px; +} +.window.maximized .window-border { + display: none; +} +// win11 圓角 +.window.windowRoundedCorners { + right: 0.5px; + bottom: 0.5px; + border: none; + border-radius: 0px; +} +/*---------------------------*/ + +/* #region window-titlebar 標題列*/ + +/*標題列*/ +.window-titlebar { + height: 30px; + background-color: rgba(0, 0, 0, 0); + display: flex; + justify-content: space-between; + + .titlebar-text { + height: 100%; + color: var(--color-white); + display: flex; + align-items: center; + padding: 0 8px; + flex: 1; + user-select: none; + overflow: hidden; + + app-region: drag; //讓視窗允許拖曳 + } + .titlebar-text span { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .titlebar-toolbar { + display: flex; + } + .titlebar-toolbar-btn { + height: 100%; + width: 38px; + margin-left: 1px; + display: flex; + justify-content: center; + align-items: center; + user-select: none; + /* border-radius: 4px; */ + } + + .titlebar-toolbar-btn:hover { + background-color: var(--color-white10); + cursor: pointer; + } + .titlebar-toolbar-btn svg { + width: 25px; + height: 25px; + pointer-events: none; + } +} +/* #endregion */ + +/*---------------------------*/ + +/* #region window-border 改變視窗大小的框 */ + +.window-border { + position: fixed; + z-index: 9999; + user-select: none; + app-region: no-drag; //讓視窗不允許拖曳 +} +.window-CT { + height: var(--window-border); + top: 0; + left: var(--window-border-corner); + right: var(--window-border); + cursor: n-resize; +} + +.window-RC { + width: var(--window-border); + top: var(--window-border); + right: 0; + bottom: var(--window-border-corner); + cursor: w-resize; +} + +.window-CB { + height: var(--window-border); + bottom: 0; + left: var(--window-border-corner); + right: var(--window-border-corner); + cursor: n-resize; +} + +.window-LC { + width: var(--window-border); + top: var(--window-border-corner); + left: 0; + bottom: var(--window-border-corner); + cursor: w-resize; +} + +.window-LT { + width: var(--window-border-corner); + height: var(--window-border-corner); + left: 0; + top: 0; + cursor: nw-resize; +} + +.window-RT { + width: var(--window-border); + height: var(--window-border); + right: 0; + top: 0; + cursor: ne-resize; +} + +.window-LB { + width: var(--window-border-corner); + height: var(--window-border-corner); + left: 0; + bottom: 0; + cursor: ne-resize; +} + +.window-RB { + width: var(--window-border-corner); + height: var(--window-border-corner); + right: 0; + bottom: 0; + cursor: nw-resize; +} + +/* #endregion */ diff --git a/Www/scss/_Menu.scss b/Www/scss/_Menu.scss new file mode 100644 index 00000000..b86a4ba3 --- /dev/null +++ b/Www/scss/_Menu.scss @@ -0,0 +1,239 @@ +.menu { + background-color: rgba(0, 0, 0, 0); + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 100; + //pointer-events: none; + display: none; + //opacity: 0; + //transition: opacity 5s; + //transform: translateY(-5px); + app-region: no-drag; //讓視窗不允許拖曳 +} + +.menu[active="true"] { + //pointer-events: inherit; + display: block; + //transition: opacity 5s; + //opacity: 1; + //transform: translateY(0px) !important; +} + +.menu-content { + position: absolute; + overflow-y: auto; + overflow-x: hidden; + //display: flex; + //flex-direction: column; + //align-items: start; +} +.menu-box { + margin-left: 5px; + margin-right: 4px; + margin-top: 5px; + + margin-bottom: 5px; + background-color: var(--color-black80); + padding: 5px; + border-radius: 8px; + + box-shadow: 0px 0px 3px var(--color-blue40); + border: 1px solid var(--color-blue40); + backdrop-filter: saturate(180%) blur(20px); +} + +.menu-grid { + display: flex; + flex-direction: row; +} +.menu-grid-item { + min-width: 35px; + height: 35px; + max-width: 50px; + flex: 1; + border-radius: 5px; + user-select: none; + display: flex; + justify-content: center; + align-items: center; + //overflow: hidden; +} +.menu-grid-item:hover { + background-color: var(--color-white10); + cursor: pointer; +} +.menu-grid-item svg { + width: 25px; +} +.menu-grid-txt { + //width: 30px; + font-size: 12px; + color: var(--color-white); + padding: 3px 0; + //word-wrap: break-word; + //word-break: break-all; + white-space: nowrap; + text-align: center; + //transform:scaleX(0.6) +} +.menu-grid-hr { + height: 35px; + width: 1px; + background-color: var(--color-white10); + margin: 0px 3px; +} + +/* 水平項目 */ +.menu-hor-item { + max-width: 330px; + padding: 4px 4px; + padding-right: 35px; + color: var(--color-white); + border-radius: 5px; + user-select: none; + display: flex; + align-items: center; +} +.menu-hor-item:hover { + background-color: var(--color-white10); + cursor: pointer; +} + +//標題 +.menu-hor-title { + padding: 5px 5px; + //padding-left: 30px; + padding-right: 33px; + color: var(--color-blue); + user-select: none; +} +//文字框 +.menu-text { + height: 33px; + color: var(--color-blue); + border: none; + outline: none; + background-color: rgba(0, 0, 0, 0); + width: 100%; + user-select: all; +} + +/*圖示*/ +.menu-hor-icon { + width: 25px; + height: 25px; + flex-shrink: 0; + //margin-left: 3px; + margin-right: 4px; + display: flex; + align-items: center; +} +.menu-hor-icon svg { + max-width: 25px; + max-height: 25px; +} +.menu-hor-icon img { + max-width: 25px; + max-height: 25px; +} +/*文字*/ +.menu-hor-txt { + line-height: 25px; + /*寬度不足時出現「...」*/ + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +/*水平線*/ +.menu-hor-hr { + height: 1px; + background-color: var(--color-white10); + margin: 5px 0; +} + +/*滾動條樣式*/ +.menu-content::-webkit-scrollbar { + background-color: var(--color-black60); + width: 10px; +} + +.menu-content::-webkit-scrollbar-track { + background-color: rgba(0, 0, 0, 0); +} + +.menu-content::-webkit-scrollbar-thumb { + background-color: var(--color-white40); + //產生透明框線並且剪裁掉 + border: 3px solid rgba(0, 0, 0, 0); + background-clip: content-box; +} + +#menu-bulkView { + min-width: 200px; + user-select: none; + + .menu-bulkView-box { + margin-bottom: 10px; + } + .menu-bulkView-title { + color: var(--color-white); + } + .menu-bulkView-select { + background-color: rgba(0, 0, 0, 0); + color: var(--color-white); + min-height: 35px; + border: 1px solid var(--color-white40); + border-radius: 5px; + padding: 0 5px; + width: 100%; + cursor: pointer; + } + + .menu-bulkView-checkbox { + cursor: pointer; + display: flex; + align-items: center; + height: 24px; + } + .menu-bulkView-checkbox:hover { + background-color: var(--color-white10); + } + .menu-bulkView-checkbox span { + color: var(--color-white); + } +} + +//--------- + +// 大量瀏覽模式的 每行圖片數 +.menu-bulkView-columns { + display: flex; + border-radius: 5px; + border: 1px solid var(--color-white40); + overflow: hidden; + min-width: 220px; +} +.menu-bulkView-columns-item { + flex: 1; + height: 35px; + color: var(--color-white); + display: flex; + align-items: center; + justify-content: center; + border-right: 1px solid var(--color-white40); + cursor: pointer; +} +.menu-bulkView-columns-item:hover { + background-color: var(--color-white10); +} +.menu-bulkView-columns-item:last-child { + border-right: none; +} +.menu-bulkView-columns-item[active="true"] { + // outline: 1px solid var(--color-blue); + background-color: var(--color-white20); +} diff --git a/Www/scss/_Msgbox.scss b/Www/scss/_Msgbox.scss new file mode 100644 index 00000000..5b7f063a --- /dev/null +++ b/Www/scss/_Msgbox.scss @@ -0,0 +1,155 @@ +.msgbox { + position: fixed; + top: 30px; + left: 0; + right: 0; + bottom: 0; + display: flex; + align-items: center; + justify-content: center; + z-index: 99; + padding-bottom: 30px; +} +@media screen and (max-width: 300px) { + .msgbox-box { + min-width: 100% !important; + } +} +.msgbox-box { + min-width: 300px; + max-width: 500px; + margin: 10px; + border-radius: 8px; + background-color: var(--color-black80); + box-shadow: 0px 0px 3px var(--color-blue40); + border: 1px solid var(--color-blue40); + backdrop-filter: saturate(180%) blur(20px); + display: flex; + flex-direction: column; + color: var(--color-white); + overflow: hidden; + position: relative; + + /*用於顯示時的動畫*/ + transition: all 0.1s; + transition-timing-function: cubic-bezier(0.6, 0.3, 0.33, 1.67); + opacity: 0.8; + transform: scaleY(1.05) translateY(0px); +} +.msgbox-box[active="true"] { + opacity: 1; + transform: scaleY(1) translateY(0px); +} + +.msgbox-txt { + //display: flex; + /* align-items: center; */ + margin: 40px; + flex: 1; + overflow-x: hidden; + overflow-y: auto; + max-height: 100px; +} + +/*文字輸入框*/ +.msgbox-input { + background-color: rgba(0, 0, 0, 0); + color: var(--color-white); + min-height: 35px; + border: 1px solid var(--color-white40); + border-radius: 5px; + padding: 0 5px; + /* width: 100%; */ + display: block; + margin-left: 40px; + margin-right: 40px; + margin-bottom: 20px; + flex: 1; +} + +.msgbox-bottom { + display: flex; + justify-content: center; + margin: 0px 10px 20px 10px; +} + +//按鈕 +.msgbox-btn { + min-width: 80px; + height: 35px; + padding: 0 10px; + margin: 0px 10px; + display: inline-flex; + align-items: center; + justify-content: center; + color: var(--color-white); + background-color: var(--color-white20); + border: none; + height: 35px; + border-radius: 5px; + user-select: none; +} +.msgbox-btn:hover { + background-color: var(--color-white30); + cursor: pointer; +} + +/*右上角的 X */ +.msgbox-close { + position: absolute; + width: 30px; + height: 30px; + display: flex; + align-items: center; + justify-content: center; + top: 0px; + right: 0px; +} + +.msgbox-close:hover { + background-color: var(--color-white10); + cursor: pointer; +} + +.msgbox-close::after { + content: ""; + height: 15px; + width: 2px; + background-color: var(--color-blue); + position: absolute; + transform: rotate(45deg); +} + +.msgbox-close::before { + content: ""; + height: 2px; + width: 15px; + background-color: var(--color-blue); + position: absolute; + transform: rotate(45deg); +} + +/* radio */ +.msgbox-radioList { + margin-bottom: 20px; + margin-left: 30px; + margin-right: 30px; +} + +.msgbox-radio { + min-height: 30px; + display: flex; + align-items: center; + padding-left: 3px; + border-radius: 5px; +} +.msgbox-radio:hover { + cursor: pointer; + background-color: var(--color-white10); +} + +//標題 +.msgbox-title { + font-size: 20px; + margin-bottom: 8px; +} diff --git a/Www/scss/_Tiefseeview.scss b/Www/scss/_Tiefseeview.scss new file mode 100644 index 00000000..b606e831 --- /dev/null +++ b/Www/scss/_Tiefseeview.scss @@ -0,0 +1,231 @@ +.tiefseeview { + overflow: hidden; + position: relative; + + // 用於縮放 dpi + .tiefseeview-dpizoom { + position: relative; + top: 0; + left: 0; + right: 0; + bottom: 0; + width: 100%; + height: 100%; + zoom: 1; + } + + // 實際佔位,用於設定 left、top + .tiefseeview-container { + pointer-events: none; + position: absolute; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + } + + // 放圖片的容器,用於套用旋轉 + .tiefseeview-data { + // 縮放是以圖片寬度為基準 + // width: 100%; + } + + // 圖片 + .view-img { + // width: 100%; + // height: 100%; + } + .view-bigimg { + position: relative; + } + .view-bigimg-canvas { + position: absolute; + } + .view-bigimg-bg { + position: absolute; + left: 0; + top: 0; + } + + .tiefseeview-loading { + background-position: center center; + background-size: 200px; + // background-size:100%; + z-index: 100; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-repeat: no-repeat; + } +} + +// -------- + +// 垂直滾動條 +.tiefseeview .scroll-y { + width: 20px; + position: absolute; + right: 0px; + top: 0px; + bottom: 0px; + z-index: 5; + + // 背景 + .scroll-bg { + height: 100%; + width: 10px; + background-color: var(--color-black60); + position: absolute; + // margin: auto; + // left: 0; + right: 0; + top: 0; + bottom: 0; + opacity: 0; + } + + // 拖曳區域 + .scroll-box { + width: 10px; + background-color: var(--color-white40); + position: absolute; + // margin: auto; + // left: 0; + right: 0; + // box-shadow: 0px 0px 3px 1px var(--color-black10); + // transform: scaleX(0.4); + border: 3px solid rgba(0, 0, 0, 0); + background-clip: content-box; + } + + &:hover { + cursor: pointer; + } + + // 移入與拖曳時-背景 + &:hover .scroll-bg, + &[action="true"] .scroll-bg { + opacity: 1; + backdrop-filter: saturate(180%) blur(20px); + } + + // 移入與拖曳時-拖曳區域 + &:hover .scroll-box, + &[action="true"] .scroll-box { + // background-color: rgba(255, 255, 255, 0.8); + // transform: scaleX(1); + } +} + +// -------- + +// 水平滾動條 +.tiefseeview .scroll-x { + height: 20px; + position: absolute; + right: 0px; + left: 0px; + bottom: 0px; + z-index: 5; + + // 背景 + .scroll-bg { + height: 10px; + width: 100%; + background-color: var(--color-black60); + position: absolute; + margin: auto; + left: 0; + right: 0; + // top: 0; + bottom: 0; + opacity: 0; + } + + // 拖曳區域 + .scroll-box { + height: 10px; + background-color: var(--color-white40); + position: absolute; + // top: 0; + bottom: 0px; + // margin: auto 0; + // box-shadow: 0px 0px 3px 1px var(--color-black10); + // transform: scaleY(0.4); + border: 3px solid rgba(0, 0, 0, 0); + background-clip: content-box; + } + + &:hover { + cursor: pointer; + } + + // 移入與拖曳時-背景 + &:hover .scroll-bg, + &[action="true"] .scroll-bg { + opacity: 1; + backdrop-filter: saturate(180%) blur(20px); + } + + // 移入與拖曳時-拖曳區域 + &:hover .scroll-box, + &[action="true"] .scroll-box { + // background-color: rgba(255, 255, 255, 0.8); + // transform: scaleY(1); + } +} + +// -------- + +// 剪裁 +.tiefseeview { + // 拖曳點 + .tiefseeview-clip { + position: absolute; + overflow: hidden; + top: 0; + left: 0; + right: 0; + bottom: 0; + width: 20px; + height: 20px; + border-radius: 50%; + z-index: 3; + background-color: #fff; + box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.5); + } + // 左上角 + .tiefseeview-clip-lt { + cursor: nw-resize; + } + // 右上角 + .tiefseeview-clip-rt { + cursor: ne-resize; + } + // 左下角 + .tiefseeview-clip-lb { + cursor: sw-resize; + } + // 右下角 + .tiefseeview-clip-rb { + cursor: se-resize; + } + // 中間的拖曳區塊 + .tiefseeview-clip-c { + cursor: move; + position: absolute; + z-index: 1; + } + // 周圍的半透明黑色區塊 + .tiefseeview-clip-svg { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 2; + pointer-events: none; + } +} diff --git a/Www/scss/_Toast.scss b/Www/scss/_Toast.scss new file mode 100644 index 00000000..27cc2636 --- /dev/null +++ b/Www/scss/_Toast.scss @@ -0,0 +1,94 @@ +.toastList { + position: fixed; + bottom: 0; + right: 0; + max-height: 50vh; + overflow-y: auto; + display: flex; + flex-direction: column; + align-items: flex-end; + z-index: 999; + + @keyframes toastStart { + from { + transform: translateY(-5px); + } + + to { + transform: translateY(0px); + } + } + + .toastItem { + border-radius: 8px; + background-color: var(--color-black80); + box-shadow: 0px 0px 3px var(--color-blue40); + border: 1px solid var(--color-blue40); + backdrop-filter: saturate(180%) blur(20px); + + display: flex; + margin-top: 10px; + margin-left: 10px; + margin-right: 10px; + overflow: hidden; + flex-shrink: 0; + + //動畫 + animation-name: toastStart; + animation-iteration-count: 1; + animation-duration: 0.15s; + animation-timing-function: ease-out; + } + + .toastItem:last-child { + margin-bottom: 10px; + } + + .toastText { + padding: 12px; + flex: 1; + max-width: 300px; + color: var(--color-white); + font-size: 15px; + } + + //關閉按鈕 + .toastClose { + width: 23px; + // height: 23px; + position: relative; + cursor: pointer; + } + + .toastClose:hover { + background-color: var(--color-white30); + } + + .toastClose::before { + background-color: var(--color-blue); + position: absolute; + content: ""; + height: 1px; + width: 14px; + top: 0; + left: 0; + right: 0; + bottom: 0; + margin: auto; + transform: rotate(45deg); + } + + .toastClose::after { + background-color: var(--color-blue); + position: absolute; + content: ""; + height: 14px; + width: 1px; + top: 0; + left: 0; + right: 0; + bottom: 0; + margin: auto; + transform: rotate(45deg); + } +} diff --git a/Www/ts/BaseWindow.ts b/Www/ts/BaseWindow.ts index 8d6b91fe..2f290224 100644 --- a/Www/ts/BaseWindow.ts +++ b/Www/ts/BaseWindow.ts @@ -1,21 +1,42 @@ -declare const chrome: any; -const WV2 = chrome.webview.hostObjects; -const WV_Window: WV_Window = WV2.WV_Window; -const WV_Directory: WV_Directory = WV2.WV_Directory; -const WV_File: WV_File = WV2.WV_File; -const WV_Path: WV_Path = WV2.WV_Path; -const WV_System: WV_System = WV2.WV_System; -const WV_RunApp: WV_RunApp = WV2.WV_RunApp; -const WV_Image: WV_Image = WV2.WV_Image; -const PORT = location.hash.replace("#", ""); -const APIURL = "http://127.0.0.1:" + PORT; // api 網址 -var _dropPath: string[] | undefined = undefined; // 暫存。取得拖曳進視窗的檔案路徑 - -interface Window { +import { Lib } from "./Lib"; +import { Throttle } from "./Throttle"; + +declare global { + + var chrome: any; + var WV_Window: WV_Window; + var WV_Directory: WV_Directory; + var WV_File: WV_File; + var WV_Path: WV_Path; + var WV_System: WV_System; + var WV_RunApp: WV_RunApp; + var WV_Image: WV_Image; + + var PORT: string; + var APIURL: string; + + var _dropPath: string[] | undefined; + /** 網頁的縮放比例,預設值 1.0 */ - zoomFactor: number; + var zoomFactor: number; + + var baseWindow: BaseWindow; } +const WV2 = chrome.webview.hostObjects; +window.WV_Window = WV2.WV_Window; +window.WV_Directory = WV2.WV_Directory; +window.WV_File = WV2.WV_File; +window.WV_Path = WV2.WV_Path; +window.WV_System = WV2.WV_System; +window.WV_RunApp = WV2.WV_RunApp; +window.WV_Image = WV2.WV_Image; +window.PORT = location.hash.replace("#", ""); +window.APIURL = "http://127.0.0.1:" + PORT; // api 網址 + +window._dropPath = undefined; + + class BaseWindow { public domWindow: HTMLDivElement; @@ -57,19 +78,6 @@ class BaseWindow { this.btnClose = _btnClose; this.domTitlebarText = _domTitlebarText; - /*// 判斷作業系統類型 - //@ts-ignore - navigator.userAgentData.getHighEntropyValues(["platformVersion"]).then(ua => { - //@ts-ignore - if (navigator.userAgentData.platform === "Windows") { - const majorPlatformVersion = parseInt(ua.platformVersion.split('.')[0]); - if (majorPlatformVersion >= 13) { - console.log("Windows 11 or later"); - dom_window.setAttribute("os","win11"); - } - } - });*/ - (async () => { // 判斷目前的狀態是視窗化還是最大化 this.windowState = await WV_Window.WindowState; @@ -124,6 +132,7 @@ class BaseWindow { windowBorder(document.querySelector(".window-RB"), "RB"); // 右下 // windowBorder(document.querySelector(".window-titlebar .titlebar-text"), "move"); + function windowBorder(dom: HTMLDivElement, type: ("CT" | "RC" | "CB" | "LC" | "LT" | "RT" | "LB" | "RB" | "move")) { dom.addEventListener("mousedown", async (e) => { if (e.button === 0) { // 滑鼠左鍵 @@ -143,6 +152,10 @@ class BaseWindow { } } + public static init() { + window.baseWindow = new BaseWindow(); + } + /** * 取得拖曳進來的檔案路徑 */ @@ -218,11 +231,11 @@ class BaseWindow { if (type === "none") { await WV_Window.WindowRoundedCorners(false); - this.domWindow.classList.remove("windowRoundedCorners"); + this.domWindow?.classList.remove("windowRoundedCorners"); } else { await WV_Window.WindowRoundedCorners(true); - this.domWindow.classList.add("windowRoundedCorners"); + this.domWindow?.classList.add("windowRoundedCorners"); } await WV_Window.WindowStyle(type); @@ -237,11 +250,11 @@ class BaseWindow { /** 視窗化或最大化時,標題列右邊的按鈕 */ private updateWindowState() { if (this.windowState === "Maximized") { - this.domWindow.classList.add("maximized"); + this.domWindow?.classList.add("maximized"); this.btnNormal.style.display = "flex"; this.btnMaximized.style.display = "none"; } else { - this.domWindow.classList.remove("maximized"); + this.domWindow?.classList.remove("maximized"); this.btnNormal.style.display = "none"; this.btnMaximized.style.display = "flex"; } @@ -443,3 +456,6 @@ class TouchDrop { } } + + +export { BaseWindow }; \ No newline at end of file diff --git a/Www/ts/Config.ts b/Www/ts/Config.ts index 00d216bc..3bc64320 100644 --- a/Www/ts/Config.ts +++ b/Www/ts/Config.ts @@ -1,4 +1,6 @@ -class Config { +import { BaseWindow } from "./BaseWindow"; + +export class Config { private baseWindow: BaseWindow; @@ -628,7 +630,7 @@ class Config { } } -const GroupType = { +export const GroupType = { /** 起始畫面 */ welcome: "welcome", diff --git a/Www/ts/DateExtensions.ts b/Www/ts/DateExtensions.ts new file mode 100644 index 00000000..a0299ef7 --- /dev/null +++ b/Www/ts/DateExtensions.ts @@ -0,0 +1,32 @@ +/** + * 對 Date 的擴充套件,將 Date 轉化為指定格式的String + * 月(M)、日(d)、小時(h)、分(m)、秒(s)、季度(q) 可以用 1-2 個佔位符, + * 年(y)可以用 1-4 個佔位符,毫秒(S)只能用 1 個佔位符(是 1-3 位的數字) + * 例子: + * (new Date()).format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423 + * (new Date()).format("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18 + */ +Date.prototype.format = function (this: Date, format: string): string { + const o: { [key: string]: number } = { + "M+": this.getMonth() + 1, // month + "d+": this.getDate(), // day + "h+": this.getHours(), // hour + "m+": this.getMinutes(), // minute + "s+": this.getSeconds(), // second + "q+": Math.floor((this.getMonth() + 3) / 3), // quarter + "S": this.getMilliseconds() // millisecond + } + + format = format.replace(/(y+)/, (match) => { + return (this.getFullYear() + "").substring(4 - match.length); + }); + for (const k in o) { + format = format.replace(new RegExp("(" + k + ")"), (match) => { + return match.length == 1 ? o[k].toString() : ("00" + o[k]).substring(("" + o[k]).length); + }); + } + return format; +} +interface Date { + format(format: string): string; +} diff --git a/Www/ts/I18n.ts b/Www/ts/I18n.ts index 64b1786f..8d52fd9b 100644 --- a/Www/ts/I18n.ts +++ b/Www/ts/I18n.ts @@ -1,4 +1,4 @@ -class I18n { +export class I18n { public getData; // 取得 翻譯json public setData; // 設定 翻譯json diff --git a/Www/ts/Lib.ts b/Www/ts/Lib.ts index 0accb705..0394f896 100644 --- a/Www/ts/Lib.ts +++ b/Www/ts/Lib.ts @@ -1,4 +1,4 @@ -class Lib { +export class Lib { /** * 取得資料夾路徑 @@ -730,187 +730,3 @@ class Lib { } } - -/** - * 對Date的擴充套件,將 Date 轉化為指定格式的String - * 月(M)、日(d)、小時(h)、分(m)、秒(s)、季度(q) 可以用 1-2 個佔位符, - * 年(y)可以用 1-4 個佔位符,毫秒(S)只能用 1 個佔位符(是 1-3 位的數字) - * 例子: - * (new Date()).format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423 - * (new Date()).format("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18 - */ -Date.prototype.format = function (this: Date, format: string): string { - const o: { [key: string]: number } = { - "M+": this.getMonth() + 1, // month - "d+": this.getDate(), // day - "h+": this.getHours(), // hour - "m+": this.getMinutes(), // minute - "s+": this.getSeconds(), // second - "q+": Math.floor((this.getMonth() + 3) / 3), // quarter - "S": this.getMilliseconds() // millisecond - } - - format = format.replace(/(y+)/, (match) => { - return (this.getFullYear() + "").substring(4 - match.length); - }); - for (const k in o) { - format = format.replace(new RegExp("(" + k + ")"), (match) => { - return match.length == 1 ? o[k].toString() : ("00" + o[k]).substring(("" + o[k]).length); - }); - } - return format; -} -interface Date { - format(format: string): string; -} - -/** - * 節流 (定時執行,時間內重複執行,則只會執行最後一個指令) - */ -class Throttle { - public run: (() => Promise) | undefined = undefined; - - constructor(timeout = 50) { - - let isAsyncTaskRunning = false; - - setInterval(() => { - - if (this.run === undefined) { return; } - if (isAsyncTaskRunning) { return; } - - let func = this.run; - this.run = undefined; - isAsyncTaskRunning = true; - - func().then(() => { - isAsyncTaskRunning = false; - }).catch(() => { - console.error(); - isAsyncTaskRunning = false; - }); - - }, timeout); - } -} - -/** - * 限制最大同時連線數。Chrome最大連線數為6 - */ -class RequestLimiter { - private queue: [HTMLImageElement, string][]; - private inProgress: number; // 目前正在進行的請求數 - private maxRequests: number; - - constructor(maxRequests: number) { - this.queue = []; - this.inProgress = 0; - this.maxRequests = Math.min(maxRequests, 6); // 設置上限 - } - - public addRequest(img: HTMLImageElement, url: string) { - - // 檢查 img 元素是否仍然存在於文檔中 - if (!document.body.contains(img)) { - return; - } - - // 檢查佇列中是否已經存在相同的 img 元素和網址 - const index = this.queue.findIndex(([i, u]) => i === img && u === url); - if (index !== -1) { // 如果存在,則忽略這個請求 - return; - } - - // 檢查佇列中是否存在相同的 img 元素但不同的網址 - const index2 = this.queue.findIndex(([i, u]) => i === img && u !== url); - if (index2 !== -1) { // 如果存在,則將舊的請求從佇列中移除 - this.queue.splice(index2, 1); - } - - // 添加新的請求 - this.queue.push([img, url]); - this.processQueue(); - } - - private processQueue() { - while (this.inProgress < this.maxRequests && this.queue.length > 0) { - const [img, url] = this.queue.shift()!; - this.inProgress++; // 圖片開始加載時增加 inProgress - this.loadImage(img, url).then(() => { - this.inProgress--; - this.processQueue(); - }).catch((error) => { - // console.error(error); - this.inProgress--; // 當錯誤發生時,減少 inProgress 的值 - this.processQueue(); // 繼續處理隊列中的下一個請求 - }); - } - } - - private loadImage(img: HTMLImageElement, url: string) { - return new Promise((resolve, reject) => { - - // 如果圖片已經不存在 - let intervalTimer = setInterval(() => { - if (!document.body.contains(img)) { - // console.log("Image element has been removed from the document."); - clearInterval(intervalTimer); - clearTimeout(timeoutTimer); - reject("Image element has been removed from the document."); - } - }, 50); - - // 載入超時 - let timeoutTimer = setTimeout(() => { - clearInterval(intervalTimer); - reject("Loading image timed out."); - }, 30 * 1000); - - img.src = url; - img.onload = img.onerror = () => { - clearInterval(intervalTimer); - clearTimeout(timeoutTimer); - resolve(); - }; - }); - } -} - -/** - * 指定哪些元素允許被選取 - */ -class SelectionManager { - private mode: "whitelist" | "blacklist"; - private filter: string[] = []; - - constructor(mode: "whitelist" | "blacklist") { - this.mode = mode; - this.init(); - } - - private init() { - document.addEventListener("mousedown", (event: MouseEvent) => { - // 點擊的不是左鍵 - if (event.button !== 0) { - return; - } - - const target = event.target as Element; - // 如果點擊的是文字輸入框 - if (target instanceof HTMLInputElement || - target instanceof HTMLTextAreaElement || - target instanceof HTMLSelectElement - ) { - return; - } - const isMatch = this.filter.some(selector => target.matches(selector)); - if ((this.mode === "blacklist" && isMatch) || (this.mode === "whitelist" && !isMatch)) { - event.preventDefault(); - } - }); - } - - public add(selector: string) { - this.filter.push(selector); - } -} diff --git a/Www/ts/MainWindow/AiDrawingPrompt.ts b/Www/ts/MainWindow/AiDrawingPrompt.ts index 75b4e1ea..dbfd57aa 100644 --- a/Www/ts/MainWindow/AiDrawingPrompt.ts +++ b/Www/ts/MainWindow/AiDrawingPrompt.ts @@ -1,7 +1,9 @@ +import { Lib } from "../Lib"; + /** * 提取 AI 繪圖的 Prompt */ -class AiDrawingPrompt { +export class AiDrawingPrompt { /** * Automatic1111 (字串分割) @@ -67,11 +69,8 @@ class AiDrawingPrompt { } let jsonF = Lib.jsonStrFormat(text); if (jsonF.ok) { // 如果是json (例如 Hashes - if ("Civitai resources") { - text = CivitaiStringify(jsonF.json); - } else { - text = jsonF.jsonFormat; // 格式化json再顯示 - } + + text = CivitaiStringify(jsonF.json); } else { if (title === "Tiled Diffusion" && text.startsWith('{') && text.endsWith('}')) { //格式例如 {'Method': 'MultiDiffusion', 'Tile tile width': 96} diff --git a/Www/ts/MainWindow/BulkView.ts b/Www/ts/MainWindow/BulkView.ts index 06188caf..da2cb893 100644 --- a/Www/ts/MainWindow/BulkView.ts +++ b/Www/ts/MainWindow/BulkView.ts @@ -1,7 +1,14 @@ +import { Lib } from "../Lib"; +import { RequestLimiter } from "../RequestLimiter"; +import { Throttle } from "../Throttle"; +import { TiefseeScroll } from "../TiefseeScroll"; +import { WebAPI } from "../WebAPI"; +import { MainWindow } from "./MainWindow"; + /** * 大量瀏覽模式 */ -class BulkView { +export class BulkView { public visible; public load; @@ -250,12 +257,12 @@ class BulkView { _originBulkViewHeight = _domBulkViewContent.offsetHeight; _originBulkViewScrollTop = _domBulkView.scrollTop; - const columns = M.config.settings.bulkView.columns = Number.parseInt(getGroupRadioVal(_domColumns)); - const gaplessMode = M.config.settings.bulkView.gaplessMode = _domGaplessMode.value; - const fixedWidth = M.config.settings.bulkView.fixedWidth = _domFixedWidth.value; - const align = M.config.settings.bulkView.align = _domAlign.value; - const indentation = M.config.settings.bulkView.indentation = _domIndentation.value; - const waterfall = M.config.settings.bulkView.waterfall = _domWaterfall.value; + const columns = M.config.settings.bulkView.columns = Number.parseInt(getGroupRadioVal(_domColumns)); + const gaplessMode = M.config.settings.bulkView.gaplessMode = _domGaplessMode.value; + const fixedWidth = M.config.settings.bulkView.fixedWidth = _domFixedWidth.value; + const align = M.config.settings.bulkView.align = _domAlign.value; + const indentation = M.config.settings.bulkView.indentation = _domIndentation.value; + const waterfall = M.config.settings.bulkView.waterfall = _domWaterfall.value; _domBulkViewContent.setAttribute("waterfall", waterfall); _domBulkViewContent.setAttribute("columns", columns.toString()); diff --git a/Www/ts/MainWindow/DirSort.ts b/Www/ts/MainWindow/DirSort.ts index 90e12f80..eacf75d8 100644 --- a/Www/ts/MainWindow/DirSort.ts +++ b/Www/ts/MainWindow/DirSort.ts @@ -1,4 +1,8 @@ -class DirSort { +import { Lib } from "../Lib"; +import { WebAPI } from "../WebAPI"; +import { MainWindow } from "./MainWindow"; + +export class DirSort { // public getSortType; public readSortType; @@ -219,7 +223,7 @@ class DirSort { /** * 排序類型 */ -const DirSortType = { +export const DirSortType = { /** 檔名自然排序 */ name: "name", /** 檔名自然排序(逆) */ @@ -243,7 +247,7 @@ const DirSortType = { /** * 遞增或遞減 */ -const DirOrderbyType = { +export const DirOrderbyType = { desc: "desc", asc: "asc", } diff --git a/Www/ts/MainWindow/Dragbar.ts b/Www/ts/MainWindow/Dragbar.ts index c9a29c80..ff58a3cb 100644 --- a/Www/ts/MainWindow/Dragbar.ts +++ b/Www/ts/MainWindow/Dragbar.ts @@ -1,7 +1,9 @@ +import { Lib } from "../Lib"; + /** * 改變物件 size 的拖曳條 */ -class Dragbar { +export class Dragbar { public init; public getEventStart; diff --git a/Www/ts/MainWindow/FileLoad.ts b/Www/ts/MainWindow/FileLoad.ts index e5da3700..261a20f6 100644 --- a/Www/ts/MainWindow/FileLoad.ts +++ b/Www/ts/MainWindow/FileLoad.ts @@ -1,7 +1,14 @@ +import { GroupType } from "../Config"; +import { Lib } from "../Lib"; +import { Throttle } from "../Throttle"; +import { Toast } from "../Toast"; +import { WebAPI } from "../WebAPI"; +import { MainWindow } from "./MainWindow"; + /** * 載入檔案 */ -class FileLoad { +export class FileLoad { public getWaitingFile: () => string[]; public setWaitingFile: (ar: string[]) => void; diff --git a/Www/ts/MainWindow/FileShow.ts b/Www/ts/MainWindow/FileShow.ts index 501b9473..8c26b544 100644 --- a/Www/ts/MainWindow/FileShow.ts +++ b/Www/ts/MainWindow/FileShow.ts @@ -1,4 +1,11 @@ -class FileShow { +import { MainWindow } from "./MainWindow"; +import { Iframes } from "./Iframes"; +import { Tiefseeview, TiefseeviewAlignType, TiefseeviewZoomType } from "../Tiefseeview"; +import { GroupType } from "../Config"; +import { WebAPI } from "../WebAPI"; +import { Lib } from "../Lib"; + +export class FileShow { public openImage; public openVideo; diff --git a/Www/ts/MainWindow/FileSort.ts b/Www/ts/MainWindow/FileSort.ts index c50d8a3a..70ca26ec 100644 --- a/Www/ts/MainWindow/FileSort.ts +++ b/Www/ts/MainWindow/FileSort.ts @@ -1,4 +1,8 @@ -class FileSort { +import { Lib } from "../Lib"; +import { WebAPI } from "../WebAPI"; +import { MainWindow } from "./MainWindow"; + +export class FileSort { public readSortType; public updateMenu; @@ -216,7 +220,7 @@ class FileSort { /** * 排序類型 */ -const FileSortType = { +export const FileSortType = { /** 檔名自然排序 */ name: "name", @@ -254,7 +258,7 @@ const FileSortType = { /** * 遞增或遞減 */ -const FileOrderbyType = { +export const FileOrderbyType = { desc: "desc", asc: "asc", } diff --git a/Www/ts/MainWindow/FullScreen.ts b/Www/ts/MainWindow/FullScreen.ts new file mode 100644 index 00000000..5e8ea36d --- /dev/null +++ b/Www/ts/MainWindow/FullScreen.ts @@ -0,0 +1,90 @@ +import { MainWindow } from "./MainWindow"; + +/** + * 全螢幕 + */ +export class FullScreen { + + M: MainWindow; + + /** 是否啟用全螢幕 */ + private enabled = false; + /** 當前是否顯示標題列 */ + private showTitlebar = false; + /** 標題列 */ + private domTitleBar = document.querySelector("#window-titlebar") as HTMLDivElement; + /** 工具列 */ + private domMainT = document.querySelector("#main-T") as HTMLDivElement; + /** 標題列 - 離開全螢幕 */ + private btnExitFullScreen = document.querySelector(".titlebar-toolbar-exitFullScreen") as HTMLDivElement; + + /** 滑鼠移到視窗頂端時,顯示標題列與工具列 */ + private mousemoveEvent = (e: MouseEvent) => { + // if (this.M.menu.getIsShow()) { return; } + if (this.showTitlebar === false && e.clientY <= 5) { + this.showTitlebar = true; + document.body.setAttribute("showTitlebar", "true"); + } else if (this.showTitlebar === true && e.clientY < this.domTitleBar.offsetHeight + this.domMainT.offsetHeight + 10) { + this.showTitlebar = true; + document.body.setAttribute("showTitlebar", "true"); + } else { + this.showTitlebar = false; + document.body.setAttribute("showTitlebar", "false"); + } + }; + + /** 視窗化後就結束全螢幕 */ + private exitEvent = async () => { + if (this.getEnabled() === true && baseWindow.windowState !== "Maximized") { + this.setEnabled(false); + } + } + + /** + * + */ + constructor(M: MainWindow) { + this.M = M; + + // 結束全螢幕 + this.btnExitFullScreen.addEventListener("click", () => { + this.setEnabled(false); + }); + } + + /** + * 取得 是否啟用全螢幕 + */ + public getEnabled() { + return this.enabled; + } + + /** + * 啟用或關閉全螢幕 + * @param val + */ + public async setEnabled(val?: boolean) { + if (val === undefined) { + val = !this.enabled; + } + this.enabled = val; + this.M.menu.close(); + + await WV_Window.SetFullScreen(val); + + if (val) { + document.body.setAttribute("fullScreen", "true"); + document.addEventListener("mousemove", this.mousemoveEvent); + baseWindow.sizeChangeEvents.push(this.exitEvent); + } else { + document.body.setAttribute("fullScreen", "false"); + document.removeEventListener("mousemove", this.mousemoveEvent); + // 移除事件 + const index = baseWindow.sizeChangeEvents.indexOf(this.exitEvent); + if (index > -1) { + baseWindow.sizeChangeEvents.splice(index, 1); + } + } + + } +} diff --git a/Www/ts/MainWindow/Hotkey.ts b/Www/ts/MainWindow/Hotkey.ts index 434543ad..e294fcd3 100644 --- a/Www/ts/MainWindow/Hotkey.ts +++ b/Www/ts/MainWindow/Hotkey.ts @@ -1,7 +1,11 @@ +import { GroupType } from "../Config"; +import { Lib } from "../Lib"; +import { MainWindow } from "./MainWindow"; + /** * 快速鍵 */ -class Hotkey { +export class Hotkey { constructor(M: MainWindow) { diff --git a/Www/ts/MainWindow/Iframes.ts b/Www/ts/MainWindow/Iframes.ts index b239b6cc..f9a78c04 100644 --- a/Www/ts/MainWindow/Iframes.ts +++ b/Www/ts/MainWindow/Iframes.ts @@ -1,4 +1,9 @@ -class Iframes { +import { GroupType } from "../Config"; +import { Lib } from "../Lib"; +import { WebAPI } from "../WebAPI"; +import { MainWindow } from "./MainWindow"; + +export class Iframes { public monacoEditor; public pdfTronWebviewer; @@ -380,7 +385,6 @@ class MonacoEditor { } } - class CherryMarkdown { public visible; public loadFile; @@ -647,7 +651,6 @@ class Pdfview { } } - class Welcomeview { public visible; diff --git a/Www/ts/MainWindow/ImgSearch.ts b/Www/ts/MainWindow/ImgSearch.ts index d2e621c0..d94de2ba 100644 --- a/Www/ts/MainWindow/ImgSearch.ts +++ b/Www/ts/MainWindow/ImgSearch.ts @@ -1,4 +1,8 @@ -class ImgSearch { +import { Lib } from "../Lib"; +import { WebAPI } from "../WebAPI"; +import { MainWindow } from "./MainWindow"; + +export class ImgSearch { constructor(M: MainWindow) { diff --git a/Www/ts/MainWindow/IndexedDBManager.ts b/Www/ts/MainWindow/IndexedDBManager.ts index 56f68451..e93a939a 100644 --- a/Www/ts/MainWindow/IndexedDBManager.ts +++ b/Www/ts/MainWindow/IndexedDBManager.ts @@ -1,14 +1,4 @@ -/** - * 資料表名稱 - */ -const DbStoreName = { - /** Civitai Resources 的暫存資料 */ - civitaiResources: "civitaiResources", - /** 詳細資訊面板內的項目折疊狀態 */ - infoPanelCollapse: "infoPanelCollapse", -} - -class IndexedDBManager { +export class IndexedDBManager { // 資料表名稱 private storeNames: string[] = Object.values(DbStoreName); @@ -79,3 +69,13 @@ class IndexedDBManager { objectStore.delete(id); } } + +/** + * 資料表名稱 + */ +export const DbStoreName = { + /** Civitai Resources 的暫存資料 */ + civitaiResources: "civitaiResources", + /** 詳細資訊面板內的項目折疊狀態 */ + infoPanelCollapse: "infoPanelCollapse", +} diff --git a/Www/ts/MainWindow/LargeBtn.ts b/Www/ts/MainWindow/LargeBtn.ts index 93a662dd..e1d36330 100644 --- a/Www/ts/MainWindow/LargeBtn.ts +++ b/Www/ts/MainWindow/LargeBtn.ts @@ -1,7 +1,9 @@ +import { MainWindow } from "./MainWindow"; + /** * 在下面或兩側的 大型切換按鈕 */ -class LargeBtn { +export class LargeBtn { public domLargeBtnLeft: HTMLElement; public domLargeBtnRight: HTMLElement; diff --git a/Www/ts/MainWindow/MainDirList.ts b/Www/ts/MainWindow/MainDirList.ts index f42ce8a1..e2045aef 100644 --- a/Www/ts/MainWindow/MainDirList.ts +++ b/Www/ts/MainWindow/MainDirList.ts @@ -1,7 +1,13 @@ +import { MainWindow } from "./MainWindow"; +import { Dragbar } from "./Dragbar"; +import { TiefseeScroll } from "../TiefseeScroll"; +import { WebAPI } from "../WebAPI"; +import { Lib } from "../Lib"; + /** * 資料夾預覽視窗 */ -class MainDirList { +export class MainDirList { public init; public select; diff --git a/Www/ts/MainWindow/MainExif.ts b/Www/ts/MainWindow/MainExif.ts index 443ca4bd..fedbba8e 100644 --- a/Www/ts/MainWindow/MainExif.ts +++ b/Www/ts/MainWindow/MainExif.ts @@ -1,4 +1,15 @@ -class MainExif { +import { MainWindow } from "./MainWindow"; +import { Dragbar } from "./Dragbar"; +import { AiDrawingPrompt } from "./AiDrawingPrompt"; +import { DbStoreName, IndexedDBManager } from "./IndexedDBManager"; +import { WebAPI } from "../WebAPI"; +import { GroupType } from "../Config"; +import { Toast } from "../Toast"; +import { TiefseeScroll } from "../TiefseeScroll"; +import { Lib } from "../Lib"; +import { RequestLimiter } from "../RequestLimiter"; + +export class MainExif { public init; public setEnabled; @@ -1578,206 +1589,3 @@ class MainExif { } } - - -class TextEditor { - - public show; - public close; - public save; - public getIsShow; - public getText; - public setText; - public setOnSave; - - constructor(M: MainWindow) { - const _dom = document.querySelector("#textEditor") as HTMLElement; - const _domTextarea = _dom?.querySelector(".textEditor-textarea") as HTMLTextAreaElement; - const _domBtnSave = _dom?.querySelector(".js-save") as HTMLElement; - const _domBtnPretty = _dom?.querySelector(".js-pretty") as HTMLElement; - const _domBtnClose = _dom?.querySelector(".js-close") as HTMLElement; - let _filePath = ""; - let _isShow = false; - let _onSave = (text: string) => { }; - - this.show = show; - this.close = close; - this.save = save; - this.getIsShow = getIsShow; - this.getText = getText; - this.setText = setText; - this.setOnSave = setOnSave; - - // 讓 Textarea 支援 tab - _domTextarea.addEventListener("keydown", function (e) { - - if (e.code === "Tab") { - // selection - if (this.selectionStart == this.selectionEnd) { - // These single character operations are undoable - if (!e.shiftKey) { - document.execCommand("insertText", false, "\t"); - } - else { - var text = this.value; - if (this.selectionStart > 0 && text[this.selectionStart - 1] == "\t") { - document.execCommand("delete"); - } - } - } - else { - // Block indent/unindent trashes undo stack. - // Select whole lines - let selStart = this.selectionStart; - let selEnd = this.selectionEnd; - let text = _domTextarea.value; - while (selStart > 0 && text[selStart - 1] != "\n") - selStart--; - while (selEnd > 0 && text[selEnd - 1] != "\n" && selEnd < text.length) - selEnd++; - - // Get selected text - let lines = text.substring(selStart, selEnd).split("\n"); - - // Insert tabs - for (let i = 0; i < lines.length; i++) { - // Don't indent last line if cursor at start of line - if (i == lines.length - 1 && lines[i].length == 0) - continue; - - // Tab or Shift+Tab? - if (e.shiftKey) { - if (lines[i].startsWith("\t")) - lines[i] = lines[i].substring(1); - else if (lines[i].startsWith(" ")) - lines[i] = lines[i].substring(4); - } - else - lines[i] = "\t" + lines[i]; - } - let linesJoin = lines.join("\n"); - - // Update the text area - this.value = text.substring(0, selStart) + linesJoin + text.substring(selEnd); - this.selectionStart = selStart; - this.selectionEnd = selStart + linesJoin.length; - } - - return false; - } - - return true; - }); - - _domBtnSave.addEventListener("click", async () => { - await save(); - }) - _domBtnPretty.addEventListener("click", () => { - let t = getText(); - try { - const j = JSON.parse(t); - t = JSON.stringify(j, null, "\t"); - setText(t); - } catch (e) { - Toast.show(M.i18n.t("msg.formattingFailed"), 1000 * 3); // 儲存完成 - } - }) - _domBtnClose.addEventListener("click", () => { - close(); - }) - - /** - * 取得目前是否顯示 - */ - function getIsShow() { - return _isShow; - } - - /** - * 顯示視窗 - * @param path 檔案路徑 - */ - async function show(path: string | null) { - - _isShow = true; - _dom.style.display = ""; - await Lib.sleep(1); - _dom.setAttribute("active", "true"); - - if (path === null) { path = "" } - _filePath = path; - let t = ""; - if (await WV_File.Exists(_filePath)) { - t = await WV_File.GetText(_filePath); - } - setText(t); - - // 設定焦點 - _domTextarea.focus(); - _domTextarea.setSelectionRange(0, 0); - - _domTextarea.scrollTop = 0; - - // 如果是json,就顯示 格式化 的按鈕 - if ( - Lib.getExtension(_filePath) === ".json" - || t.startsWith("{") - ) { - _domBtnPretty.style.display = ""; - } else { - _domBtnPretty.style.display = "none"; - } - } - - /** - * 關閉視窗 - */ - function close() { - _isShow = false; - _dom.setAttribute("active", "false"); - - setTimeout(() => { - if (_dom.getAttribute("active") == "false") { - _domTextarea.value = ""; - _dom.style.display = "none"; - } - }, 300); - } - - /** - * 設定 儲存後執行的回調 - */ - function setOnSave(funcSave: (text: string) => void) { - _onSave = funcSave; - } - - /** - * 儲存 - */ - async function save() { - let t = getText(); - try { - await WV_File.SetText(_filePath, t); - _onSave(t); - Toast.show(M.i18n.t("msg.saveComplete"), 1000 * 3); // 儲存完成 - } catch (e) { - Toast.show(M.i18n.t("msg.saveFailed") + ":\n" + e, 1000 * 3); // 儲存失敗 - } - } - - /** - * 取得 文字 - */ - function getText() { - return _domTextarea.value; - } - - /** - * 設定 文字 - */ - function setText(t: string) { - _domTextarea.value = t; - } - - } -} diff --git a/Www/ts/MainWindow/MainFileList.ts b/Www/ts/MainWindow/MainFileList.ts index 846fda53..608a132a 100644 --- a/Www/ts/MainWindow/MainFileList.ts +++ b/Www/ts/MainWindow/MainFileList.ts @@ -1,7 +1,13 @@ +import { MainWindow } from "./MainWindow"; +import { Dragbar } from "./Dragbar"; +import { TiefseeScroll } from "../TiefseeScroll"; +import { WebAPI } from "../WebAPI"; +import { Lib } from "../Lib"; + /** * 檔案預覽視窗 */ -class MainFileList { +export class MainFileList { public init; public select; diff --git a/Www/ts/MainWindow/MainMenu.ts b/Www/ts/MainWindow/MainMenu.ts index 06c8781f..06681057 100644 --- a/Www/ts/MainWindow/MainMenu.ts +++ b/Www/ts/MainWindow/MainMenu.ts @@ -1,4 +1,8 @@ -class MainMenu { +import { Lib } from "../Lib"; +import { WebAPI } from "../WebAPI"; +import { MainWindow } from "./MainWindow"; + +export class MainMenu { public updateRightMenuImageZoomRatioTxt; public updateMenuLayoutCheckState; diff --git a/Www/ts/MainWindow/MainToolbar.ts b/Www/ts/MainWindow/MainToolbar.ts index 2c5d9693..60bd1c03 100644 --- a/Www/ts/MainWindow/MainToolbar.ts +++ b/Www/ts/MainWindow/MainToolbar.ts @@ -1,4 +1,8 @@ -class MainToolbar { +import { GroupType } from "../Config"; +import { Lib } from "../Lib"; +import { MainWindow } from "./MainWindow"; + +export class MainToolbar { public setEnabled; public getArrray; diff --git a/Www/ts/MainWindow/MainWindow.ts b/Www/ts/MainWindow/MainWindow.ts index 0863aeb9..9fdfed5a 100644 --- a/Www/ts/MainWindow/MainWindow.ts +++ b/Www/ts/MainWindow/MainWindow.ts @@ -1,11 +1,43 @@ -var baseWindow: BaseWindow; +import { BaseWindow } from "../BaseWindow"; +import { IndexedDBManager } from "./IndexedDBManager"; +import { MainToolbar } from "./MainToolbar"; +import { FileLoad } from "./FileLoad"; +import { MainFileList } from "./MainFileList"; +import { MainDirList } from "./MainDirList"; +import { MainExif } from "./MainExif"; +import { FileShow } from "./FileShow"; +import { FileSort } from "./FileSort"; +import { DirSort } from "./DirSort"; +import { ImgSearch } from "./ImgSearch"; +import { MainMenu } from "./MainMenu"; +import { Menu } from "./Menu"; +import { LargeBtn } from "./LargeBtn"; +import { BulkView } from "./BulkView"; +import { Script } from "./Script"; +import { Hotkey } from "./Hotkey"; +import { TiefseeScroll } from "../TiefseeScroll"; +import { I18n } from "../I18n"; +import { WebAPI } from "../WebAPI"; +import { Config } from "../Config"; +import { Msgbox } from "../Msgbox"; +import { Toast } from "../Toast"; +import { Lib } from "../Lib"; +import { SelectionManager } from "../SelectionManager"; +import { FullScreen } from "./FullScreen"; +import { ToolbarBack } from "./ToolbarBack"; +import { TextEditor } from "./TextEditor"; +import "../DateExtensions"; + +declare global { + var mainWindow: MainWindow; +} -var mainWindow: MainWindow; document.addEventListener("DOMContentLoaded", async () => { - mainWindow = new MainWindow(); + BaseWindow.init(); + window.mainWindow = new MainWindow(); }); -class MainWindow { +export class MainWindow { public quickLookUp; @@ -43,7 +75,7 @@ class MainWindow { constructor() { - baseWindow = new BaseWindow(); // 初始化視窗 + //baseWindow = new BaseWindow(); // 初始化視窗 this.quickLookUp = quickLookUp; @@ -991,153 +1023,3 @@ class MainWindow { } } - -/** - * 頁面的返回按鈕 - */ -class ToolbarBack { - - public visible; - public getVisible; - public setEvent; - public runEvent; - - constructor() { - - const _btn = document.querySelector("#toolbar-back") as HTMLElement; - var _clickEvent: () => void = () => { } - var _active = false; - - this.visible = visible; - this.getVisible = getVisible; - this.setEvent = setEvent; - this.runEvent = runEvent; - - _btn.addEventListener("click", () => { - _clickEvent(); - }) - - /** - * 設定顯示或隱藏dom - */ - function visible(val: boolean) { - if (val === true) { - _btn.setAttribute("active", "true"); - _active = true; - } else { - _btn.setAttribute("active", ""); - _active = false; - } - } - - function getVisible() { - return _active; - } - - /** - * 設定新的click事件 - * @param func - */ - function setEvent(func: () => void) { - _clickEvent = func; - } - - /** - * 執行click事件 - */ - function runEvent() { - _clickEvent(); - } - - } -} - - -/** - * 全螢幕 - */ -class FullScreen { - - M: MainWindow; - - /** 是否啟用全螢幕 */ - private enabled = false; - /** 當前是否顯示標題列 */ - private showTitlebar = false; - /** 標題列 */ - private domTitleBar = document.querySelector("#window-titlebar") as HTMLDivElement; - /** 工具列 */ - private domMainT = document.querySelector("#main-T") as HTMLDivElement; - /** 標題列 - 離開全螢幕 */ - private btnExitFullScreen = document.querySelector(".titlebar-toolbar-exitFullScreen") as HTMLDivElement; - - /** 滑鼠移到視窗頂端時,顯示標題列與工具列 */ - private mousemoveEvent = (e: MouseEvent) => { - // if (this.M.menu.getIsShow()) { return; } - if (this.showTitlebar === false && e.clientY <= 5) { - this.showTitlebar = true; - document.body.setAttribute("showTitlebar", "true"); - } else if (this.showTitlebar === true && e.clientY < this.domTitleBar.offsetHeight + this.domMainT.offsetHeight + 10) { - this.showTitlebar = true; - document.body.setAttribute("showTitlebar", "true"); - } else { - this.showTitlebar = false; - document.body.setAttribute("showTitlebar", "false"); - } - }; - - /** 視窗化後就結束全螢幕 */ - private exitEvent = async () => { - if (this.getEnabled() === true && baseWindow.windowState !== "Maximized") { - this.setEnabled(false); - } - } - - /** - * - */ - constructor(M: MainWindow) { - this.M = M; - - // 結束全螢幕 - this.btnExitFullScreen.addEventListener("click", () => { - this.setEnabled(false); - }); - } - - /** - * 取得 是否啟用全螢幕 - */ - public getEnabled() { - return this.enabled; - } - - /** - * 啟用或關閉全螢幕 - * @param val - */ - public async setEnabled(val?: boolean) { - if (val === undefined) { - val = !this.enabled; - } - this.enabled = val; - this.M.menu.close(); - - await WV_Window.SetFullScreen(val); - - if (val) { - document.body.setAttribute("fullScreen", "true"); - document.addEventListener("mousemove", this.mousemoveEvent); - baseWindow.sizeChangeEvents.push(this.exitEvent); - } else { - document.body.setAttribute("fullScreen", "false"); - document.removeEventListener("mousemove", this.mousemoveEvent); - // 移除事件 - const index = baseWindow.sizeChangeEvents.indexOf(this.exitEvent); - if (index > -1) { - baseWindow.sizeChangeEvents.splice(index, 1); - } - } - - } -} diff --git a/Www/ts/MainWindow/Menu.ts b/Www/ts/MainWindow/Menu.ts index 148f64ea..e2dabd4e 100644 --- a/Www/ts/MainWindow/Menu.ts +++ b/Www/ts/MainWindow/Menu.ts @@ -1,4 +1,7 @@ -class Menu { +import { Lib } from "../Lib"; +import { MainWindow } from "./MainWindow"; + +export class Menu { public openAtButton; public openAtMouse; diff --git a/Www/ts/MainWindow/Script.ts b/Www/ts/MainWindow/Script.ts index 2ce58097..a343aa90 100644 --- a/Www/ts/MainWindow/Script.ts +++ b/Www/ts/MainWindow/Script.ts @@ -1,4 +1,11 @@ -class Script { +import { GroupType } from "../Config"; +import { Lib } from "../Lib"; +import { TiefseeviewZoomType } from "../Tiefseeview"; +import { Toast } from "../Toast"; +import { WebAPI } from "../WebAPI"; +import { MainWindow } from "./MainWindow"; + +export class Script { private M: MainWindow; public img: ScriptImg; @@ -241,8 +248,7 @@ class Script { } } - -class ScriptImg { +export class ScriptImg { M: MainWindow; constructor(_M: MainWindow) { this.M = _M; @@ -583,7 +589,7 @@ class ScriptImg { } -class ScriptFileLoad { +export class ScriptFileLoad { M: MainWindow; constructor(_M: MainWindow) { this.M = _M; @@ -692,14 +698,14 @@ class ScriptFileLoad { } -class ScriptFileShow { +export class ScriptFileShow { M: MainWindow; constructor(_M: MainWindow) { this.M = _M; } } -class ScriptFile { +export class ScriptFile { M: MainWindow; constructor(_M: MainWindow) { this.M = _M; @@ -752,7 +758,7 @@ class ScriptFile { } } -class ScriptMenu { +export class ScriptMenu { M: MainWindow; constructor(_M: MainWindow) { this.M = _M; @@ -1100,8 +1106,7 @@ class ScriptMenu { } - -class ScriptOpen { +export class ScriptOpen { M: MainWindow; constructor(_M: MainWindow) { this.M = _M; @@ -1161,7 +1166,7 @@ class ScriptOpen { let src = arSrc[i]; let base64; if (src.startsWith("file://")) { - const url = WebAPI.getFile(Lib.urlToPath(src)) + const url = WebAPI.getFile(Lib.urlToPath(src)) let file = await this.M.downloadFileFromUrl(url); if (file != null) { base64 = await Lib.readFileAsDataURL(file); @@ -1326,8 +1331,7 @@ class ScriptOpen { } - -class ScriptCopy { +export class ScriptCopy { M: MainWindow; constructor(_M: MainWindow) { @@ -1534,8 +1538,7 @@ class ScriptCopy { } } - -class ScriptSetting { +export class ScriptSetting { M: MainWindow; constructor(_M: MainWindow) { @@ -1573,8 +1576,7 @@ class ScriptSetting { } } - -class ScriptWindow { +export class ScriptWindow { domLoading = document.querySelector("#loadingWindow") as HTMLElement; btnTopmost = document.querySelector("#menu-layout .js-topmost") as HTMLElement; @@ -1670,8 +1672,7 @@ class ScriptWindow { } } - -class ScriptBulkView { +export class ScriptBulkView { M: MainWindow; constructor(_M: MainWindow) { diff --git a/Www/ts/MainWindow/TextEditor.ts b/Www/ts/MainWindow/TextEditor.ts new file mode 100644 index 00000000..3163f879 --- /dev/null +++ b/Www/ts/MainWindow/TextEditor.ts @@ -0,0 +1,205 @@ +import { Lib } from "../Lib"; +import { Toast } from "../Toast"; +import { MainWindow } from "./MainWindow"; + +export class TextEditor { + + public show; + public close; + public save; + public getIsShow; + public getText; + public setText; + public setOnSave; + + constructor(M: MainWindow) { + const _dom = document.querySelector("#textEditor") as HTMLElement; + const _domTextarea = _dom?.querySelector(".textEditor-textarea") as HTMLTextAreaElement; + const _domBtnSave = _dom?.querySelector(".js-save") as HTMLElement; + const _domBtnPretty = _dom?.querySelector(".js-pretty") as HTMLElement; + const _domBtnClose = _dom?.querySelector(".js-close") as HTMLElement; + let _filePath = ""; + let _isShow = false; + let _onSave = (text: string) => { }; + + this.show = show; + this.close = close; + this.save = save; + this.getIsShow = getIsShow; + this.getText = getText; + this.setText = setText; + this.setOnSave = setOnSave; + + // 讓 Textarea 支援 tab + _domTextarea.addEventListener("keydown", function (e) { + + if (e.code === "Tab") { + // selection + if (this.selectionStart == this.selectionEnd) { + // These single character operations are undoable + if (!e.shiftKey) { + document.execCommand("insertText", false, "\t"); + } + else { + var text = this.value; + if (this.selectionStart > 0 && text[this.selectionStart - 1] == "\t") { + document.execCommand("delete"); + } + } + } + else { + // Block indent/unindent trashes undo stack. + // Select whole lines + let selStart = this.selectionStart; + let selEnd = this.selectionEnd; + let text = _domTextarea.value; + while (selStart > 0 && text[selStart - 1] != "\n") + selStart--; + while (selEnd > 0 && text[selEnd - 1] != "\n" && selEnd < text.length) + selEnd++; + + // Get selected text + let lines = text.substring(selStart, selEnd).split("\n"); + + // Insert tabs + for (let i = 0; i < lines.length; i++) { + // Don't indent last line if cursor at start of line + if (i == lines.length - 1 && lines[i].length == 0) + continue; + + // Tab or Shift+Tab? + if (e.shiftKey) { + if (lines[i].startsWith("\t")) + lines[i] = lines[i].substring(1); + else if (lines[i].startsWith(" ")) + lines[i] = lines[i].substring(4); + } + else + lines[i] = "\t" + lines[i]; + } + let linesJoin = lines.join("\n"); + + // Update the text area + this.value = text.substring(0, selStart) + linesJoin + text.substring(selEnd); + this.selectionStart = selStart; + this.selectionEnd = selStart + linesJoin.length; + } + + return false; + } + + return true; + }); + + _domBtnSave.addEventListener("click", async () => { + await save(); + }) + _domBtnPretty.addEventListener("click", () => { + let t = getText(); + try { + const j = JSON.parse(t); + t = JSON.stringify(j, null, "\t"); + setText(t); + } catch (e) { + Toast.show(M.i18n.t("msg.formattingFailed"), 1000 * 3); // 儲存完成 + } + }) + _domBtnClose.addEventListener("click", () => { + close(); + }) + + /** + * 取得目前是否顯示 + */ + function getIsShow() { + return _isShow; + } + + /** + * 顯示視窗 + * @param path 檔案路徑 + */ + async function show(path: string | null) { + + _isShow = true; + _dom.style.display = ""; + await Lib.sleep(1); + _dom.setAttribute("active", "true"); + + if (path === null) { path = "" } + _filePath = path; + let t = ""; + if (await WV_File.Exists(_filePath)) { + t = await WV_File.GetText(_filePath); + } + setText(t); + + // 設定焦點 + _domTextarea.focus(); + _domTextarea.setSelectionRange(0, 0); + + _domTextarea.scrollTop = 0; + + // 如果是json,就顯示 格式化 的按鈕 + if ( + Lib.getExtension(_filePath) === ".json" + || t.startsWith("{") + ) { + _domBtnPretty.style.display = ""; + } else { + _domBtnPretty.style.display = "none"; + } + } + + /** + * 關閉視窗 + */ + function close() { + _isShow = false; + _dom.setAttribute("active", "false"); + + setTimeout(() => { + if (_dom.getAttribute("active") == "false") { + _domTextarea.value = ""; + _dom.style.display = "none"; + } + }, 300); + } + + /** + * 設定 儲存後執行的回調 + */ + function setOnSave(funcSave: (text: string) => void) { + _onSave = funcSave; + } + + /** + * 儲存 + */ + async function save() { + let t = getText(); + try { + await WV_File.SetText(_filePath, t); + _onSave(t); + Toast.show(M.i18n.t("msg.saveComplete"), 1000 * 3); // 儲存完成 + } catch (e) { + Toast.show(M.i18n.t("msg.saveFailed") + ":\n" + e, 1000 * 3); // 儲存失敗 + } + } + + /** + * 取得 文字 + */ + function getText() { + return _domTextarea.value; + } + + /** + * 設定 文字 + */ + function setText(t: string) { + _domTextarea.value = t; + } + + } +} diff --git a/Www/ts/MainWindow/ToolbarBack.ts b/Www/ts/MainWindow/ToolbarBack.ts new file mode 100644 index 00000000..7e915933 --- /dev/null +++ b/Www/ts/MainWindow/ToolbarBack.ts @@ -0,0 +1,59 @@ +/** + * 頁面的返回按鈕 + */ +export class ToolbarBack { + + public visible; + public getVisible; + public setEvent; + public runEvent; + + constructor() { + + const _btn = document.querySelector("#toolbar-back") as HTMLElement; + var _clickEvent: () => void = () => { } + var _active = false; + + this.visible = visible; + this.getVisible = getVisible; + this.setEvent = setEvent; + this.runEvent = runEvent; + + _btn.addEventListener("click", () => { + _clickEvent(); + }) + + /** + * 設定顯示或隱藏dom + */ + function visible(val: boolean) { + if (val === true) { + _btn.setAttribute("active", "true"); + _active = true; + } else { + _btn.setAttribute("active", ""); + _active = false; + } + } + + function getVisible() { + return _active; + } + + /** + * 設定新的click事件 + * @param func + */ + function setEvent(func: () => void) { + _clickEvent = func; + } + + /** + * 執行click事件 + */ + function runEvent() { + _clickEvent(); + } + + } +} diff --git a/Www/ts/Msgbox.ts b/Www/ts/Msgbox.ts index 20ddb11b..24594c7d 100644 --- a/Www/ts/Msgbox.ts +++ b/Www/ts/Msgbox.ts @@ -1,7 +1,10 @@ +import { I18n } from "./I18n"; +import { Lib } from "./Lib"; + /** * 訊息方塊 */ -class Msgbox { +export class Msgbox { private _isShow = false; private _i18n: I18n; diff --git a/Www/ts/RequestLimiter.ts b/Www/ts/RequestLimiter.ts new file mode 100644 index 00000000..eb998875 --- /dev/null +++ b/Www/ts/RequestLimiter.ts @@ -0,0 +1,81 @@ +/** + * 限制最大同時連線數。Chrome最大連線數為6 + */ +export class RequestLimiter { + private queue: [HTMLImageElement, string][]; + private inProgress: number; // 目前正在進行的請求數 + private maxRequests: number; + + constructor(maxRequests: number) { + this.queue = []; + this.inProgress = 0; + this.maxRequests = Math.min(maxRequests, 6); // 設置上限 + } + + public addRequest(img: HTMLImageElement, url: string) { + + // 檢查 img 元素是否仍然存在於文檔中 + if (!document.body.contains(img)) { + return; + } + + // 檢查佇列中是否已經存在相同的 img 元素和網址 + const index = this.queue.findIndex(([i, u]) => i === img && u === url); + if (index !== -1) { // 如果存在,則忽略這個請求 + return; + } + + // 檢查佇列中是否存在相同的 img 元素但不同的網址 + const index2 = this.queue.findIndex(([i, u]) => i === img && u !== url); + if (index2 !== -1) { // 如果存在,則將舊的請求從佇列中移除 + this.queue.splice(index2, 1); + } + + // 添加新的請求 + this.queue.push([img, url]); + this.processQueue(); + } + + private processQueue() { + while (this.inProgress < this.maxRequests && this.queue.length > 0) { + const [img, url] = this.queue.shift()!; + this.inProgress++; // 圖片開始加載時增加 inProgress + this.loadImage(img, url).then(() => { + this.inProgress--; + this.processQueue(); + }).catch((error) => { + // console.error(error); + this.inProgress--; // 當錯誤發生時,減少 inProgress 的值 + this.processQueue(); // 繼續處理隊列中的下一個請求 + }); + } + } + + private loadImage(img: HTMLImageElement, url: string) { + return new Promise((resolve, reject) => { + + // 如果圖片已經不存在 + let intervalTimer = setInterval(() => { + if (!document.body.contains(img)) { + // console.log("Image element has been removed from the document."); + clearInterval(intervalTimer); + clearTimeout(timeoutTimer); + reject("Image element has been removed from the document."); + } + }, 50); + + // 載入超時 + let timeoutTimer = setTimeout(() => { + clearInterval(intervalTimer); + reject("Loading image timed out."); + }, 30 * 1000); + + img.src = url; + img.onload = img.onerror = () => { + clearInterval(intervalTimer); + clearTimeout(timeoutTimer); + resolve(); + }; + }); + } +} diff --git a/Www/ts/SelectionManager.ts b/Www/ts/SelectionManager.ts new file mode 100644 index 00000000..420e2439 --- /dev/null +++ b/Www/ts/SelectionManager.ts @@ -0,0 +1,38 @@ +/** + * 指定哪些元素允許被選取 + */ +export class SelectionManager { + private mode: "whitelist" | "blacklist"; + private filter: string[] = []; + + constructor(mode: "whitelist" | "blacklist") { + this.mode = mode; + this.init(); + } + + private init() { + document.addEventListener("mousedown", (event: MouseEvent) => { + // 點擊的不是左鍵 + if (event.button !== 0) { + return; + } + + const target = event.target as Element; + // 如果點擊的是文字輸入框 + if (target instanceof HTMLInputElement || + target instanceof HTMLTextAreaElement || + target instanceof HTMLSelectElement + ) { + return; + } + const isMatch = this.filter.some(selector => target.matches(selector)); + if ((this.mode === "blacklist" && isMatch) || (this.mode === "whitelist" && !isMatch)) { + event.preventDefault(); + } + }); + } + + public add(selector: string) { + this.filter.push(selector); + } +} diff --git a/Www/ts/SettingWindow/SettingWindow.ts b/Www/ts/SettingWindow/SettingWindow.ts index 1efe18df..79fb4c48 100644 --- a/Www/ts/SettingWindow/SettingWindow.ts +++ b/Www/ts/SettingWindow/SettingWindow.ts @@ -1,8 +1,18 @@ -var baseWindow: BaseWindow; +import { BaseWindow } from "../BaseWindow"; +import { Config } from "../Config"; +import { I18n } from "../I18n"; +import { Lib } from "../Lib"; +import { MainToolbar } from "../MainWindow/MainToolbar"; +import { Msgbox } from "../Msgbox"; +import { SelectionManager } from "../SelectionManager"; + +declare global { + var settingWindow: SettingWindow; +} -var settingWindow; document.addEventListener("DOMContentLoaded", async () => { - settingWindow = new SettingWindow(); + BaseWindow.init(); + window.settingWindow = new SettingWindow(); }); class SettingWindow { @@ -11,8 +21,6 @@ class SettingWindow { constructor() { - baseWindow = new BaseWindow(); // 初始化視窗 - this.saveData = saveSetting; var _appInfo: AppInfo; diff --git a/Www/ts/Throttle.ts b/Www/ts/Throttle.ts new file mode 100644 index 00000000..1b915f76 --- /dev/null +++ b/Www/ts/Throttle.ts @@ -0,0 +1,29 @@ +/** + * 節流 (定時執行,時間內重複執行,則只會執行最後一個指令) + */ +export class Throttle { + public run: (() => Promise) | undefined = undefined; + + constructor(timeout = 50) { + + let isAsyncTaskRunning = false; + + setInterval(() => { + + if (this.run === undefined) { return; } + if (isAsyncTaskRunning) { return; } + + let func = this.run; + this.run = undefined; + isAsyncTaskRunning = true; + + func().then(() => { + isAsyncTaskRunning = false; + }).catch(() => { + console.error(); + isAsyncTaskRunning = false; + }); + + }, timeout); + } +} diff --git a/Www/ts/TiefseeScroll.ts b/Www/ts/TiefseeScroll.ts index f3d5e178..47f71c70 100644 --- a/Www/ts/TiefseeScroll.ts +++ b/Www/ts/TiefseeScroll.ts @@ -1,7 +1,9 @@ +import { Lib } from "./Lib"; + /** * 滾動條元件 */ -class TiefseeScroll { +export class TiefseeScroll { public getEventChange; public setEventChange; diff --git a/Www/ts/Tiefseeview.ts b/Www/ts/Tiefseeview.ts index 9578a492..6f4fcb88 100644 --- a/Www/ts/Tiefseeview.ts +++ b/Www/ts/Tiefseeview.ts @@ -1,7 +1,10 @@ +import { Lib } from "./Lib"; +import { TiefseeScroll } from "./TiefseeScroll"; + /** * 圖片瀏覽器 */ -class Tiefseeview { +export class Tiefseeview { public domTiefseeview: HTMLDivElement; // 整體的 div public domCon: HTMLDivElement; // 表示整體佔位的容器,用於設定 left、topo @@ -3282,7 +3285,7 @@ class Tiefseeview { /** * 對齊位置 */ -enum TiefseeviewAlignType { +export enum TiefseeviewAlignType { /** 上 */ "top", /** 右 */ @@ -3308,7 +3311,7 @@ enum TiefseeviewAlignType { /** * 圖片縮放模式 */ -enum TiefseeviewZoomType { +export enum TiefseeviewZoomType { /** 圖片大於視窗則縮放到視窗內,小於視窗則用圖片原始大小 */ "fitWindowOrImageOriginal", @@ -3337,7 +3340,7 @@ enum TiefseeviewZoomType { /** * 圖片渲染模式 */ -enum TiefseeviewImageRendering { +export enum TiefseeviewImageRendering { /** 預設值,運算成本較高 */ "auto" = 0, diff --git a/Www/ts/Toast.ts b/Www/ts/Toast.ts index b2fd25c4..ae7297aa 100644 --- a/Www/ts/Toast.ts +++ b/Www/ts/Toast.ts @@ -1,4 +1,6 @@ -class Toast { +import { Lib } from "./Lib"; + +export class Toast { static domToastList: undefined | HTMLElement = undefined; // 放所有 toastItem 的容器 diff --git a/Www/ts/WebAPI.ts b/Www/ts/WebAPI.ts index ac2b4aa4..499df88e 100644 --- a/Www/ts/WebAPI.ts +++ b/Www/ts/WebAPI.ts @@ -1,4 +1,6 @@ -class WebAPI { +import { Lib } from "./Lib"; + +export class WebAPI { static Directory = class {