From bb2a5cdb399ff78ae7abef7b91bcf4615824fa62 Mon Sep 17 00:00:00 2001 From: npmrun <1549469775@qq.com> Date: Thu, 20 Feb 2025 23:41:29 +0800 Subject: [PATCH] fix bug --- .vscode/settings.json | 2 +- src/main/commands/BasicCommand.ts | 57 ++++- src/renderer/index.html | 30 +-- src/renderer/src/components/AdjustLine.vue | 292 +++++++++++++++++++--- src/renderer/src/components/NavBar.vue | 39 ++- src/renderer/src/pages/index.vue | 387 +++++++++++++++++++++++++---- 6 files changed, 707 insertions(+), 100 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 0d09930..7e74831 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,6 @@ { "[typescript]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" + "editor.defaultFormatter": "vscode.typescript-language-features" }, "[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" diff --git a/src/main/commands/BasicCommand.ts b/src/main/commands/BasicCommand.ts index eb3889b..de5608d 100644 --- a/src/main/commands/BasicCommand.ts +++ b/src/main/commands/BasicCommand.ts @@ -1,5 +1,58 @@ +import { app, dialog } from "electron" +import { inject } from "inversify" +import WindowManager from "main/modules/window-manager" + export default class BasicCommand { - log() { - console.log("1231") + constructor(@inject(WindowManager) private _WindowManager: WindowManager) { + // + } + + toggleDevTools() { + const focusedWindow = this._WindowManager.getFocusWindow() + if (focusedWindow) { + // @ts-ignore ... + focusedWindow.toggleDevTools() + } + } + fullscreen() { + const focusedWindow = this._WindowManager.getFocusWindow() + const isFullScreen = focusedWindow!.isFullScreen() + focusedWindow!.setFullScreen(!isFullScreen) + return !isFullScreen + } + isFullscreen() { + const focusedWindow = this._WindowManager.getFocusWindow() + return focusedWindow!.isFullScreen() + } + + relunch() { + app.relaunch() + app.exit() + } + + reload() { + const focusedWindow = this._WindowManager.getFocusWindow() + // 重载之后, 刷新并关闭所有的次要窗体 + if (this._WindowManager.length() > 1 && focusedWindow && focusedWindow.$$opts!.name === this._WindowManager.mainInfo.name) { + const choice = dialog.showMessageBoxSync(focusedWindow, { + type: "question", + buttons: ["取消", "是的,继续", "不,算了"], + title: "警告", + defaultId: 2, + cancelId: 0, + message: "警告", + detail: "重载主窗口将关闭所有子窗口,是否继续", + }) + if (choice == 1) { + this._WindowManager.getWndows().forEach(win => { + if (win.$$opts!.name !== this._WindowManager.mainInfo.name) { + win.close() + } + }) + } else { + return + } + } + focusedWindow!.reload() } } diff --git a/src/renderer/index.html b/src/renderer/index.html index 82eacab..2cf2727 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -1,17 +1,19 @@ <!doctype html> <html> - <head> - <meta charset="UTF-8" /> - <title>Electron</title> - <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP --> - <meta - http-equiv="Content-Security-Policy" - content="default-src 'self' api: 'unsafe-inline'; script-src 'self' api:; style-src 'self' 'unsafe-inline'; img-src 'self' data:;" - /> - </head> - <body> - <div id="app"></div> - <script type="module" src="/src/main.ts"></script> - </body> -</html> +<head> + <meta charset="UTF-8" /> + <title>Electron</title> + <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP --> + <meta http-equiv="Content-Security-Policy" content="default-src 'self' api: 'unsafe-inline'; + script-src 'self' api:; + style-src 'self' 'unsafe-inline'; + img-src 'self' data: *;" /> +</head> + +<body> + <div id="app"></div> + <script type="module" src="/src/main.ts"></script> +</body> + +</html> \ No newline at end of file diff --git a/src/renderer/src/components/AdjustLine.vue b/src/renderer/src/components/AdjustLine.vue index d0d31a1..d399061 100644 --- a/src/renderer/src/components/AdjustLine.vue +++ b/src/renderer/src/components/AdjustLine.vue @@ -1,17 +1,29 @@ <template> - <div class="adjust-line" :class="['adjust-line__' + direction]" ref="adjustLineEL"></div> + <div ref="adjustLineEL" :class="['adjust-line', `adjust-line--${direction}`, { 'adjust-line--dragging': isDragging }]"> + <div class="adjust-line__handle"> + <div class="adjust-line__grip"> + <span class="grip-line"></span> + <span class="grip-line"></span> + </div> + </div> + </div> </template> <script setup lang="ts"> -import { nextTick, onMounted, ref, watch } from "vue" +import { nextTick, onMounted, ref, watch, computed, onBeforeUnmount, onErrorCaptured } from "vue" +import { useDebounceFn } from "@vueuse/core" const adjustLineEL = ref<HTMLElement>() -type IProps = { +// 定义方向类型 +type Direction = "left" | "right" | "top" | "bottom" + +// 优化Props接口 +interface AdjustLineProps { /** * 所在方向 'left' | 'right' | 'top' | 'bottom' */ - direction?: "left" | "right" | "top" | "bottom" + direction?: Direction /** * 需要调整的元素 */ @@ -24,14 +36,86 @@ type IProps = { * 唯一ID */ mid?: string + minSize?: number + maxSize?: number + defaultSize?: number + onChange?: (size: number) => void } -const props = withDefaults(defineProps<IProps>(), { +const props = withDefaults(defineProps<AdjustLineProps>(), { direction: "right", + minSize: 100, + maxSize: 800, }) +// 定义事件 +const emit = defineEmits<{ + (e: "resize", size: number): void + (e: "resizeStart"): void + (e: "resizeEnd", size: number): void +}>() + let curTarget: HTMLElement | undefined | null +const isDragging = ref(false) +const currentSize = ref(props.defaultSize || 0) + +// 使用computed优化方向判断 +const isHorizontal = computed(() => props.direction === "left" || props.direction === "right") + +// 使用computed获取光标样式 +const cursorStyle = computed(() => (isHorizontal.value ? "ew-resize" : "ns-resize")) + +// 保存状态到localStorage的优化 +const storageKey = computed(() => `adjust-line-${props.mid}`) + +function saveSize(size: number) { + if (props.mid) { + try { + localStorage.setItem(storageKey.value, String(size)) + } catch (error) { + console.warn("Failed to save size to localStorage:", error) + } + } +} + +function loadSavedSize(): number | null { + if (props.mid) { + try { + const saved = localStorage.getItem(storageKey.value) + return saved ? Number(saved) : null + } catch (error) { + console.warn("Failed to load size from localStorage:", error) + return null + } + } + return null +} + +// 使用防抖优化resize事件 +const emitResize = useDebounceFn((size: number) => { + emit("resize", size) +}, 16) + +// 使用ResizeObserver监听容器大小变化 +const observeResize = () => { + if (!adjustLineEL.value) return + + const observer = new ResizeObserver(() => { + if (curTarget) { + const size = isHorizontal.value ? curTarget.clientWidth : curTarget.clientHeight + currentSize.value = size + emitResize(size) + } + }) + + observer.observe(adjustLineEL.value) + + onBeforeUnmount(() => { + observer.disconnect() + }) +} + onMounted(async () => { await nextTick() if (!props.target) { @@ -51,6 +135,7 @@ onMounted(async () => { } }, ) + observeResize() }) function handle(target: HTMLElement) { @@ -231,49 +316,198 @@ function handle(target: HTMLElement) { } } } + +function handleDrag(e: MouseEvent, target: HTMLElement) { + const startPos = isHorizontal.value ? e.clientX : e.clientY + const startSize = isHorizontal.value ? target.clientWidth : target.clientHeight + + const handleMouseMove = (e: MouseEvent) => { + const currentPos = isHorizontal.value ? e.clientX : e.clientY + const diff = props.direction === "right" || props.direction === "bottom" ? startPos - currentPos : currentPos - startPos + + let newSize = startSize - diff + + // 限制大小范围 + newSize = Math.max(props.minSize, Math.min(props.maxSize, newSize)) + + // 应用新尺寸 + if (isHorizontal.value) { + target.style.width = `${newSize}px` + } else { + target.style.height = `${newSize}px` + } + + currentSize.value = newSize + emit("resize", newSize) + } + + const handleMouseUp = () => { + document.removeEventListener("mousemove", handleMouseMove) + document.removeEventListener("mouseup", handleMouseUp) + document.body.style.userSelect = "" + isDragging.value = false + saveSize(currentSize.value) + emit("resizeEnd", currentSize.value) + } + + document.addEventListener("mousemove", handleMouseMove) + document.addEventListener("mouseup", handleMouseUp) + document.body.style.userSelect = "none" + isDragging.value = true + emit("resizeStart") +} + +const debug = { + log: (...args: any[]) => { + if (process.env.NODE_ENV === "development") { + console.log("[AdjustLine]", ...args) + } + }, + error: (...args: any[]) => { + console.error("[AdjustLine]", ...args) + }, +} + +function handleError(error: Error, context: string) { + debug.error(`Error in ${context}:`, error) + // 可以添加错误上报逻辑 +} + +// 错误边界处理 +onErrorCaptured((err, instance, info) => { + handleError(err as Error, info) + return false +}) </script> <style lang="scss" scoped> .adjust-line { position: absolute; z-index: 999; - transition: background-color 0.5s ease; - &:hover, - &:active { - background: #1976d2; + &__handle { + position: absolute; + display: flex; + align-items: center; + justify-content: center; + background: transparent; + transition: all 0.2s ease; + } + + &__grip { + display: flex; + gap: 3px; + opacity: 0; + transition: opacity 0.2s; + + .adjust-line:hover &, + .adjust-line--dragging & { + opacity: 1; + } + } + + .grip-line { + background-color: #999; + border-radius: 1px; + + .adjust-line:hover &, + .adjust-line--dragging & { + background-color: #666; + } } - &__left { - left: -2px; + // 水平方向的调整线 + &--left, + &--right { top: 0; bottom: 0; - width: 4px; - cursor: ew-resize; + width: 10px; // 增加可点击区域 + cursor: col-resize; + + .adjust-line__handle { + left: 0; + top: 0; + bottom: 0; + width: 100%; + } + + .adjust-line__grip { + flex-direction: column; + } + + .grip-line { + width: 2px; + height: 16px; + } + + &:hover .adjust-line__handle { + background-color: rgba(0, 0, 0, 0.05); + } } - &__top { - top: -2px; + // 垂直方向的调整线 + &--top, + &--bottom { left: 0; right: 0; - height: 4px; - cursor: n-resize; + height: 10px; // 增加可点击区域 + cursor: row-resize; + + .adjust-line__handle { + top: 0; + left: 0; + right: 0; + height: 100%; + } + + .adjust-line__grip { + flex-direction: row; + } + + .grip-line { + width: 16px; + height: 2px; + } + + &:hover .adjust-line__handle { + background-color: rgba(0, 0, 0, 0.05); + } } - &__bottom { - bottom: -2px; - left: 0; - right: 0; - height: 4px; - cursor: n-resize; + // 调整位置以居中 + &--left { + left: -5px; + } + &--right { + right: -5px; + } + &--top { + top: -5px; + } + &--bottom { + bottom: -5px; } - &__right { - right: -2px; - top: 0; - bottom: 0; - width: 4px; - cursor: ew-resize; + // 拖动时的全局遮罩 + &--dragging { + &::after { + content: ""; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: -1; + cursor: inherit; + } + + .adjust-line__handle { + background-color: rgba(0, 0, 0, 0.08); + } + + .grip-line { + background-color: #666; + } } } </style> diff --git a/src/renderer/src/components/NavBar.vue b/src/renderer/src/components/NavBar.vue index a8f6ac4..90d8706 100644 --- a/src/renderer/src/components/NavBar.vue +++ b/src/renderer/src/components/NavBar.vue @@ -1,5 +1,14 @@ <template> - <div relative h="30px" leading="29px" pr="137px" select-none border-b="1px solid #E5E5E5" bg="#F8F8F8"> + <div + relative + h="30px" + leading="29px" + pr="137px" + :style="{ paddingRight: isFullScreen ? '0' : '' }" + select-none + border-b="1px solid #E5E5E5" + bg="#F8F8F8" + > <div absolute top-0 right-0 bottom-0 left-0 style="-webkit-app-region: drag"></div> <div h-full px-2 flex items-center gap-1 justify-between> <div flex items-center gap-1> @@ -21,17 +30,39 @@ import icon from "@res/icon.png" import config from "config" import { PopupMenu } from "@/bridge/PopupMenu" +const isFullScreen = ref(false) +onBeforeMount(async () => { + isFullScreen.value = await api.call("BasicCommand.isFullscreen") +}) const onClickMenu = () => { const menu = new PopupMenu([ { - label: "关于", - click() { - fetch("api://fuck/BasicService/showAbout") + label: "全屏", + async click() { + isFullScreen.value = await api.call("BasicCommand.fullscreen") + }, + }, + { + label: "切换开发者工具", + async click() { + isFullScreen.value = await api.call("BasicCommand.toggleDevTools") }, }, { type: "separator", }, + { + label: "重载", + click() { + api.call("BasicCommand.reload") + }, + }, + { + label: "重启", + click() { + api.call("BasicCommand.relunch") + }, + }, ]) menu.show() } diff --git a/src/renderer/src/pages/index.vue b/src/renderer/src/pages/index.vue index 3cfd35a..31d6727 100644 --- a/src/renderer/src/pages/index.vue +++ b/src/renderer/src/pages/index.vue @@ -1,5 +1,5 @@ <script setup lang="ts"> -import { onBeforeMount, onBeforeUnmount, onMounted, ref, useTemplateRef } from "vue" +import { onBeforeMount, onBeforeUnmount, onMounted, ref, useTemplateRef, nextTick } from "vue" import { PopupMenu } from "@/bridge/PopupMenu" // const PlaceHolderRef = useTemplateRef("PlaceHolder") @@ -25,6 +25,7 @@ const { stop } = useResizeObserver(PlaceHolder, () => { api.call("TabsCommand.bindElement", rect) } }) + onBeforeUnmount(() => { stop() }) @@ -89,8 +90,19 @@ function handleTabContextMenu(_, index) { menu.show() } -function changeTab(_, index) { - api.call("TabsCommand.setActive", index) +function scrollTabIntoView(index: number) { + nextTick(() => { + const tabList = document.querySelector('.tab-list') + const tabItems = tabList?.querySelectorAll('.tab-item') + if (tabList && tabItems && tabItems[index]) { + tabItems[index].scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' }) + } + }) +} + +async function changeTab(_, index) { + await api.call("TabsCommand.setActive", index) + scrollTabIntoView(index) } function addTabInput() { @@ -102,8 +114,10 @@ function addTabInput() { } } } -function addTab() { - api.call("TabsCommand.add", "about:blank") + +async function addTab() { + await api.call("TabsCommand.add", "about:blank") + scrollTabIntoView(list.value.length - 1) } async function closeTab(_, index) { @@ -135,57 +149,330 @@ function onClickDevTool() { <AdjustLine></AdjustLine> </div> <div b-l="1px solid #E5E5E5" flex-1 w-0 overflow-auto flex flex-col> - <div h="100px" flex flex-col b-b="1px solid #E5E5E5"> - <div flex gap-1 my-1 px-1 w-full> - <div - v-for="(item, index) in list" - :key="index" - p-1 - b-b="1px solid gray" - b-l="1px solid gray" - b-r="1px solid gray" - :b-t="item.isActive ? '1px solid red' : '1px solid gray'" - flex - flex-1 - w-0 - items-center - cursor="pointer" - gap="5px" - max-w="200px" - @contextmenu="handleTabContextMenu(item, index)" - @click="changeTab(item, index)" - > - <div flex-1 w-0 line-1 text-normal>{{ item.title || "加载中..." }}</div> - <span p-1 rounded hover="bg-gray-2 text-hover" @click.stop="closeTab(item, index)">X</span> + <!-- Tab栏 --> + <div h="100px" flex flex-col b-b="1px solid var(--border-color)" class="tab-container"> + <!-- Tab列表 --> + <div class="tab-list-container"> + <div class="tab-list"> + <div + v-for="(item, index) in list" + :key="index" + :class="{ + 'tab-item': true, + 'active': item.isActive + }" + @contextmenu="handleTabContextMenu(item, index)" + @click="changeTab(item, index)" + > + <div class="tab-content"> + <!-- 网站图标 --> + <img + v-if="item.favicons?.length" + :src="item.favicons[0]" + class="tab-icon" + alt="" + /> + <div v-else class="tab-icon-placeholder"></div> + + <!-- 标题 --> + <div class="tab-title">{{ item.title || "加载中..." }}</div> + + <!-- 关闭按钮 --> + <div class="tab-close" @click.stop="closeTab(item, index)"> + <svg width="16" height="16" viewBox="0 0 16 16"> + <path d="M12.81 4.36l-1.17-1.17L8 6.83 4.36 3.19 3.19 4.36 6.83 8l-3.64 3.64 1.17 1.17L8 9.17l3.64 3.64 1.17-1.17L9.17 8z" + fill="currentColor"/> + </svg> + </div> + </div> + </div> </div> - <div - p-1 - b-b="1px solid gray" - b-l="1px solid gray" - b-r="1px solid gray" - b-t="1px solid gray" - flex - items-center - cursor="pointer" - gap="5px" - hover="bg-gray-2 text-hover" - > - <span p-1 rounded @click.stop="addTab()">+</span> + + <!-- 新建标签页按钮移到容器外部 --> + <div class="new-tab-button-container"> + <div class="new-tab-button" @click.stop="addTab()"> + <svg width="20" height="20" viewBox="0 0 20 20"> + <path d="M10 4v12M4 10h12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/> + </svg> + </div> </div> </div> - <div mx="5px" overflow="auto" flex-1 h-0 flex items-center gap-x="5px"> - <div flex-1 w-0 h="35px" px-3 rounded="35px" b="1px solid gray-4" flex items-center> - <input v-model="curUrl" placeholder="输入点什么" w-full text="16px" b-0 leading="25px" outline-0 type="text" /> - </div> - <div inline-block hover="bg-gray-2 text-hover" px-1 py-1 rounded cursor="pointer" @click="addTabInput()"> - <button text="14px" bg-transparent b-0 cursor="pointer">前往</button> - </div> - <div inline-block hover="bg-gray-2 text-hover" px-1 py-1 rounded cursor="pointer" @click="onClickDevTool()"> - <button text="14px" bg-transparent b-0 cursor="pointer">DevTool</button> + + <!-- 地址栏 --> + <div class="address-bar"> + <div class="url-input-container"> + <input + v-model="curUrl" + placeholder="输入网址" + type="text" + class="url-input" + /> </div> + <button class="action-button" @click="addTabInput()">前往</button> + <button class="action-button" @click="onClickDevTool()">DevTool</button> </div> </div> - <div ref="PlaceHolder" ml="1px" flex-1 h-0 flex items-center justify-center>fuck</div> + + <!-- 内容区域 --> + <div ref="PlaceHolder" ml="1px" flex-1 h-0 flex items-center justify-center> + <!-- 保持原有内容 --> + </div> </div> </div> </template> + +<style scoped> +.tab-container { + background: var(--tab-bar-bg, #f3f3f3); + border-bottom: none; + padding-top: 4px; + height: auto; + min-height: 80px; +} + +.tab-list-container { + position: relative; + display: flex; + align-items: flex-end; + height: 32px; + padding: 0; + margin-bottom: 0; + width: 100%; + overflow: auto; +} + +.tab-list { + height: 32px; + display: flex; + align-items: flex-end; + gap: 0; + margin-bottom: 0; + overflow-x: auto; + overflow-y: hidden; + padding: 0 4px; + /* 隐藏滚动条但保持功能 */ + scrollbar-width: none; /* Firefox */ + -ms-overflow-style: none; /* IE and Edge */ + &::-webkit-scrollbar { + display: none; /* Chrome, Safari and Opera */ + } +} + +.tab-item { + position: relative; + min-width: 160px; + max-width: 240px; + height: 29px; + margin-right: -6px; + border-radius: 6px 6px 0 0; + background: var(--tab-bg, #dee1e6); + transition: all 0.15s ease; + z-index: 1; + display: flex; + align-items: center; + flex-shrink: 0; /* 防止标签被压缩 */ + cursor: pointer; +} + +.tab-item::after { + content: ''; + position: absolute; + right: 0; + top: 6px; + height: 16px; + width: 1px; + background: var(--tab-separator-color, #bdc1c6); + opacity: 0.3; +} + +.tab-item:hover { + background: var(--tab-hover-bg, #e9ebee); +} + +.tab-item.active { + background: var(--tab-active-bg, #fff); + z-index: 2; + height: 32px; + margin-bottom: -1px; +} + +.tab-item.active::before { + content: ''; + position: absolute; + left: 0; + right: 0; + top: 0; + height: 2px; + background: var(--primary-color, #1a73e8); + border-radius: 2px 2px 0 0; +} + +.tab-content { + display: flex; + align-items: center; + padding: 0 8px; + height: 100%; + gap: 6px; + width: 100%; +} + +.tab-icon { + width: 16px; + height: 16px; + flex-shrink: 0; + border-radius: 3px; +} + +.tab-icon-placeholder { + width: 16px; + height: 16px; + background: #bdc1c6; + border-radius: 50%; + flex-shrink: 0; + opacity: 0.7; +} + +.tab-title { + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-size: 12px; + color: var(--text-color, #5f6368); + line-height: 1.2; + padding-right: 4px; +} + +.tab-item.active .tab-title { + color: var(--active-text-color, #202124); +} + +.tab-close { + width: 16px; + height: 16px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + color: var(--icon-color, #5f6368); + opacity: 0; + transition: opacity 0.15s ease; + flex-shrink: 0; +} + +.tab-item:hover .tab-close { + opacity: 0.6; +} + +.tab-close:hover { + background: var(--close-hover-bg, rgba(0, 0, 0, 0.08)); + opacity: 1; +} + +.new-tab-button-container { + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 32px; + background: var(--tab-bar-bg); +} + +.new-tab-button { + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 6px; + color: var(--icon-color, #5f6368); + transition: all 0.15s ease; + cursor: pointer; + opacity: 0.8; + background: transparent; +} + +.new-tab-button:hover { + background: var(--tab-hover-bg, rgba(0, 0, 0, 0.06)); + opacity: 1; +} + +.address-bar { + padding: 8px 12px; + margin: 0; + background: var(--address-bar-bg, #fff); + display: flex; + align-items: center; + gap: 8px; + width: 100%; + border-top: 1px solid var(--tab-separator-color, rgba(0, 0, 0, 0.1)); +} + +.url-input-container { + flex: 1; + height: 36px; + background: var(--input-bg, #f1f3f4); + border-radius: 18px; + padding: 0 16px; + display: flex; + align-items: center; + margin: 0; + min-width: 0; +} + +.url-input { + width: 100%; + height: 100%; + border: none; + background: transparent; + outline: none; + font-size: 14px; + color: var(--text-color, #333); +} + +.action-button { + flex-shrink: 0; + height: 36px; + padding: 0 16px; + border: none; + border-radius: 18px; + background: transparent; + color: var(--text-color, #333); + font-size: 14px; + cursor: pointer; + transition: all 0.2s; +} + +.action-button:hover { + background: var(--button-hover-bg, #f1f3f4); +} + +/* 修改CSS变量 */ +:root { + --tab-bar-bg: #f1f3f4; + --tab-bg: rgba(32, 33, 36, 0.1); + --tab-hover-bg: rgba(32, 33, 36, 0.08); + --tab-active-bg: #fff; + --tab-separator-color: rgba(0, 0, 0, 0.2); + --text-color: #5f6368; + --active-text-color: #202124; + --icon-color: #5f6368; + --close-hover-bg: rgba(0, 0, 0, 0.08); + --primary-color: #1a73e8; + --new-tab-shadow: 0 -8px 12px -6px rgba(0, 0, 0, 0.1); +} + +[data-theme="dark"] { + --tab-bar-bg: #202124; + --tab-bg: rgba(255, 255, 255, 0.1); + --tab-hover-bg: rgba(255, 255, 255, 0.08); + --tab-active-bg: #292a2d; + --tab-separator-color: rgba(255, 255, 255, 0.2); + --text-color: #9ba0a5; + --active-text-color: #e8eaed; + --icon-color: #9ba0a5; + --close-hover-bg: rgba(255, 255, 255, 0.08); + --primary-color: #8ab4f8; + --new-tab-shadow: 0 -8px 12px -6px rgba(0, 0, 0, 0.3); +} +</style>