mirror of
https://github.com/Kuingsmile/PicList.git
synced 2026-05-13 07:40:06 +08:00
🔨 Refactor(custom): refactor mini toolbox shorkey page
This commit is contained in:
@@ -1,57 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="toolbox-handler">
|
|
||||||
<button class="handler-button" @click="() => props.handler(value)">
|
|
||||||
{{ props.handlerText }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
interface IProps {
|
|
||||||
status: string
|
|
||||||
value: any
|
|
||||||
handlerText: string
|
|
||||||
handler: (value: any) => void | Promise<void>
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = defineProps<IProps>()
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
export default {
|
|
||||||
name: 'ToolboxHandler',
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="stylus">
|
|
||||||
.toolbox-handler {
|
|
||||||
margin-top: 0.75rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.handler-button {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.5rem;
|
|
||||||
padding: 0.5rem 1rem;
|
|
||||||
background: var(--color-accent);
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
border-radius: var(--radius-md);
|
|
||||||
font-size: 0.75rem;
|
|
||||||
font-weight: 500;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: var(--transition-fast);
|
|
||||||
font-family: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.handler-button:hover {
|
|
||||||
background: var(--color-accent-hover);
|
|
||||||
transform: translateY(-1px);
|
|
||||||
box-shadow: var(--shadow-sm);
|
|
||||||
}
|
|
||||||
|
|
||||||
.handler-button:active {
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
23
src/renderer/components/toolbox/ToolboxHandler.vue
Normal file
23
src/renderer/components/toolbox/ToolboxHandler.vue
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mt-0">
|
||||||
|
<CustomButton type="primary" :text="props.handlerText" @click="() => props.handler(props.value)" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import CustomButton from '@/components/common/CustomButton.vue'
|
||||||
|
interface IProps {
|
||||||
|
status: string
|
||||||
|
value: any
|
||||||
|
handlerText: string
|
||||||
|
handler: (value: any) => void | Promise<void>
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<IProps>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'ToolboxHandler',
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<component :is="icon" class="toolbox-status-icon" :style="{ color }" />
|
<component :is="icon" class="flex h-[20px] w-[20px] items-center justify-center rounded-full" :style="{ color }" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
@@ -43,14 +43,3 @@ export default {
|
|||||||
name: 'ToolboxStatusIcon',
|
name: 'ToolboxStatusIcon',
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="stylus">
|
|
||||||
.toolbox-status-icon {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
border-radius: var(--radius-full);
|
|
||||||
transition: var(--transition-fast);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -4,15 +4,15 @@
|
|||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
body {
|
body {
|
||||||
@apply m-0 h-full w-full overflow-hidden bg-bg p-0 font-[inherit] text-main;
|
@apply m-0 h-full w-full overflow-hidden bg-transparent p-0 font-[inherit] text-main;
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
@apply m-0 h-full p-0 w-full;
|
@apply m-0 h-full p-0 w-full bg-transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app {
|
#app {
|
||||||
@apply h-full w-full;
|
@apply h-full w-full bg-transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
:focus {
|
:focus {
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="mini-page">
|
<div
|
||||||
|
id="mini-page"
|
||||||
|
class="relative box-border h-screen w-screen cursor-pointer overflow-hidden border-4 border-white bg-accent bg-center bg-no-repeat text-center text-[40px] leading-[100vh]"
|
||||||
|
:class="[osGlobal === 'linux' ? 'rounded-none bg-size-[100vh_100vw]' : 'rounded-full bg-size-[90vh_90vw]']"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
id="upload-area"
|
id="upload-area"
|
||||||
|
class="h-full w-full transition-all duration-200 ease-in-out"
|
||||||
:class="{
|
:class="{
|
||||||
'is-dragover': dragover,
|
'bg-[rgba(0,0,0,0.3)]': dragover,
|
||||||
uploading: isShowingProgress,
|
'bg-[linear-gradient(to_top,#409EFF_50%,#fff_51%)] bg-size-[200%]': isShowingProgress,
|
||||||
linux: osGlobal === 'linux',
|
'rounded-none': osGlobal === 'linux',
|
||||||
|
'rounded-full': osGlobal !== 'linux',
|
||||||
}"
|
}"
|
||||||
:style="{ backgroundPosition: '0 ' + progress + '%' }"
|
:style="{ backgroundPosition: '0 ' + progress + '%' }"
|
||||||
@drop.prevent="onDrop"
|
@drop.prevent="onDrop"
|
||||||
@@ -15,12 +21,13 @@
|
|||||||
<img
|
<img
|
||||||
v-if="!dragover && !isShowingProgress"
|
v-if="!dragover && !isShowingProgress"
|
||||||
:src="logoPath ? logoPath : './squareLogo.png'"
|
:src="logoPath ? logoPath : './squareLogo.png'"
|
||||||
style="border-radius: var(--radius-round); width: 100%; height: 100%"
|
class="block h-full w-full [image-rendering:-webkit-optimize-contrast]"
|
||||||
|
:class="osGlobal === 'linux' ? 'rounded-none' : 'rounded-full'"
|
||||||
draggable="false"
|
draggable="false"
|
||||||
@dragstart.prevent
|
@dragstart.prevent
|
||||||
/>
|
/>
|
||||||
<div id="upload-dragger" @dblclick="openUploadWindow">
|
<div id="upload-dragger" class="h-full" @dblclick="openUploadWindow">
|
||||||
<input id="file-uploader" type="file" multiple @change="onChange" />
|
<input id="file-uploader" type="file" class="hidden" multiple @change="onChange" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -200,51 +207,3 @@ export default {
|
|||||||
name: 'MiniPage',
|
name: 'MiniPage',
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus">
|
|
||||||
html, body, #app
|
|
||||||
background: transparent
|
|
||||||
#mini-page
|
|
||||||
background: #409EFF;
|
|
||||||
overflow: hidden;
|
|
||||||
color #FFF
|
|
||||||
height 100vh
|
|
||||||
width 100vw
|
|
||||||
border-radius 50%
|
|
||||||
text-align center
|
|
||||||
line-height 100vh
|
|
||||||
font-size 40px
|
|
||||||
background-size 90vh 90vw
|
|
||||||
background-position center center
|
|
||||||
background-repeat no-repeat
|
|
||||||
position relative
|
|
||||||
border 4px solid #fff
|
|
||||||
box-sizing border-box
|
|
||||||
cursor pointer
|
|
||||||
|
|
||||||
&.linux
|
|
||||||
border-radius 0
|
|
||||||
background-size 100vh 100vw
|
|
||||||
#upload-area
|
|
||||||
height 100%
|
|
||||||
width 100%
|
|
||||||
border-radius 50%
|
|
||||||
transition all .2s ease-in-out
|
|
||||||
&.linux
|
|
||||||
border-radius 0
|
|
||||||
&.uploading
|
|
||||||
background: linear-gradient(to top, #409EFF 50%, #fff 51%)
|
|
||||||
background-size 200%
|
|
||||||
#upload-dragger
|
|
||||||
height 100%
|
|
||||||
&.is-dragover
|
|
||||||
background rgba(0,0,0,0.3)
|
|
||||||
#file-uploader
|
|
||||||
display none
|
|
||||||
#mini-page img
|
|
||||||
width 100%
|
|
||||||
height 100%
|
|
||||||
border-radius 50%
|
|
||||||
display block
|
|
||||||
image-rendering: -webkit-optimize-contrast
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -1,39 +1,46 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="rename-container">
|
<div class="flex h-full w-full items-center justify-center bg-bg-secondary p-2">
|
||||||
<div class="rename-card">
|
<div
|
||||||
<form @submit.prevent="confirmName">
|
class="flex h-full w-full flex-1 items-center overflow-hidden rounded-md border border-border bg-bg-tertiary shadow-md"
|
||||||
<div class="form-content">
|
>
|
||||||
<div class="form-group">
|
<form class="flex-1 p-4" @submit.prevent="confirmName">
|
||||||
<div class="input-wrapper">
|
<div class="p-4">
|
||||||
<input
|
<div class="relative flex items-center">
|
||||||
ref="fileNameInput"
|
<input
|
||||||
v-model="form.fileName"
|
ref="fileNameInput"
|
||||||
type="text"
|
v-model="form.fileName"
|
||||||
class="form-input"
|
type="text"
|
||||||
:class="{ 'input-error': validationError }"
|
class="box-border w-full rounded-md border border-border px-4 py-3 text-sm text-main focus:border-accent focus:outline-none [.input-error]:border-danger"
|
||||||
:placeholder="t('pages.rename.placeholder')"
|
:class="{ 'input-error': validationError }"
|
||||||
autofocus
|
:placeholder="t('pages.rename.placeholder')"
|
||||||
@keyup.enter="confirmName"
|
autofocus
|
||||||
@input="clearValidationError"
|
@keyup.enter="confirmName"
|
||||||
/>
|
@input="clearValidationError"
|
||||||
<button v-if="form.fileName" type="button" class="input-clear" @click="clearFileName">
|
/>
|
||||||
<XIcon :size="16" />
|
<button
|
||||||
</button>
|
v-if="form.fileName"
|
||||||
</div>
|
type="button"
|
||||||
<div v-if="validationError" class="validation-error">
|
class="absolute top-1/2 -right-7 flex h-[24px] w-[24px] -translate-y-1/2 cursor-pointer items-center justify-center rounded-full border-none bg-danger/10 text-secondary hover:bg-danger/20 hover:text-white"
|
||||||
{{ validationError }}
|
@click="clearFileName"
|
||||||
</div>
|
>
|
||||||
|
<XIcon :size="16" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div v-if="validationError" class="mt-2 flex justify-end gap-2 text-sm font-medium text-danger">
|
||||||
|
{{ validationError }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Actions -->
|
<!-- Actions -->
|
||||||
<div class="form-actions">
|
<div class="flex flex-col items-center justify-center gap-3">
|
||||||
<button type="button" class="btn btn-secondary" @click="cancel">
|
<CustomButton class="w-[80%]" type="secondary" :text="t('common.cancel')" @click="cancel" />
|
||||||
{{ $t('common.cancel') }}
|
<CustomButton
|
||||||
</button>
|
class="w-[80%]"
|
||||||
<button type="submit" class="btn btn-primary" :disabled="!form.fileName.trim()">
|
type="primary"
|
||||||
{{ $t('common.confirm') }}
|
:text="t('common.confirm')"
|
||||||
</button>
|
:disabled="!form.fileName.trim()"
|
||||||
|
@click="confirmName"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -45,6 +52,7 @@ import { XIcon } from 'lucide-vue-next'
|
|||||||
import { nextTick, onBeforeMount, onBeforeUnmount, reactive, ref, useTemplateRef } from 'vue'
|
import { nextTick, onBeforeMount, onBeforeUnmount, reactive, ref, useTemplateRef } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
import CustomButton from '@/components/common/CustomButton.vue'
|
||||||
import { GET_RENAME_FILE_NAME, RENAME_FILE_NAME } from '@/utils/constant'
|
import { GET_RENAME_FILE_NAME, RENAME_FILE_NAME } from '@/utils/constant'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
@@ -112,231 +120,9 @@ onBeforeUnmount(() => {
|
|||||||
window.electron.ipcRendererRemoveAllListeners(RENAME_FILE_NAME)
|
window.electron.ipcRendererRemoveAllListeners(RENAME_FILE_NAME)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export default {
|
export default {
|
||||||
name: 'RenamePage',
|
name: 'RenamePage',
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
|
||||||
.rename-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
padding: 2rem;
|
|
||||||
min-height: 100vh;
|
|
||||||
background: var(--color-background-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.rename-card {
|
|
||||||
overflow: hidden;
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
border-radius: var(--radius-lg);
|
|
||||||
width: 100%;
|
|
||||||
max-width: 500px;
|
|
||||||
background: var(--color-background-primary);
|
|
||||||
box-shadow:
|
|
||||||
0 20px 25px -5px rgb(0 0 0 / 10%),
|
|
||||||
0 10px 10px -5px rgb(0 0 0 / 4%);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Form */
|
|
||||||
.form-content {
|
|
||||||
padding: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-group {
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-group:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-label {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 0.75rem;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--color-text-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-wrapper {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-input {
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
border-radius: var(--radius-md);
|
|
||||||
padding: 0.875rem 1rem;
|
|
||||||
padding-right: 2.5rem;
|
|
||||||
width: 100%;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
color: var(--color-text-primary);
|
|
||||||
background: var(--color-background-primary);
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-input:focus {
|
|
||||||
border-color: var(--color-accent);
|
|
||||||
outline: none;
|
|
||||||
box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-accent-hover), transparent 60%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-input.input-error {
|
|
||||||
border-color: #f56c6c;
|
|
||||||
box-shadow: 0 0 0 2px rgb(245 108 108 / 20%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-clear {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
right: 0.75rem;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
border: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
color: var(--color-text-secondary);
|
|
||||||
background: var(--color-background-tertiary);
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-clear:hover {
|
|
||||||
color: var(--color-text-primary);
|
|
||||||
background: var(--color-background-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.validation-error {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-top: 0.5rem;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
color: #f56c6c;
|
|
||||||
gap: 0.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Actions */
|
|
||||||
.form-actions {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
gap: 0.75rem;
|
|
||||||
padding: 1rem 2rem 2rem;
|
|
||||||
background: var(--color-background-tertiary);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Buttons */
|
|
||||||
.btn {
|
|
||||||
display: inline-flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
border: none;
|
|
||||||
border-radius: var(--radius-md);
|
|
||||||
padding: 0.75rem 1.5rem;
|
|
||||||
min-width: fit-content;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
font-weight: 500;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
gap: 0.5rem;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn:disabled {
|
|
||||||
opacity: 0.5;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn:hover:not(:disabled) {
|
|
||||||
transform: translateY(-1px);
|
|
||||||
box-shadow: 0 4px 8px rgb(0 0 0 / 15%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary {
|
|
||||||
color: white;
|
|
||||||
background: #409eff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary:hover:not(:disabled) {
|
|
||||||
background: #66b1ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-secondary {
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
color: var(--color-text-primary);
|
|
||||||
background: var(--color-background-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-secondary:hover:not(:disabled) {
|
|
||||||
border-color: var(--color-accent);
|
|
||||||
background: var(--color-background-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Responsive Design */
|
|
||||||
@media (width <= 768px) {
|
|
||||||
.rename-container {
|
|
||||||
padding: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rename-card {
|
|
||||||
max-width: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-actions {
|
|
||||||
padding: 1rem 1.5rem 1.5rem;
|
|
||||||
flex-direction: column-reverse;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (width <= 480px) {
|
|
||||||
.rename-container {
|
|
||||||
padding: 0.75rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-actions {
|
|
||||||
padding: 1rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Focus styles for accessibility */
|
|
||||||
.btn:focus-visible,
|
|
||||||
.input-clear:focus-visible {
|
|
||||||
outline: 2px solid var(--color-accent);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-input:focus-visible {
|
|
||||||
outline: 2px solid var(--color-accent);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Animation for error state */
|
|
||||||
@keyframes shake {
|
|
||||||
0%,
|
|
||||||
100% {
|
|
||||||
transform: translateX(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
25% {
|
|
||||||
transform: translateX(-4px);
|
|
||||||
}
|
|
||||||
|
|
||||||
75% {
|
|
||||||
transform: translateX(4px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-error {
|
|
||||||
animation: shake 0.3s ease-in-out;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -1,117 +1,130 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="shortkey-container">
|
<div class="relative flex h-full w-full items-center justify-center">
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="shortkey-header">
|
<div class="relative z-1 flex h-full w-full flex-col items-center justify-start gap-4 rounded-xl border-none p-4">
|
||||||
<div class="header-content">
|
<div
|
||||||
<KeyboardIcon :size="24" class="header-icon" />
|
class="flex w-full items-center justify-between gap-4 overflow-visible rounded-2xl border border-border-secondary p-4 shadow-md max-md:items-stretch"
|
||||||
<div>
|
>
|
||||||
<h1>{{ t('pages.shortKey.title') }}</h1>
|
<div class="flex flex-1 flex-wrap items-center gap-4 p-1">
|
||||||
<p>{{ ' ' }}</p>
|
<KeyboardIcon :size="24" class="text-accent" />
|
||||||
|
<div>
|
||||||
|
<h1 class="m-0 text-2xl font-semibold tracking-tight text-main">{{ t('pages.shortKey.title') }}</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Shortcuts Table Card -->
|
||||||
|
<div
|
||||||
|
class="relative flex h-full w-full flex-1 items-center justify-center overflow-hidden rounded-2xl border border-border-secondary p-1 shadow-md"
|
||||||
|
>
|
||||||
|
<div class="h-full w-full overflow-hidden rounded-xl shadow-sm">
|
||||||
|
<table class="w-full table-auto bg-white text-left text-sm text-main">
|
||||||
|
<thead class="bg-bg-secondary text-sm text-main uppercase">
|
||||||
|
<tr>
|
||||||
|
<th class="px-6 py-4 font-semibold">{{ t('pages.shortKey.name') }}</th>
|
||||||
|
<th class="px-6 py-4 font-semibold">{{ t('pages.shortKey.bind') }}</th>
|
||||||
|
<th class="px-6 py-4 font-semibold">{{ t('pages.shortKey.status') }}</th>
|
||||||
|
<th class="px-6 py-4 font-semibold">{{ t('pages.shortKey.source') }}</th>
|
||||||
|
<th class="px-6 py-4 font-semibold">{{ t('pages.shortKey.handle') }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="divide-y divide-gray-100">
|
||||||
|
<tr
|
||||||
|
v-for="(item, index) in list"
|
||||||
|
:key="item.name"
|
||||||
|
class="rounded-md transition-colors odd:bg-white even:bg-gray-50/30 hover:bg-accent/10"
|
||||||
|
>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
<div class="text-sm font-semibold text-secondary">
|
||||||
|
{{ item.label ? item.label : item.name }}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
<div class="flex gap-1">
|
||||||
|
<kbd
|
||||||
|
v-if="item.key"
|
||||||
|
class="rounded-md border border-b-4 border-gray-300 bg-gray-100 px-2 py-1 text-xs font-semibold text-main shadow-sm"
|
||||||
|
>{{ item.key }}</kbd
|
||||||
|
>
|
||||||
|
<span v-else class="text-xs text-secondary italic">{{ t('pages.shortKey.noBinding') }}</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
<span
|
||||||
|
:class="[
|
||||||
|
'inline-flex items-center rounded-md p-2 text-sm font-semibold text-secondary',
|
||||||
|
item.enable ? 'bg-success/10' : 'bg-danger/10',
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
{{ item.enable ? t('pages.shortKey.enabled') : t('pages.shortKey.disabled') }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 text-secondary">
|
||||||
|
<span class="rounded-md bg-accent/10 p-2 font-bold text-main">{{
|
||||||
|
calcOriginShowName(item.from || '')
|
||||||
|
}}</span>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 text-center">
|
||||||
|
<div class="flex items-center justify-start gap-3">
|
||||||
|
<button
|
||||||
|
:class="item.enable ? 'text-danger' : 'text-success'"
|
||||||
|
class="w-[80px] rounded-md border border-border p-2 text-center text-sm font-semibold transition-colors hover:bg-accent/10"
|
||||||
|
@click="toggleEnable(item)"
|
||||||
|
>
|
||||||
|
{{ item.enable ? t('pages.shortKey.disable') : t('pages.shortKey.enable') }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="w-[80px] rounded-md border border-border p-2 text-center text-sm font-semibold text-secondary transition-colors hover:bg-accent/10"
|
||||||
|
@click="openKeyBindingDialog(item, index)"
|
||||||
|
>
|
||||||
|
{{ t('pages.shortKey.edit') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Shortcuts Table Card -->
|
|
||||||
<div class="shortkey-card">
|
|
||||||
<div class="table-container">
|
|
||||||
<table class="shortkey-table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>{{ t('pages.shortKey.name') }}</th>
|
|
||||||
<th>{{ t('pages.shortKey.bind') }}</th>
|
|
||||||
<th>{{ t('pages.shortKey.status') }}</th>
|
|
||||||
<th>{{ t('pages.shortKey.source') }}</th>
|
|
||||||
<th>{{ t('pages.shortKey.handle') }}</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr v-for="(item, index) in list" :key="item.name" class="table-row">
|
|
||||||
<td class="name-cell">
|
|
||||||
<div class="shortcut-name">
|
|
||||||
{{ item.label ? item.label : item.name }}
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td class="key-cell">
|
|
||||||
<div class="key-binding">
|
|
||||||
<kbd v-if="item.key" class="key-display">{{ item.key }}</kbd>
|
|
||||||
<span v-else class="no-binding">{{ t('pages.shortKey.noBinding') }}</span>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td class="status-cell">
|
|
||||||
<span class="status-badge" :class="{ 'status-enabled': item.enable, 'status-disabled': !item.enable }">
|
|
||||||
{{ item.enable ? t('pages.shortKey.enabled') : t('pages.shortKey.disabled') }}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td class="source-cell">
|
|
||||||
<span class="source-name">{{ calcOriginShowName(item.from || '') }}</span>
|
|
||||||
</td>
|
|
||||||
<td class="actions-cell">
|
|
||||||
<div class="action-buttons">
|
|
||||||
<button
|
|
||||||
class="btn btn-sm"
|
|
||||||
:class="item.enable ? 'btn-danger' : 'btn-success'"
|
|
||||||
@click="toggleEnable(item)"
|
|
||||||
>
|
|
||||||
{{ item.enable ? t('pages.shortKey.disable') : t('pages.shortKey.enable') }}
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-sm btn-secondary" @click="openKeyBindingDialog(item, index)">
|
|
||||||
<Edit :size="14" />
|
|
||||||
{{ t('pages.shortKey.edit') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Key Binding Modal -->
|
<!-- Key Binding Modal -->
|
||||||
<transition name="modal">
|
<transition name="modal">
|
||||||
<div v-if="keyBindingVisible" class="modal-overlay" @click.self="cancelKeyBinding">
|
<CustomModal
|
||||||
<div class="modal-content">
|
v-if="keyBindingVisible"
|
||||||
<div class="modal-header">
|
v-model:visible="keyBindingVisible"
|
||||||
<h3 class="modal-title">
|
:title="t('pages.shortKey.changeUpload')"
|
||||||
{{ t('pages.shortKey.changeUpload') }}
|
width="600px"
|
||||||
</h3>
|
height="auto"
|
||||||
<button class="modal-close" @click="cancelKeyBinding">
|
>
|
||||||
<XIcon :size="20" />
|
<div class="p-4">
|
||||||
</button>
|
<label class="mb-4 block text-sm font-semibold text-secondary">{{ t('pages.shortKey.keyBinding') }}</label>
|
||||||
</div>
|
<input
|
||||||
<div class="modal-body">
|
v-model="shortKey"
|
||||||
<div class="form-group">
|
class="box-border w-full rounded-md border border-border bg-bg-secondary p-3 text-center font-mono text-sm tracking-wider text-main focus:border-accent focus:outline-none"
|
||||||
<label>{{ t('pages.shortKey.keyBinding') }}</label>
|
:placeholder="t('pages.shortKey.pressKeys')"
|
||||||
<input
|
readonly
|
||||||
v-model="shortKey"
|
@keydown.prevent="keyDetect($event as KeyboardEvent)"
|
||||||
class="form-input key-input"
|
/>
|
||||||
:placeholder="t('pages.shortKey.pressKeys')"
|
<div class="mt-2 text-center text-sm text-secondary">
|
||||||
readonly
|
{{ t('pages.shortKey.pressHint') }}
|
||||||
@keydown.prevent="keyDetect($event as KeyboardEvent)"
|
|
||||||
/>
|
|
||||||
<div class="input-hint">
|
|
||||||
{{ t('pages.shortKey.pressHint') }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button class="btn btn-secondary" @click="cancelKeyBinding">
|
|
||||||
{{ $t('common.cancel') }}
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-primary" @click="confirmKeyBinding">
|
|
||||||
{{ $t('common.confirm') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<template #footer>
|
||||||
|
<CustomButton type="secondary" :text="t('common.cancel')" @click="cancelKeyBinding" />
|
||||||
|
<CustomButton type="primary" :text="t('common.confirm')" @click="confirmKeyBinding" />
|
||||||
|
</template>
|
||||||
|
</CustomModal>
|
||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { Edit, KeyboardIcon, XIcon } from 'lucide-vue-next'
|
import { KeyboardIcon } from 'lucide-vue-next'
|
||||||
import { onBeforeMount, onBeforeUnmount, ref, watch } from 'vue'
|
import { onBeforeMount, onBeforeUnmount, ref, watch } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
import CustomButton from '@/components/common/CustomButton.vue'
|
||||||
|
import CustomModal from '@/components/common/CustomModal.vue'
|
||||||
import { getRawData } from '@/utils/common'
|
import { getRawData } from '@/utils/common'
|
||||||
import { configPaths } from '@/utils/configPaths'
|
import { configPaths } from '@/utils/configPaths'
|
||||||
import { getConfig } from '@/utils/dataSender'
|
import { getConfig } from '@/utils/dataSender'
|
||||||
@@ -191,5 +204,3 @@ export default {
|
|||||||
name: 'ShortkeyPage',
|
name: 'ShortkeyPage',
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped src="./css/ShortKey.css"></style>
|
|
||||||
|
|||||||
@@ -1,101 +1,108 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="toolbox-container">
|
<div class="relative no-scrollbar flex h-full w-full items-center justify-center bg-bg-tertiary">
|
||||||
<!-- Header Card -->
|
<div
|
||||||
<div class="toolbox-card header-card">
|
class="relative z-1 no-scrollbar flex h-full w-full flex-col items-center justify-start gap-6 overflow-auto rounded-xl border-none p-8 shadow-sm"
|
||||||
<div class="card-header">
|
>
|
||||||
<div class="header-content">
|
<!-- Header Card -->
|
||||||
<img class="header-logo" :src="defaultLogo" alt="Toolbox Logo" />
|
<div
|
||||||
<div class="header-text">
|
class="flex w-full items-center justify-between gap-4 overflow-visible rounded-2xl border border-border-secondary px-6 py-2 shadow-md max-md:items-stretch max-md:p-5"
|
||||||
<h1 class="header-title">
|
>
|
||||||
{{ t('pages.toolbox.title') }}
|
<div class="flex flex-1 flex-wrap items-center gap-4 p-1">
|
||||||
</h1>
|
<div class="flex flex-1 items-center gap-4">
|
||||||
<p class="header-subtitle">
|
<img class="h-[48px] w-[48px] rounded-full object-cover" :src="defaultLogo" alt="Toolbox Logo" />
|
||||||
{{ t('pages.toolbox.description') }}
|
<div class="flex flex-col gap-1">
|
||||||
</p>
|
<h1 class="m-0 text-2xl font-semibold text-main">
|
||||||
</div>
|
{{ t('pages.toolbox.title') }}
|
||||||
</div>
|
</h1>
|
||||||
<div class="header-actions">
|
<p class="m-0 text-sm text-secondary">
|
||||||
<template v-if="progress !== 100">
|
{{ t('pages.toolbox.description') }}
|
||||||
<button class="action-button" :class="{ disabled: isLoading }" :disabled="isLoading" @click="handleCheck">
|
</p>
|
||||||
<span>{{ t('pages.toolbox.startScan') }}</span>
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
<template v-else-if="isAllSuccess">
|
|
||||||
<div class="success-tips">
|
|
||||||
{{ t('pages.toolbox.success') }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template v-else-if="!isAllSuccess">
|
|
||||||
<template v-if="canFixLength !== 0">
|
|
||||||
<button class="action-button" @click="handleFix">
|
|
||||||
<span>{{ t('pages.toolbox.startFix') }}</span>
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<div class="cant-fix-container">
|
|
||||||
<span class="cant-fix-text">{{ $t('pages.toolbox.autoFixFail') }}</span>
|
|
||||||
<button class="action-button secondary small" @click="handleCheck">
|
|
||||||
<span>{{ t('pages.toolbox.reScan') }}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Progress Card -->
|
|
||||||
<div class="toolbox-card progress-card">
|
|
||||||
<div class="progress-container">
|
|
||||||
<div class="progress-bar">
|
|
||||||
<div class="progress-fill" :style="{ width: `${progress}%` }" />
|
|
||||||
</div>
|
|
||||||
<span class="progress-text">{{ Math.round(progress) }}%</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Items Card -->
|
|
||||||
<div class="toolbox-card items-card">
|
|
||||||
<div class="items-list">
|
|
||||||
<div
|
|
||||||
v-for="(item, key) in fixList"
|
|
||||||
:key="key"
|
|
||||||
class="item"
|
|
||||||
:class="{
|
|
||||||
'item-active': activeTypes.includes(key),
|
|
||||||
'item-error': item.status === IToolboxItemCheckStatus.ERROR,
|
|
||||||
'item-success': item.status === IToolboxItemCheckStatus.SUCCESS,
|
|
||||||
'item-loading': item.status === IToolboxItemCheckStatus.LOADING,
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<div class="item-header" @click="toggleItem(key)">
|
|
||||||
<div class="item-title">
|
|
||||||
<span>{{ item.title }}</span>
|
|
||||||
<toolbox-status-icon :status="item.status" />
|
|
||||||
</div>
|
|
||||||
<div class="item-chevron">
|
|
||||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
||||||
<polyline points="6,9 12,15 18,9" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<transition name="item-content">
|
<div class="flex flex-wrap items-center gap-3">
|
||||||
<div v-if="activeTypes.includes(key)" class="item-content">
|
<template v-if="progress !== 100">
|
||||||
<div class="item-message">
|
<CustomButton
|
||||||
{{ item.msg || '' }}
|
type="primary"
|
||||||
|
:text="t('pages.toolbox.startScan')"
|
||||||
|
:disabled="isLoading"
|
||||||
|
@click="handleCheck"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="isAllSuccess">
|
||||||
|
<div class="border border-success/50 bg-bg-secondary px-5 py-3 text-sm font-semibold text-secondary">
|
||||||
|
{{ t('pages.toolbox.success') }}
|
||||||
</div>
|
</div>
|
||||||
<template v-if="item.handler && item.handlerText && item.value">
|
</template>
|
||||||
<div class="item-actions">
|
<template v-else-if="!isAllSuccess">
|
||||||
<toolbox-handler
|
<template v-if="canFixLength !== 0">
|
||||||
:value="item.value"
|
<CustomButton type="secondary" :text="t('pages.toolbox.startFix')" @click="handleFix" />
|
||||||
:status="item.status"
|
</template>
|
||||||
:handler="item.handler"
|
<template v-else>
|
||||||
:handler-text="item.handlerText"
|
<div class="flex flex-wrap items-center gap-3">
|
||||||
/>
|
<span class="text-sm text-secondary">{{ $t('pages.toolbox.autoFixFail') }}</span>
|
||||||
|
<CustomButton type="secondary" :text="t('pages.toolbox.reScan')" @click="handleCheck" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Progress Card -->
|
||||||
|
<div class="w-full rounded-md border border-border-secondary shadow-sm">
|
||||||
|
<div class="flex items-center p-2">
|
||||||
|
<div class="relative mr-3 h-2 flex-1 overflow-hidden rounded-full bg-surface-elevated">
|
||||||
|
<div class="absolute top-0 left-0 h-2 rounded-full bg-success" :style="{ width: `${progress}%` }" />
|
||||||
|
</div>
|
||||||
|
<span class="text-sm text-secondary">{{ Math.round(progress) }}%</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Items Card -->
|
||||||
|
<div class="w-full flex-1 overflow-hidden rounded-md border border-border-secondary shadow-sm">
|
||||||
|
<div class="h-full w-full overflow-auto p-4">
|
||||||
|
<div class="border border-border-secondary shadow-sm">
|
||||||
|
<div
|
||||||
|
v-for="(item, key) in fixList"
|
||||||
|
:key="key"
|
||||||
|
class="border-b border-border-secondary last:border-0 hover:bg-surface-elevated"
|
||||||
|
:class="{
|
||||||
|
'bg-surface-elevated': activeTypes.includes(key),
|
||||||
|
'border-l-3 border-danger': item.status === IToolboxItemCheckStatus.ERROR,
|
||||||
|
'border-l-3 border-success': item.status === IToolboxItemCheckStatus.SUCCESS,
|
||||||
|
'border-l-3 border-accent': item.status === IToolboxItemCheckStatus.LOADING,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div class="flex cursor-pointer items-center justify-between px-6 py-4" @click="toggleItem(key)">
|
||||||
|
<div class="flex flex-1 items-center gap-3 text-sm font-semibold text-secondary">
|
||||||
|
<span>{{ item.title }}</span>
|
||||||
|
<toolbox-status-icon :status="item.status" />
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center text-secondary">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<polyline points="6,9 12,15 18,9" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<transition name="item-content">
|
||||||
|
<div v-if="activeTypes.includes(key)" class="border-t border-border-secondary bg-surface p-2">
|
||||||
|
<div class="mb-3 text-sm leading-[1.5] text-secondary">
|
||||||
|
{{ item.msg || '' }}
|
||||||
|
</div>
|
||||||
|
<template v-if="item.handler && item.handlerText && item.value">
|
||||||
|
<div class="flex justify-start">
|
||||||
|
<toolbox-handler
|
||||||
|
:value="item.value"
|
||||||
|
:status="item.status"
|
||||||
|
:handler="item.handler"
|
||||||
|
:handler-text="item.handlerText"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -106,8 +113,9 @@
|
|||||||
import { computed, onUnmounted, reactive, ref } from 'vue'
|
import { computed, onUnmounted, reactive, ref } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
import ToolboxHandler from '@/components/ToolboxHandler.vue'
|
import CustomButton from '@/components/common/CustomButton.vue'
|
||||||
import ToolboxStatusIcon from '@/components/ToolboxStatusIcon.vue'
|
import ToolboxHandler from '@/components/toolbox/ToolboxHandler.vue'
|
||||||
|
import ToolboxStatusIcon from '@/components/toolbox/ToolboxStatusIcon.vue'
|
||||||
import useConfirm from '@/hooks/useConfirm'
|
import useConfirm from '@/hooks/useConfirm'
|
||||||
import { IRPCActionType, IToolboxItemCheckStatus, IToolboxItemType } from '@/utils/enum'
|
import { IRPCActionType, IToolboxItemCheckStatus, IToolboxItemType } from '@/utils/enum'
|
||||||
|
|
||||||
@@ -247,5 +255,3 @@ export default {
|
|||||||
name: 'ToolBoxPage',
|
name: 'ToolBoxPage',
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped src="./css/ToolboxPage.css"></style>
|
|
||||||
|
|||||||
@@ -142,10 +142,10 @@
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
v-if="showProgress"
|
v-if="showProgress"
|
||||||
class="flex flex-wrap items-center justify-between gap-4 rounded-2xl border border-border-secondary p-0 shadow-md"
|
class="flex w-full flex-wrap items-center justify-between gap-4 rounded-2xl border border-border-secondary p-0 shadow-md"
|
||||||
>
|
>
|
||||||
<div class="mx-2 my-2 w-full rounded-lg border border-border bg-surface p-4">
|
<div class="flex w-full items-center gap-2 rounded-lg border border-border bg-surface p-2">
|
||||||
<div class="mb-2 h-3 overflow-hidden rounded-lg bg-bg-secondary">
|
<div class="h-3 flex-1 overflow-hidden rounded-lg bg-bg-secondary">
|
||||||
<div
|
<div
|
||||||
class="h-full rounded-lg bg-[linear-gradient(90deg,var(--color-accent)_0%,var(--color-primary)_50%)] duration-fast ease-standard data-[error=true]:bg-danger data-[error=true]:bg-none"
|
class="h-full rounded-lg bg-[linear-gradient(90deg,var(--color-accent)_0%,var(--color-primary)_50%)] duration-fast ease-standard data-[error=true]:bg-danger data-[error=true]:bg-none"
|
||||||
:data-error="showError"
|
:data-error="showError"
|
||||||
|
|||||||
@@ -1,427 +0,0 @@
|
|||||||
.shortkey-container {
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 1.5rem;
|
|
||||||
min-height: 100vh;
|
|
||||||
color: var(--color-text-primary);
|
|
||||||
background: var(--color-background-secondary);
|
|
||||||
scrollbar-width: none;
|
|
||||||
-ms-overflow-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shortkey-container::-webkit-scrollbar {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Header */
|
|
||||||
.shortkey-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
border-radius: var(--radius-lg);
|
|
||||||
padding: 1.5rem;
|
|
||||||
background: var(--color-surface);
|
|
||||||
box-shadow: 0 2px 8px rgb(0 0 0 / 10%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-content {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-icon {
|
|
||||||
color: var(--color-accent);
|
|
||||||
}
|
|
||||||
|
|
||||||
.shortkey-header h1 {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 1.5rem;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--color-text-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.shortkey-header p {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
color: var(--color-text-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Card */
|
|
||||||
.shortkey-card {
|
|
||||||
overflow: hidden;
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
border-radius: var(--radius-lg);
|
|
||||||
background: var(--color-background-primary);
|
|
||||||
box-shadow: 0 2px 8px var(--color-border);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Table */
|
|
||||||
.table-container {
|
|
||||||
overflow-x: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shortkey-table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shortkey-table th {
|
|
||||||
border-bottom: 1px solid var(--color-border);
|
|
||||||
padding: 1rem;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
font-weight: 600;
|
|
||||||
text-align: left;
|
|
||||||
color: var(--color-text-primary);
|
|
||||||
background: var(--color-background-tertiary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.shortkey-table td {
|
|
||||||
border-bottom: 1px solid var(--color-border-secondary);
|
|
||||||
padding: 1rem;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-row:hover {
|
|
||||||
background: var(--color-background-tertiary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-row:last-child td {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Table Cells */
|
|
||||||
.name-cell {
|
|
||||||
width: 25%;
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--color-text-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.key-cell {
|
|
||||||
width: 20%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.key-binding {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.key-display {
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
border-radius: var(--radius-sm);
|
|
||||||
padding: 0.25rem 0.5rem;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
font-family: monospace;
|
|
||||||
color: var(--color-text-primary);
|
|
||||||
background: var(--color-background-tertiary);
|
|
||||||
box-shadow: 0 1px 2px rgb(0 0 0 / 10%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-binding {
|
|
||||||
font-size: 0.875rem;
|
|
||||||
color: var(--color-text-secondary);
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-cell {
|
|
||||||
width: 15%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-badge {
|
|
||||||
display: inline-block;
|
|
||||||
border-radius: var(--radius-lg);
|
|
||||||
padding: 0.25rem 0.75rem;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-enabled {
|
|
||||||
border: 1px solid rgb(103 194 58 / 20%);
|
|
||||||
color: var(--color-success);
|
|
||||||
background: rgb(103 194 58 / 10%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-disabled {
|
|
||||||
border: 1px solid rgb(245 108 108 / 20%);
|
|
||||||
color: var(--color-danger);
|
|
||||||
background: rgb(245 108 108 / 10%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.source-cell {
|
|
||||||
width: 15%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.source-name {
|
|
||||||
font-size: 0.875rem;
|
|
||||||
color: var(--color-text-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.actions-cell {
|
|
||||||
width: 25%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-buttons {
|
|
||||||
display: flex;
|
|
||||||
gap: 0.5rem;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Buttons */
|
|
||||||
.btn {
|
|
||||||
display: inline-flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
border: none;
|
|
||||||
border-radius: var(--radius-sm);
|
|
||||||
padding: 0.5rem 0.875rem;
|
|
||||||
min-width: fit-content;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
font-weight: 500;
|
|
||||||
text-decoration: none;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
gap: 0.375rem;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn:disabled {
|
|
||||||
opacity: 0.5;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn:hover:not(:disabled) {
|
|
||||||
transform: translateY(-1px);
|
|
||||||
box-shadow: 0 4px 8px rgb(0 0 0 / 15%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-sm {
|
|
||||||
padding: 0.375rem 0.75rem;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary {
|
|
||||||
color: white;
|
|
||||||
background: var(--color-accent);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary:hover:not(:disabled) {
|
|
||||||
background: var(--color-accent-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-secondary {
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
color: var(--color-text-primary);
|
|
||||||
background: var(--color-background-tertiary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-secondary:hover:not(:disabled) {
|
|
||||||
border-color: var(--color-accent);
|
|
||||||
background: var(--color-background-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-success {
|
|
||||||
color: white;
|
|
||||||
background: var(--color-success);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-success:hover:not(:disabled) {
|
|
||||||
background: var(--color-success);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-danger {
|
|
||||||
color: white;
|
|
||||||
background: var(--color-danger);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-danger:hover:not(:disabled) {
|
|
||||||
background: var(--color-danger);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Modal */
|
|
||||||
.modal-overlay {
|
|
||||||
position: fixed;
|
|
||||||
inset: 0;
|
|
||||||
z-index: 1000;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
padding: 1rem;
|
|
||||||
background: rgb(0 0 0 / 50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
overflow: hidden;
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
border-radius: var(--radius-lg);
|
|
||||||
width: 100%;
|
|
||||||
max-width: 500px;
|
|
||||||
max-height: 90vh;
|
|
||||||
background: var(--color-background-primary);
|
|
||||||
box-shadow: 0 20px 25px -5px rgb(0 0 0 / 10%), 0 10px 10px -5px rgb(0 0 0 / 4%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
border-bottom: 1px solid var(--color-border-secondary);
|
|
||||||
padding: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-title {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 1.125rem;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--color-text-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-close {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
border: none;
|
|
||||||
border-radius: var(--radius-sm);
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
color: var(--color-text-secondary);
|
|
||||||
background: var(--color-background-tertiary);
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-close:hover {
|
|
||||||
color: var(--color-text-primary);
|
|
||||||
background: var(--color-background-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-body {
|
|
||||||
padding: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-footer {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
border-top: 1px solid var(--color-border-secondary);
|
|
||||||
padding: 1rem 1.5rem;
|
|
||||||
background: var(--color-background-tertiary);
|
|
||||||
gap: 0.75rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Form Elements */
|
|
||||||
.form-group {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-group label {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--color-text-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-input {
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
border-radius: var(--radius-md);
|
|
||||||
padding: 0.75rem;
|
|
||||||
width: 100%;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
color: var(--color-text-primary);
|
|
||||||
background: var(--color-background-primary);
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-input:focus {
|
|
||||||
border-color: var(--color-accent);
|
|
||||||
outline: none;
|
|
||||||
box-shadow: 0 0 0 2px rgb(64 158 255 / 20%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.key-input {
|
|
||||||
font-family: monospace;
|
|
||||||
font-weight: 600;
|
|
||||||
text-align: center;
|
|
||||||
letter-spacing: 0.5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-hint {
|
|
||||||
margin-top: 0.5rem;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
text-align: center;
|
|
||||||
color: var(--color-text-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Responsive Design */
|
|
||||||
@media (width <= 768px) {
|
|
||||||
.shortkey-container {
|
|
||||||
padding: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shortkey-header {
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-start;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-container {
|
|
||||||
overflow-x: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shortkey-table th,
|
|
||||||
.shortkey-table td {
|
|
||||||
padding: 0.75rem 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-buttons {
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 0.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-sm {
|
|
||||||
padding: 0.25rem 0.5rem;
|
|
||||||
font-size: 0.7rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
margin: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-header,
|
|
||||||
.modal-body,
|
|
||||||
.modal-footer {
|
|
||||||
padding: 1rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (width <= 480px) {
|
|
||||||
.shortkey-container {
|
|
||||||
padding: 0.75rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shortkey-header h1 {
|
|
||||||
font-size: 1.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shortkey-table {
|
|
||||||
font-size: 0.875rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shortkey-table th,
|
|
||||||
.shortkey-table td {
|
|
||||||
padding: 0.5rem 0.375rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Focus styles for accessibility */
|
|
||||||
.btn:focus-visible,
|
|
||||||
.modal-close:focus-visible {
|
|
||||||
outline: 2px solid var(--color-accent);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-input:focus-visible {
|
|
||||||
outline: 2px solid var(--color-accent);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
@@ -1,363 +0,0 @@
|
|||||||
/* Global scrolling behavior */
|
|
||||||
html, body {
|
|
||||||
overflow-x: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Container */
|
|
||||||
.toolbox-container {
|
|
||||||
display: flex;
|
|
||||||
overflow-y: auto;
|
|
||||||
margin: 0;
|
|
||||||
padding: 1rem;
|
|
||||||
width: 100%;
|
|
||||||
min-height: 100vh;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 1.25rem;
|
|
||||||
box-sizing: border-box;
|
|
||||||
background: var(--color-background-tertiary);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Card Base */
|
|
||||||
.toolbox-card {
|
|
||||||
overflow: auto;
|
|
||||||
border: 1px solid var(--color-border-secondary);
|
|
||||||
border-radius: var(--radius-xl);
|
|
||||||
background: var(--color-background-tertiary);
|
|
||||||
box-shadow: var(--shadow-sm);
|
|
||||||
transition: var(--transition-medium);
|
|
||||||
}
|
|
||||||
|
|
||||||
.toolbox-card:hover {
|
|
||||||
border-color: var(--color-border);
|
|
||||||
box-shadow: var(--shadow-md);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Header Card */
|
|
||||||
.header-card .card-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
border-bottom: 1px solid var(--color-border-secondary);
|
|
||||||
padding: 1rem 1.5rem;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-content {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 1rem;
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-logo {
|
|
||||||
border-radius: var(--radius-lg);
|
|
||||||
width: 48px;
|
|
||||||
height: 48px;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-text {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 0.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-title {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 1.5rem;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--color-text-primary);
|
|
||||||
letter-spacing: -0.025em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-subtitle {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
color: var(--color-text-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-actions {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.75rem;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-button {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
border: none;
|
|
||||||
border-radius: var(--radius-lg);
|
|
||||||
padding: 0.75rem 1.25rem;
|
|
||||||
min-width: 120px;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
font-family: inherit;
|
|
||||||
font-weight: 500;
|
|
||||||
color: white;
|
|
||||||
background: var(--color-accent);
|
|
||||||
transition: var(--transition-fast);
|
|
||||||
gap: 0.5rem;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-button:hover:not(.disabled) {
|
|
||||||
background: var(--color-accent-hover);
|
|
||||||
transform: translateY(-1px);
|
|
||||||
box-shadow: var(--shadow-md);
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-button.disabled {
|
|
||||||
opacity: 0.6;
|
|
||||||
cursor: not-allowed;
|
|
||||||
transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-button.secondary {
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
color: var(--color-text-primary);
|
|
||||||
background: var(--color-surface-elevated);
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-button.secondary:hover {
|
|
||||||
border-color: var(--color-accent);
|
|
||||||
color: var(--color-accent);
|
|
||||||
background: var(--color-surface);
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-button.small {
|
|
||||||
padding: 0.5rem 0.75rem;
|
|
||||||
min-width: auto;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.success-tips {
|
|
||||||
border: 1px solid rgb(103 194 58 / 30%);
|
|
||||||
border-radius: var(--radius-lg);
|
|
||||||
padding: 0.75rem 1.25rem;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--color-success);
|
|
||||||
background: var(--color-background-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cant-fix-container {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.75rem;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cant-fix-text {
|
|
||||||
font-size: 0.875rem;
|
|
||||||
color: var(--color-text-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Progress Card */
|
|
||||||
.progress-card {
|
|
||||||
border-radius: var(--radius-lg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-container {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 1rem 1.5rem;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-bar {
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
border-radius: var(--radius-full);
|
|
||||||
height: 8px;
|
|
||||||
background: var(--color-surface-elevated);
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-fill {
|
|
||||||
position: relative;
|
|
||||||
border-radius: var(--radius-full);
|
|
||||||
height: 100%;
|
|
||||||
background: linear-gradient(90deg, var(--color-accent) 0%, var(--color-accent-hover) 100%);
|
|
||||||
transition: width 0.3s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-fill::after {
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
background: linear-gradient(90deg, transparent 0%, rgb(255 255 255 / 20%) 50%, transparent 100%);
|
|
||||||
content: '';
|
|
||||||
animation: shimmer 2s infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes shimmer {
|
|
||||||
0% { transform: translateX(-100%); }
|
|
||||||
100% { transform: translateX(100%); }
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-text {
|
|
||||||
min-width: 40px;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
font-weight: 600;
|
|
||||||
text-align: right;
|
|
||||||
color: var(--color-text-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Items Card */
|
|
||||||
.items-card {
|
|
||||||
border-radius: var(--radius-lg);
|
|
||||||
height: 230px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-title {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 1.125rem;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--color-text-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.items-list {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item {
|
|
||||||
border-bottom: 1px solid var(--color-border-secondary);
|
|
||||||
transition: var(--transition-fast);
|
|
||||||
}
|
|
||||||
|
|
||||||
.item:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item:hover {
|
|
||||||
background: var(--color-surface-elevated);
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-active {
|
|
||||||
background: var(--color-surface-elevated);
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-error {
|
|
||||||
border-left: 3px solid var(--color-danger);
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-success {
|
|
||||||
border-left: 3px solid var(--color-success);
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-loading {
|
|
||||||
border-left: 3px solid var(--color-accent);
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
padding: 1rem 1.5rem;
|
|
||||||
transition: var(--transition-fast);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-header:hover {
|
|
||||||
background: rgb(0 0 0 / 2%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-title {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.75rem;
|
|
||||||
flex: 1;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
font-weight: 500;
|
|
||||||
color: var(--color-text-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-chevron {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
color: var(--color-text-secondary);
|
|
||||||
transition: var(--transition-fast);
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-active .item-chevron {
|
|
||||||
transform: rotate(180deg);
|
|
||||||
color: var(--color-accent);
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-content-enter-active,
|
|
||||||
.item-content-leave-active {
|
|
||||||
overflow: hidden;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-content-enter-from,
|
|
||||||
.item-content-leave-to {
|
|
||||||
max-height: 0;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-content-enter-to,
|
|
||||||
.item-content-leave-from {
|
|
||||||
max-height: 200px;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-content {
|
|
||||||
border-top: 1px solid var(--color-border-secondary);
|
|
||||||
padding: 0 1.5rem 1rem;
|
|
||||||
background: var(--color-surface);
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-message {
|
|
||||||
margin-bottom: 0.75rem;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
color: var(--color-text-secondary);
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-actions {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-start;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Responsive Design */
|
|
||||||
@media (width <= 768px) {
|
|
||||||
.toolbox-container {
|
|
||||||
padding: 0.75rem;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-card .card-header {
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: stretch;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-content {
|
|
||||||
justify-content: center;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-actions {
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cant-fix-container {
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-container {
|
|
||||||
padding: 0.75rem 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-header {
|
|
||||||
padding: 0.75rem 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-content {
|
|
||||||
padding: 0 1rem 0.75rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
.advancedAnimation {
|
|
||||||
backdrop-filter: blur(5px) saturate(180%);
|
|
||||||
background: rgb(255 255 255 / 20%);
|
|
||||||
border: 1px solid rgb(255 255 255 / 30%);
|
|
||||||
box-shadow: 0 8px 32px rgb(0 0 0 / 10%);
|
|
||||||
}
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
/* Modal - Base Styles (Used by ImageProcess Dialog) */
|
|
||||||
.modal-overlay {
|
|
||||||
position: fixed;
|
|
||||||
z-index: 1000;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 2rem;
|
|
||||||
background: rgb(0 0 0 / 50%);
|
|
||||||
inset: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-container {
|
|
||||||
overflow: hidden;
|
|
||||||
margin: auto;
|
|
||||||
border: 1px solid var(--color-border-secondary);
|
|
||||||
border-radius: var(--radius-2xl);
|
|
||||||
width: 90vw;
|
|
||||||
max-width: 90vw;
|
|
||||||
height: 85vh;
|
|
||||||
max-height: 85vh;
|
|
||||||
background: var(--color-background-tertiary);
|
|
||||||
box-shadow: var(--shadow-xl);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
border-bottom: 1px solid var(--color-border-secondary);
|
|
||||||
padding: 1rem 1.25rem;
|
|
||||||
background: var(--color-background-tertiary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-title {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 1.25rem;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--color-text-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-subtitle {
|
|
||||||
margin: 0.25rem 0 0;
|
|
||||||
font-size: 1.25rem;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--color-text-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-close {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
border-radius: var(--radius-round);
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
color: var(--color-text-secondary);
|
|
||||||
background: var(--color-surface-elevated);
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all var(--transition-fast);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-close:hover {
|
|
||||||
border-color: var(--color-danger);
|
|
||||||
color: white;
|
|
||||||
background: var(--color-danger);
|
|
||||||
transform: scale(1.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
overflow-y: auto;
|
|
||||||
max-height: calc(90vh - 90px);
|
|
||||||
scrollbar-width: none;
|
|
||||||
-ms-overflow-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content::-webkit-scrollbar {
|
|
||||||
width: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content::-webkit-scrollbar-track {
|
|
||||||
background: var(--color-surface);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content::-webkit-scrollbar-thumb {
|
|
||||||
background: var(--color-border-secondary);
|
|
||||||
border-radius: var(--radius-full);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content::-webkit-scrollbar-thumb:hover {
|
|
||||||
background: var(--color-text-tertiary);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (width <= 768px) {
|
|
||||||
.modal-overlay {
|
|
||||||
padding: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-header,
|
|
||||||
.modal-content {
|
|
||||||
padding: 1.5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-close:focus-visible {
|
|
||||||
outline: 2px solid var(--color-accent);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user