mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-16 13:23:52 +02:00
refactor css and add UI Standards class
This commit is contained in:
@@ -34,7 +34,6 @@
|
||||
import VRCXUpdateDialog from './components/dialogs/VRCXUpdateDialog.vue';
|
||||
|
||||
import '@/styles/globals.css';
|
||||
import '@/app.css';
|
||||
|
||||
console.log(`isLinux: ${LINUX}`);
|
||||
|
||||
|
||||
32
src/app.css
32
src/app.css
@@ -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;
|
||||
}
|
||||
@@ -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';
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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')">
|
||||
<div
|
||||
:class="[
|
||||
'group-item hover:shadow-sm',
|
||||
'group-item x-hover-card hover:shadow-sm',
|
||||
'border-dashed flex items-center justify-center gap-2 text-sm',
|
||||
{ 'opacity-50 cursor-not-allowed': !isLocalUserVrcPlusSupporter }
|
||||
]"
|
||||
@@ -253,7 +253,7 @@
|
||||
<div class="flex flex-col gap-2">
|
||||
<div
|
||||
:class="[
|
||||
'group-item hover:shadow-sm',
|
||||
'group-item x-hover-card hover:shadow-sm',
|
||||
{ 'is-active': !hasSearchInput && isGroupActive('history', historyGroupKey) }
|
||||
]"
|
||||
@click="handleGroupClick('history', historyGroupKey)">
|
||||
@@ -314,7 +314,7 @@
|
||||
<div
|
||||
v-for="favorite in avatarFavoriteSearchResults"
|
||||
:key="favorite.id"
|
||||
class="favorites-search-card hover:shadow-sm"
|
||||
class="favorites-search-card x-hover-card hover:shadow-sm"
|
||||
@click="showAvatarDialog(favorite.id)">
|
||||
<div class="favorites-search-card__content">
|
||||
<div
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
v-for="group in favoriteFriendGroups"
|
||||
: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) }
|
||||
]"
|
||||
@@ -140,7 +140,7 @@
|
||||
v-for="group in localFriendFavoriteGroups"
|
||||
: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)">
|
||||
@@ -184,7 +184,7 @@
|
||||
</div>
|
||||
<div
|
||||
v-if="!isCreatingLocalGroup"
|
||||
class="group-item hover:shadow-sm border-dashed flex items-center justify-center gap-2 text-sm"
|
||||
class="group-item x-hover-card hover:shadow-sm border-dashed flex items-center justify-center gap-2 text-sm"
|
||||
@click="startLocalGroupCreation">
|
||||
<Plus />
|
||||
<span>{{ t('view.favorite.worlds.new_group') }}</span>
|
||||
@@ -289,7 +289,7 @@
|
||||
<div
|
||||
v-for="favorite in friendFavoriteSearchResults"
|
||||
:key="favorite.id"
|
||||
class="favorites-search-card hover:shadow-sm"
|
||||
class="favorites-search-card x-hover-card hover:shadow-sm"
|
||||
@click="showUserDialog(favorite.id)">
|
||||
<div class="favorites-search-card__content">
|
||||
<div class="favorites-search-card__avatar">
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
v-for="group in favoriteWorldGroups"
|
||||
: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 worldGroupPlaceholders"
|
||||
: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) }
|
||||
]">
|
||||
@@ -160,7 +160,7 @@
|
||||
v-for="group in localWorldFavoriteGroups"
|
||||
: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)">
|
||||
@@ -204,7 +204,7 @@
|
||||
</div>
|
||||
<div
|
||||
v-if="!isCreatingLocalGroup"
|
||||
class="group-item hover:shadow-sm border-dashed flex items-center justify-center gap-2 text-sm"
|
||||
class="group-item x-hover-card hover:shadow-sm border-dashed flex items-center justify-center gap-2 text-sm"
|
||||
@click="startLocalGroupCreation">
|
||||
<Plus />
|
||||
<span>{{ t('view.favorite.worlds.new_group') }}</span>
|
||||
@@ -262,7 +262,7 @@
|
||||
<div
|
||||
v-for="favorite in worldFavoriteSearchResults"
|
||||
:key="favorite.id"
|
||||
class="favorites-search-card hover:shadow-sm"
|
||||
class="favorites-search-card x-hover-card hover:shadow-sm"
|
||||
@click="showWorldDialog(favorite.id)">
|
||||
<div class="favorites-search-card__content">
|
||||
<div
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
padding: var(--favorites-card-padding-y, 8px)
|
||||
var(--favorites-card-padding-x, 8px);
|
||||
cursor: pointer;
|
||||
transition: background-color 0.15s ease;
|
||||
width: 100%;
|
||||
min-width: var(--favorites-card-min-width, 240px);
|
||||
max-width: var(--favorites-card-target-width, 320px);
|
||||
@@ -20,6 +19,7 @@
|
||||
|
||||
.favorites-search-card:hover {
|
||||
background-color: var(--accent);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.favorites-search-card__content {
|
||||
|
||||
@@ -22,11 +22,11 @@
|
||||
border: 1px solid var(--border);
|
||||
padding: 8px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.15s ease;
|
||||
}
|
||||
|
||||
.group-item:hover {
|
||||
background-color: var(--accent);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.group-item--public {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
<template>
|
||||
<ContextMenu>
|
||||
<ContextMenuTrigger as-child>
|
||||
<Card class="friend-card p-0 gap-0" :style="cardStyle" @click="showUserDialog(friend.id)">
|
||||
<Card
|
||||
class="friend-card x-hover-card p-0 gap-0 hover:bg-accent hover:shadow-sm"
|
||||
:style="cardStyle"
|
||||
@click="showUserDialog(friend.id)">
|
||||
<div class="friend-card__header">
|
||||
<div>
|
||||
<Avatar
|
||||
@@ -241,16 +244,10 @@
|
||||
display: grid;
|
||||
gap: calc(14px * var(--card-scale) * var(--card-spacing));
|
||||
border-radius: var(--radius-lg);
|
||||
transition: background-color 0.15s ease;
|
||||
width: 100%;
|
||||
max-width: var(--friend-card-target-width, 220px);
|
||||
min-width: var(--friend-card-min-width, 220px);
|
||||
box-sizing: border-box;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--accent);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
}
|
||||
|
||||
.friend-card__header {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<ContextMenuTrigger as="div">
|
||||
<div class="avatar-card-wrapper rounded-lg" @click="$emit('click')">
|
||||
<Card
|
||||
class="avatar-card flex flex-col gap-0 p-0 cursor-pointer overflow-hidden rounded-lg relative transition-colors hover:bg-accent hover:shadow-md"
|
||||
class="avatar-card x-hover-card flex flex-col gap-0 p-0 cursor-pointer overflow-hidden rounded-lg relative hover:bg-accent hover:shadow-sm"
|
||||
:class="isActive ? 'border-2 border-primary' : 'border border-border/50'">
|
||||
<div class="w-full aspect-5/2 overflow-hidden bg-muted relative">
|
||||
<img
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<span class="category-title">{{ t('view.tools.pictures.header') }}</span>
|
||||
</div>
|
||||
<div class="tools-grid" v-show="!categoryCollapsed['image']">
|
||||
<Card class="tool-card p-0 gap-0">
|
||||
<Card class="tool-card x-hover-card p-0 gap-0 hover:bg-accent hover:shadow-sm">
|
||||
<div class="tool-content text-2xl" @click="showScreenshotMetadataPage">
|
||||
<div class="tool-icon">
|
||||
<Camera />
|
||||
@@ -554,18 +554,12 @@
|
||||
}
|
||||
|
||||
.tool-card {
|
||||
transition: background-color 0.15s ease;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
border-radius: var(--radius-lg);
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--accent);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.tool-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<Popover :open="eventPopoverOpen">
|
||||
<PopoverTrigger as-child>
|
||||
<Card
|
||||
class="event-card p-0 gap-0"
|
||||
class="event-card x-hover-card p-0 gap-0 hover:bg-accent hover:shadow-sm"
|
||||
:class="cardClass"
|
||||
@mouseenter="openEventPopover"
|
||||
@mouseleave="scheduleCloseEventPopover">
|
||||
@@ -275,18 +275,12 @@
|
||||
|
||||
<style scoped>
|
||||
.event-card {
|
||||
transition: background-color 0.15s ease;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
border-radius: var(--radius-lg);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.event-card:hover {
|
||||
background-color: var(--accent);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.event-card.grouped-card {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user