diff --git a/src/App.vue b/src/App.vue index b63883ca..a8e2cf09 100644 --- a/src/App.vue +++ b/src/App.vue @@ -34,7 +34,6 @@ import VRCXUpdateDialog from './components/dialogs/VRCXUpdateDialog.vue'; import '@/styles/globals.css'; - import '@/app.css'; console.log(`isLinux: ${LINUX}`); diff --git a/src/app.css b/src/app.css deleted file mode 100644 index 640e908e..00000000 --- a/src/app.css +++ /dev/null @@ -1,32 +0,0 @@ -html { - overflow: hidden; -} - -.lucide.is-loading { - animation: rotating 2s linear infinite; -} - -.x-container { - position: relative; - padding: 8px; - overflow: hidden auto; - box-sizing: border-box; - min-width: 0; - background: var(--background); - height: calc(100% - 20px); - margin: 8px 0 8px 0; - border-radius: var(--radius); - border: 1px solid var(--border); -} - -.aside-collapsed .x-container { - margin-right: 8px; -} - -html.dark .x-container { - background: var(--sidebar); -} - -[data-sonner-toast] [data-content] [data-description] { - white-space: pre-line; -} diff --git a/src/styles/fonts.css b/src/styles/fonts.css index a24560de..a3d5b71f 100644 --- a/src/styles/fonts.css +++ b/src/styles/fonts.css @@ -10,3 +10,39 @@ src: local('Times New Roman'); unicode-range: U+2026; } + +:root { + --font-western-primary: 'Inter Variable'; + --font-western: + 'ellipsis-font', -apple-system, var(--font-western-primary), 'Segoe UI', + 'Roboto', 'Ubuntu', 'Cantarell', 'DejaVu Sans', sans-serif; + --font-symbol: 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; + --font-fallback-cjk: sans-serif; + --font-primary-cjk: + 'Noto Sans JP Variable', 'Noto Sans SC Variable', + 'Noto Sans KR Variable', 'Noto Sans TC Variable'; +} + +:root[lang='zh-CN'] { + --font-primary-cjk: + 'Noto Sans SC Variable', 'Noto Sans JP Variable', + 'Noto Sans KR Variable', 'Noto Sans TC Variable'; +} + +:root[lang='ja'] { + --font-primary-cjk: + 'Noto Sans JP Variable', 'Noto Sans KR Variable', + 'Noto Sans TC Variable', 'Noto Sans SC Variable'; +} + +:root[lang='ko'] { + --font-primary-cjk: + 'Noto Sans KR Variable', 'Noto Sans JP Variable', + 'Noto Sans TC Variable', 'Noto Sans SC Variable'; +} + +:root[lang='zh-TW'] { + --font-primary-cjk: + 'Noto Sans TC Variable', 'Noto Sans JP Variable', + 'Noto Sans KR Variable', 'Noto Sans SC Variable'; +} diff --git a/src/styles/globals.css b/src/styles/globals.css index baa05683..f9299d4b 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -16,30 +16,6 @@ @custom-variant dark (&:is(.dark *)); -:root[lang='zh-CN'] { - --font-primary-cjk: - 'Noto Sans SC Variable', 'Noto Sans JP Variable', - 'Noto Sans KR Variable', 'Noto Sans TC Variable'; -} - -:root[lang='ja'] { - --font-primary-cjk: - 'Noto Sans JP Variable', 'Noto Sans KR Variable', - 'Noto Sans TC Variable', 'Noto Sans SC Variable'; -} - -:root[lang='ko'] { - --font-primary-cjk: - 'Noto Sans KR Variable', 'Noto Sans JP Variable', - 'Noto Sans TC Variable', 'Noto Sans SC Variable'; -} - -:root[lang='zh-TW'] { - --font-primary-cjk: - 'Noto Sans TC Variable', 'Noto Sans JP Variable', - 'Noto Sans KR Variable', 'Noto Sans SC Variable'; -} - :root { --background: oklch(1 0 0); --foreground: oklch(0.145 0 0); @@ -95,16 +71,6 @@ --visibility-public: #22c55e; --visibility-friends: #0ea5e9; --visibility-private: #ef4444; - - --font-western-primary: 'Inter Variable'; - --font-western: - 'ellipsis-font', -apple-system, var(--font-western-primary), 'Segoe UI', - 'Roboto', 'Ubuntu', 'Cantarell', 'DejaVu Sans', sans-serif; - --font-symbol: 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; - --font-fallback-cjk: sans-serif; - --font-primary-cjk: - 'Noto Sans JP Variable', 'Noto Sans SC Variable', - 'Noto Sans KR Variable', 'Noto Sans TC Variable'; } .dark { @@ -202,19 +168,51 @@ --color-visibility-private: var(--visibility-private); } -@layer base { - * { - @apply border-border outline-ring/50; - scrollbar-width: thin; - scrollbar-color: var(--border) transparent; - } - body { - @apply bg-background text-foreground; - font-family: - var(--font-western), var(--font-symbol), var(--font-primary-cjk), - var(--font-fallback-cjk); - margin: 0; - } +html { + overflow: hidden; +} + +.lucide.is-loading { + animation: rotating 2s linear infinite; +} + +.x-container { + position: relative; + padding: 8px; + overflow: hidden auto; + box-sizing: border-box; + min-width: 0; + background: var(--background); + height: calc(100% - 20px); + margin: 8px 0 8px 0; + border-radius: var(--radius); + border: 1px solid var(--border); +} + +.aside-collapsed .x-container { + margin-right: 8px; +} + +html.dark .x-container { + background: var(--sidebar); +} + +[data-sonner-toast] [data-content] [data-description] { + white-space: pre-line; +} + +* { + @apply border-border outline-ring/50; + scrollbar-width: thin; + scrollbar-color: var(--border) transparent; +} + +body { + @apply bg-background text-foreground; + font-family: + var(--font-western), var(--font-symbol), var(--font-primary-cjk), + var(--font-fallback-cjk); + margin: 0; } ::-webkit-scrollbar { @@ -233,17 +231,15 @@ background-clip: content-box; } -@layer utilities { - .scrollbar-hidden { - scrollbar-width: none; - -ms-overflow-style: none; - } +.scrollbar-hidden { + scrollbar-width: none; + -ms-overflow-style: none; +} - .scrollbar-hidden::-webkit-scrollbar { - width: 0; - height: 0; - display: none; - } +.scrollbar-hidden::-webkit-scrollbar { + width: 0; + height: 0; + display: none; } [data-slot='table-header'], @@ -255,3 +251,31 @@ width: 1em; height: 1em; } + +/* ========================================================================== + * VRCX UI Standards + * These are project-wide conventions. + * Use them when building new components. + * ==========================================================================*/ + +/* Hover Transitions + * Smooth hover state changes to avoid harsh flickering. + * x-hover-card — Cards & panels (0.2s, bg + shadow) + * x-hover-list — List items (0.15s, bg). Skip for high-density lists (e.g. friend sidebar). + * x-hover-icon — Icon buttons (0.1s, bg + color) + */ +.x-hover-card { + transition: + background-color 0.2s ease, + box-shadow 0.2s ease; +} + +.x-hover-list { + transition: background-color 0.15s ease; +} + +.x-hover-icon { + transition: + background-color 0.1s ease, + color 0.1s ease; +} diff --git a/src/views/Favorites/FavoritesAvatar.vue b/src/views/Favorites/FavoritesAvatar.vue index 2a655c69..9a8ae755 100644 --- a/src/views/Favorites/FavoritesAvatar.vue +++ b/src/views/Favorites/FavoritesAvatar.vue @@ -51,7 +51,7 @@ v-for="group in favoriteAvatarGroups" :key="group.key" :class="[ - 'group-item hover:shadow-sm', + 'group-item x-hover-card hover:shadow-sm', `group-item--${group.visibility}`, { 'is-active': !hasSearchInput && isGroupActive('remote', group.key) } ]" @@ -123,7 +123,7 @@ v-for="group in avatarGroupPlaceholders" :key="group.key" :class="[ - 'group-item hover:shadow-sm', + 'group-item x-hover-card hover:shadow-sm', 'pointer-events-none opacity-70', { 'is-active': !hasSearchInput && isGroupActive('remote', group.key) } ]"> @@ -162,7 +162,7 @@ v-for="group in localAvatarFavoriteGroups" :key="group" :class="[ - 'group-item hover:shadow-sm', + 'group-item x-hover-card hover:shadow-sm', { 'is-active': !hasSearchInput && isGroupActive('local', group) } ]" @click="handleGroupClick('local', group)"> @@ -211,7 +211,7 @@ :content="t('view.favorite.avatars.local_favorites')">