style: update font families and improve responsive design across components

This commit is contained in:
Soulter
2026-04-24 19:26:28 +08:00
parent 713b2350d2
commit 494771799a
10 changed files with 426 additions and 44 deletions

View File

@@ -9,7 +9,7 @@
<meta name="robots" content="noindex, nofollow" />
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Outfit&family=Poppins:wght@400;500;600;700&family=Roboto:wght@400;500;700&display=swap"
href="https://fonts.googleapis.com/css2?family=Outfit&family=Noto+Sans+SC:wght@100..900&display=swap"
/>
<!-- VAD (Voice Activity Detection) Libraries -->
<script src="https://cdn.jsdelivr.net/npm/onnxruntime-web@1.22.0/dist/ort.wasm.min.js"></script>

View File

@@ -65,4 +65,34 @@ const dialog = computed({
max-height: 70dvh;
margin: 0;
}
@media (max-width: 960px) {
.provider-config-dialog {
border-radius: 20px;
}
:deep(.v-overlay__content) {
width: calc(100dvw - 24px);
height: calc(100dvh - 24px);
max-width: calc(100dvw - 24px);
max-height: calc(100dvh - 24px);
}
}
@media (max-width: 600px) {
.provider-config-dialog {
border-radius: 0;
}
.provider-config-dialog__body {
overflow: auto;
}
:deep(.v-overlay__content) {
width: 100dvw;
height: 100dvh;
max-width: 100dvw;
max-height: 100dvh;
}
}
</style>

View File

@@ -429,4 +429,68 @@ async function saveEditedProvider() {
justify-content: center;
color: rgba(var(--v-theme-on-surface), 0.56);
}
@media (max-width: 960px) {
.provider-workbench {
grid-template-columns: 1fr;
grid-template-rows: auto 1px minmax(0, 1fr);
}
.provider-workbench__sidebar,
.provider-workbench__main,
.provider-workbench__divider {
height: auto;
}
.provider-workbench__divider {
min-height: 1px;
}
.provider-config-header {
align-items: stretch;
flex-direction: column;
gap: 12px;
padding: 16px;
}
.provider-config-actions :deep(.v-btn) {
width: 100%;
}
.provider-section {
padding: 16px;
}
}
@media (max-width: 600px) {
.provider-chat-panel {
overflow: auto;
}
.provider-workbench {
border-radius: 16px;
overflow: visible;
}
.provider-workbench--borderless {
border-radius: 0;
}
.provider-workbench__main {
overflow: visible;
}
.provider-config-body {
overflow-y: visible;
}
.provider-config-title {
font-size: 18px;
}
.provider-empty-state {
min-height: 260px;
padding: 24px;
}
}
</style>

View File

@@ -311,6 +311,11 @@ const isProviderTesting = (providerId) => props.testingProviders.includes(provid
line-height: 1.3;
}
.provider-models-title-wrap {
min-width: 0;
flex-shrink: 0;
}
.provider-models-subtitle {
display: block;
margin-top: 6px;
@@ -468,4 +473,55 @@ const isProviderTesting = (providerId) => props.testingProviders.includes(provid
.provider-models-empty--small {
min-height: 120px;
}
@media (max-width: 760px) {
.provider-models-toolbar {
align-items: stretch;
flex-direction: column;
}
.provider-models-title-wrap {
flex-shrink: 1;
}
.provider-models-toolbar__actions {
align-items: stretch;
justify-content: stretch;
flex-wrap: wrap;
}
.provider-models-search {
flex: 1 1 100%;
min-width: 0;
max-width: none;
}
.provider-models-toolbar__actions :deep(.v-btn) {
flex: 1 1 160px;
min-width: 0;
}
.provider-models-toolbar__actions :deep(.v-btn__content) {
white-space: normal;
}
}
@media (max-width: 600px) {
.provider-models-panel {
gap: 14px;
}
.provider-model-row {
align-items: stretch;
flex-direction: column;
gap: 10px;
padding: 14px 0;
}
.provider-model-row__actions {
align-self: flex-end;
flex-wrap: wrap;
justify-content: flex-end;
}
}
</style>

View File

@@ -5,40 +5,91 @@
<h3 class="provider-sources-title">{{ tm('providerSources.title') }}</h3>
</div>
<StyledMenu>
<template #activator="{ props }">
<v-btn
v-bind="props"
prepend-icon="mdi-plus"
color="primary"
variant="text"
size="small"
rounded="xl"
>
{{ tm('providerSources.add') }}
</v-btn>
</template>
<v-list-item
v-for="sourceType in availableSourceTypes"
:key="sourceType.value"
class="styled-menu-item"
@click="emitAddSource(sourceType.value)"
<div class="provider-sources-controls">
<div class="provider-sources-mobile-select">
<v-select
:model-value="selectedSourceValue"
:items="sourceOptions"
item-title="title"
item-value="value"
density="compact"
variant="solo-filled"
flat
hide-details
:placeholder="tm('providerSources.selectHint')"
@update:model-value="selectSourceByValue"
>
<template #prepend>
<v-avatar size="18" rounded="0" class="me-2 provider-source-avatar">
<v-img
v-if="sourceType.icon"
:src="sourceType.icon"
alt="provider icon"
cover
></v-img>
<v-icon v-else size="16">mdi-shape-outline</v-icon>
</v-avatar>
<template #selection="{ item }">
<div class="provider-source-select-value">
<v-avatar size="22" rounded="lg" class="provider-source-avatar">
<v-img
v-if="item.raw.source?.provider"
:src="resolveSourceIcon(item.raw.source)"
alt="provider logo"
cover
></v-img>
<v-icon v-else size="14">mdi-creation</v-icon>
</v-avatar>
<span>{{ item.raw.title }}</span>
</div>
</template>
<template #item="{ props: itemProps, item }">
<v-list-item
v-bind="itemProps"
:subtitle="item.raw.subtitle"
>
<template #prepend>
<v-avatar size="24" rounded="lg" class="provider-source-avatar me-2">
<v-img
v-if="item.raw.source?.provider"
:src="resolveSourceIcon(item.raw.source)"
alt="provider logo"
cover
></v-img>
<v-icon v-else size="14">mdi-creation</v-icon>
</v-avatar>
</template>
</v-list-item>
</template>
</v-select>
</div>
<StyledMenu>
<template #activator="{ props }">
<v-btn
v-bind="props"
prepend-icon="mdi-plus"
color="primary"
variant="text"
size="small"
rounded="xl"
>
{{ tm('providerSources.add') }}
</v-btn>
</template>
<v-list-item-title>{{ sourceType.label }}</v-list-item-title>
</v-list-item>
</StyledMenu>
<v-list-item
v-for="sourceType in availableSourceTypes"
:key="sourceType.value"
class="styled-menu-item"
@click="emitAddSource(sourceType.value)"
>
<template #prepend>
<v-avatar size="18" rounded="0" class="me-2 provider-source-avatar">
<v-img
v-if="sourceType.icon"
:src="sourceType.icon"
alt="provider icon"
cover
></v-img>
<v-icon v-else size="16">mdi-shape-outline</v-icon>
</v-avatar>
</template>
<v-list-item-title>{{ sourceType.label }}</v-list-item-title>
</v-list-item>
</StyledMenu>
</div>
</div>
<div v-if="displayedProviderSources.length > 0" class="provider-sources-list">
@@ -138,9 +189,34 @@ const isActive = (source) => {
const sourceBadge = (source) => source.provider || source.templateKey || 'source'
const sourceValue = (source) => (
source.isPlaceholder ? `template:${source.templateKey}` : `source:${source.id}`
)
const sourceOptions = computed(() =>
props.displayedProviderSources.map((source) => ({
title: props.getSourceDisplayName(source),
subtitle: source.api_base || sourceBadge(source),
value: sourceValue(source),
source
}))
)
const selectedSourceValue = computed(() => {
if (!props.selectedProviderSource) return null
return sourceValue(props.selectedProviderSource)
})
const emitAddSource = (type) => emit('add-provider-source', type)
const emitSelectSource = (source) => emit('select-provider-source', source)
const emitDeleteSource = (source) => emit('delete-provider-source', source)
const selectSourceByValue = (value) => {
const option = sourceOptions.value.find((item) => item.value === value)
if (option?.source) {
emitSelectSource(option.source)
}
}
</script>
<style scoped>
@@ -163,6 +239,13 @@ const emitDeleteSource = (source) => emit('delete-provider-source', source)
min-width: 0;
}
.provider-sources-controls {
display: flex;
align-items: center;
gap: 8px;
min-width: 0;
}
.provider-sources-title {
margin: 0;
font-size: 16px;
@@ -174,6 +257,26 @@ const emitDeleteSource = (source) => emit('delete-provider-source', source)
padding: 8px 20px 16px;
}
.provider-sources-mobile-select {
display: none;
min-width: 0;
flex: 1;
}
.provider-source-select-value {
min-width: 0;
display: inline-flex;
align-items: center;
gap: 8px;
}
.provider-source-select-value span {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.provider-sources-list {
flex: 1;
min-height: 0;
@@ -255,4 +358,39 @@ const emitDeleteSource = (source) => emit('delete-provider-source', source)
color: rgba(var(--v-theme-on-surface), 0.56);
font-size: 13px;
}
@media (max-width: 960px) {
.provider-sources-panel {
height: auto;
}
.provider-sources-head {
padding: 16px 16px 8px;
align-items: stretch;
flex-direction: column;
gap: 10px;
}
.provider-sources-mobile-select {
display: block;
}
.provider-sources-controls {
width: 100%;
}
.provider-sources-list {
display: none;
}
.provider-sources-empty {
min-height: 160px;
}
}
@media (max-width: 600px) {
.provider-sources-controls :deep(.v-btn) {
min-width: max-content;
}
}
</style>

View File

@@ -430,4 +430,49 @@ function closeProviderDrawer() {
height: 100%;
overflow: auto;
}
@media (max-width: 960px) {
.provider-drawer-card {
width: calc(100dvw - 24px);
height: calc(100dvh - 24px);
margin: 12px;
}
}
@media (max-width: 600px) {
.provider-name-text {
max-width: 100%;
}
.provider-drawer-overlay {
align-items: stretch;
justify-content: stretch;
}
.provider-drawer-card {
width: 100dvw;
height: 100dvh;
margin: 0;
border-radius: 0;
}
.provider-drawer-header {
padding: 8px 12px;
}
.provider-drawer-content {
overflow: auto;
}
:deep(.v-overlay__content) {
width: 100dvw;
max-width: 100dvw;
margin: 0;
}
:deep(.v-dialog > .v-overlay__content) {
width: calc(100dvw - 24px);
max-width: calc(100dvw - 24px);
}
}
</style>

View File

@@ -19,7 +19,7 @@ $code-text-color: #111827 !default;
--astrbot-code-color: #{$code-text-color};
}
$body-font-family: 'Roboto', $cjk-sans-fallback, sans-serif !default;
$body-font-family: $cjk-sans-fallback, sans-serif !default;
$heading-font-family: $body-font-family !default;
$btn-font-weight: 400 !default;
$btn-letter-spacing: 0 !default;

View File

@@ -79,14 +79,6 @@ $sizes: (
// font family
body {
.Poppins {
font-family: 'Poppins', $cjk-sans-fallback, sans-serif !important;
}
.Inter {
font-family: 'Inter', $cjk-sans-fallback, sans-serif !important;
}
.Outfit {
font-family: 'Outfit', $cjk-sans-fallback, sans-serif !important;
}

View File

@@ -6,7 +6,7 @@ export const useCustomizerStore = defineStore("customizer", {
Sidebar_drawer: config.Sidebar_drawer,
Customizer_drawer: config.Customizer_drawer,
mini_sidebar: config.mini_sidebar,
fontTheme: "Poppins",
fontTheme: "Noto Sans SC",
uiTheme: config.uiTheme,
inputBg: config.inputBg,
chatSidebarOpen: false // chat mode mobile sidebar state

View File

@@ -840,8 +840,14 @@ function goToConfigPage() {
}
@media (max-width: 960px) {
.provider-page {
padding: 12px;
padding-bottom: 32px;
}
.provider-workbench {
grid-template-columns: 1fr;
grid-template-rows: auto 1px auto;
min-height: auto;
}
@@ -851,11 +857,62 @@ function goToConfigPage() {
.provider-config-header {
flex-direction: column;
align-items: flex-start;
align-items: stretch;
padding: 16px;
}
.provider-config-actions :deep(.v-btn) {
width: 100%;
}
.provider-section {
padding: 16px;
}
}
@media (max-width: 600px) {
.provider-page {
padding: 8px;
padding-bottom: 24px;
}
.provider-page :deep(.v-container) > .v-row:first-child {
margin: 0;
padding: 8px 4px 16px !important;
}
.provider-page :deep(.v-container) > .v-row:first-child > div {
width: 100%;
}
.provider-page :deep(.v-container) > .v-row:first-child .v-btn {
width: 100%;
}
.provider-page :deep(.v-tabs) {
overflow-x: auto;
}
.provider-workbench {
border-radius: 16px;
overflow: visible;
}
.provider-workbench__main {
overflow: visible;
}
.provider-config-body {
overflow-y: visible;
}
.provider-config-title {
font-size: 18px;
}
.provider-empty-state {
min-height: 260px;
padding: 24px;
}
}
</style>