diff --git a/src/css/lang/zh-Hant/setting/index.css b/src/css/lang/zh-Hant/setting/index.css index 239a64b..94c7940 100644 --- a/src/css/lang/zh-Hant/setting/index.css +++ b/src/css/lang/zh-Hant/setting/index.css @@ -12,3 +12,147 @@ body { --background-hsl: 0deg 0% 13%; --background-variant-hsl: 0deg 0% 16%; } + +.wave-container { + display: block !important; + position: relative; + overflow: hidden; +} + +.wave-unverified::after { + content: ""; + position: absolute; + top: 0; + left: -100%; + width: 200%; + height: 100%; + background: repeating-linear-gradient( + 90deg, + transparent 0%, + transparent 35%, + rgba(255, 0, 0, 0.2) 50%, + transparent 65%, + transparent 100% + ); + animation: slide 2s linear infinite, fadeIn 0.5s ease-in; + pointer-events: none; +} + +.wave-unloaded::after { + content: ""; + position: absolute; + top: 0; + left: -100%; + width: 200%; + height: 100%; + background: repeating-linear-gradient( + 90deg, + transparent 0%, + transparent 35%, + rgba(255, 215, 0, 0.2) 50%, + transparent 65%, + transparent 100% + ); + animation: slide 2s linear infinite, fadeIn 0.5s ease-in; + pointer-events: none; +} + +@keyframes slide { + 0% { + transform: translateX(0); + } + 100% { + transform: translateX(100%); + } +} + +.switch { + position: relative; + display: inline-block; +} + +.switch input { + opacity: 0; + width: 0; + height: 0; +} + +.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc; + transition: 0.4s ease-in-out; +} + +.slider:before { + position: absolute; + content: ""; + height: 18px; + width: 18px; + left: 3px; + bottom: 3px; + background-color: white; + transition: 0.4s ease-in-out; +} + +.slider.round { + border-radius: 24px; +} + +.slider.round:before { + border-radius: 50%; +} + +input:checked + .slider:before { + transform: translateX(26px); +} + +input:checked + .slider { + background-color: #2196f3; +} + +input[data-verified="false"]:checked + .slider { + background-color: #ff4444; +} + +input[data-loaded="false"]:checked + .slider { + background-color: #ffd700; +} + +@keyframes slide { + 0% { + transform: translateX(0); + } + 100% { + transform: translateX(66.66%); + } +} + +.unverified-badge, +.unloaded-badge, +.loaded-badge { + display: inline-block; + padding: 2px 6px; + border-radius: 4px; + font-size: 12px; + margin-left: 8px; +} + +.unverified-badge { + background-color: #ff4444; + color: white; +} + +.loaded-badge { + background-color: #4caf50; + color: white; +} + +.unloaded-badge { + background-color: #ffd700; + color: black; +} diff --git a/src/js/setting/plugin_list.js b/src/js/setting/plugin_list.js index c8a0e34..b3bef1e 100644 --- a/src/js/setting/plugin_list.js +++ b/src/js/setting/plugin_list.js @@ -1,10 +1,10 @@ -const { ipcRenderer } = require('electron'); +const manager = require('../core/manager'); class PluginList { constructor() { - this.pluginManagerStore = require('../core/manager'); this.enablePluginList = JSON.parse(localStorage.getItem('enabled-plugins')) || []; this.pluginList = JSON.parse(localStorage.getItem('plugin-list')) || []; + this.loadedPlugins = JSON.parse(localStorage.getItem('loaded-plugins')) || []; this.extendedInfo = document.querySelector('.extended-info'); this.extendedConfirmWrapper = document.querySelector('.confirm-wrapper'); this.ConfirmSure = this.extendedConfirmWrapper.querySelector('.confirm-sure'); @@ -31,6 +31,13 @@ class PluginList { }); } + getPluginLoadStatus(pluginName) { + if (Array.isArray(this.loadedPlugins)) { + return this.loadedPlugins.map((_) => _.name).includes(pluginName); + } + return this.loadedPlugins[pluginName] !== undefined; + } + renderElements() { if (!this.pluginList.length) { return; @@ -40,32 +47,52 @@ class PluginList { return; } const isEnabled = this.enablePluginList.includes(item.name); + const isLoaded = this.getPluginLoadStatus(item.name); + + const waveClassName = isEnabled + ? (!isLoaded + ? 'wave-unloaded' + : !item.verified + ? 'wave-unverified' + : '') + : ''; + return ` -
-
-
-
-
- ${item.name} -
-
-
- ${item.author[0]} - ${item.version} +
+
+
+
+
+
+ ${item.name} + ${!item.verified ? '未驗證' : ''} + ${!isEnabled ? '' : isLoaded ? '已載入' : '未載入'} +
+
+
+ ${item.author[0]} + ${item.version} +
+
+
+
+ ${item.description['zh_tw']}
-
-
- ${item.description['zh_tw']} +
+ +
-
- -
-
`; @@ -79,9 +106,15 @@ class PluginList { return; } const checkbox = event.target.previousElementSibling; + if (checkbox.disabled) { + return; + } + this.lastState = checkbox.checked; this.lastTarget = event.target; - if (!checkbox.checked) { + + const isVerified = checkbox.dataset.verified === 'true'; + if (!checkbox.checked && !isVerified) { setTimeout(() => { this.extendedConfirmWrapper.classList.add('extendedOpen'); this.extendedConfirmWrapper.style.bottom = '0%'; @@ -123,23 +156,23 @@ class PluginList { setExtendedState() { const checkbox = this.lastTarget?.previousElementSibling; - if (!checkbox) { + if (!checkbox || checkbox.disabled) { return; } const pluginName = checkbox.dataset.name; const isEnabled = this.lastState; + if (isEnabled) { - this.pluginManagerStore.disable(pluginName); + manager.disable(pluginName); this.enablePluginList = this.enablePluginList.filter((name) => name !== pluginName); } else { - this.pluginManagerStore.enable(pluginName); + manager.enable(pluginName); if (!this.enablePluginList.includes(pluginName)) { this.enablePluginList.push(pluginName); } } localStorage.setItem('enabled-plugins', JSON.stringify(this.enablePluginList)); - ipcRenderer.send('all-reload'); this.hideConfirmWrapper(); } @@ -147,6 +180,7 @@ class PluginList { this.extendedConfirmWrapper.classList.remove('extendedOpen'); this.extendedConfirmWrapper.style.bottom = '-100%'; this.ConfirmTitle.textContent = ''; + clearInterval(this.interval); } } diff --git a/src/main.js b/src/main.js index 8cc12e8..0428635 100644 --- a/src/main.js +++ b/src/main.js @@ -276,13 +276,6 @@ ipcMain.on('reload', () => { } }); -ipcMain.on('all-reload', () => { - const allWindows = BrowserWindow.getAllWindows(); - allWindows.forEach((window) => { - window.webContents.reload(); - }); -}); - ipcMain.on('minimize', () => { if (win) { win.minimize();