Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/web/src/components/chat/chat-step/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<section
class="inline-flex items-center ml-1 gap-1 text-xs text-muted-foreground"
>
<i class="w-1.25 aspect-square bg-blue-500 rounded-full" />
<i class="w-1.25 aspect-square bg-info rounded-full" />
推理中
</section>
</template>
</template>
10 changes: 5 additions & 5 deletions apps/web/src/components/context-window-badge/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ const formatted = computed(() => {

const badgeClass = computed(() => {
const ctx = props.contextWindow ?? 0
if (ctx >= 1_000_000) return 'bg-violet-50 text-violet-700 dark:bg-violet-950 dark:text-violet-300'
if (ctx >= 100_000) return 'bg-emerald-50 text-emerald-700 dark:bg-emerald-950 dark:text-emerald-300'
if (ctx >= 32_000) return 'bg-sky-50 text-sky-700 dark:bg-sky-950 dark:text-sky-300'
if (ctx >= 8_000) return 'bg-amber-50 text-amber-700 dark:bg-amber-950 dark:text-amber-300'
return 'bg-neutral-100 text-neutral-600 dark:bg-neutral-800 dark:text-neutral-400'
if (ctx >= 1_000_000) return 'bg-context-window-xl text-context-window-foreground'
if (ctx >= 100_000) return 'bg-context-window-lg text-context-window-foreground'
if (ctx >= 32_000) return 'bg-context-window-md text-context-window-foreground'
if (ctx >= 8_000) return 'bg-context-window-sm text-context-window-foreground'
return 'bg-context-window-xs text-muted-foreground'
})
</script>
2 changes: 1 addition & 1 deletion apps/web/src/components/file-manager/file-list.vue
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ function handleClick(entry: HandlersFsFileInfo) {
<div class="flex flex-1 items-center gap-2 min-w-0">
<component
:is="entry.isDir ? Folder : File"
:class="entry.isDir ? 'text-blue-500' : 'text-muted-foreground'"
:class="entry.isDir ? 'text-info' : 'text-muted-foreground'"
class="size-4 shrink-0"
/>
<span class="truncate">{{ entry.name }}</span>
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/components/file-manager/file-viewer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ onBeforeUnmount(() => {
v-if="isText"
type="button"
size="sm"
class="absolute top-2 right-2 z-10 gap-1.5 bg-[#8B56E3] text-white shadow-md hover:bg-[#7c47d6] disabled:bg-[#8B56E3]/40 disabled:text-white/80"
class="absolute top-2 right-2 z-10 gap-1.5 bg-primary text-primary-foreground shadow-md hover:bg-brand-hover disabled:bg-primary/40 disabled:text-primary-foreground/80"
:disabled="!isDirty || saving"
:title="t('bots.files.save')"
@click="handleSave"
Expand Down
8 changes: 4 additions & 4 deletions apps/web/src/components/model-capabilities/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ const ICONS: Record<string, Component> = {
}

const CLASSES: Record<string, string> = {
'tool-call': 'bg-blue-50 text-blue-700 dark:bg-blue-950 dark:text-blue-300',
'vision': 'bg-purple-50 text-purple-700 dark:bg-purple-950 dark:text-purple-300',
'image-output': 'bg-pink-50 text-pink-700 dark:bg-pink-950 dark:text-pink-300',
'reasoning': 'bg-amber-50 text-amber-700 dark:bg-amber-950 dark:text-amber-300',
'tool-call': 'bg-capability-tool-soft text-capability-tool-foreground',
'vision': 'bg-capability-vision-soft text-capability-vision-foreground',
'image-output': 'bg-capability-image-soft text-capability-image-foreground',
'reasoning': 'bg-capability-reasoning-soft text-capability-reasoning-foreground',
}

function iconOf(cap: string): Component {
Expand Down
5 changes: 3 additions & 2 deletions apps/web/src/components/settings-sidebar/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
:tooltip="item.title"
:is-active="isItemActive(item.name)"
:aria-current="isItemActive(item.name) ? 'page' : undefined"
class="h-9 gap-2 relative before:absolute before:w-0.5 before:top-1.5 before:bottom-1.5 before:left-0 before:rounded-full data-[active=true]:before:bg-[#8B56E3] group-data-[collapsible=icon]:justify-center group-data-[collapsible=icon]:px-0"
class="h-9 gap-2 relative before:absolute before:w-0.5 before:top-1.5 before:bottom-1.5 before:left-0 before:rounded-full data-[active=true]:before:bg-sidebar-primary group-data-[collapsible=icon]:justify-center group-data-[collapsible=icon]:px-0"
@click="router.push({ name: item.name })"
>
<component
Expand All @@ -63,7 +63,7 @@ import { computed, inject, type Component } from 'vue'
import { storeToRefs } from 'pinia'
import { useRouter, useRoute } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { ChevronLeft, Bot, Boxes, Globe, Brain, Volume2, AudioLines, Mail, ChartLine, User, Store, Info } from 'lucide-vue-next'
import { ChevronLeft, Bot, Boxes, Globe, Brain, Volume2, AudioLines, Mail, ChartLine, User, Store, Info, Palette } from 'lucide-vue-next'
import { useChatSelectionStore } from '@/store/chat-selection'
import {
Sidebar,
Expand Down Expand Up @@ -120,6 +120,7 @@ const allNavItems: { title: string; name: string; icon: Component }[] = [
{ title: t('sidebar.email'), name: 'email', icon: Mail },
{ title: t('sidebar.supermarket'), name: 'supermarket', icon: Store },
{ title: t('sidebar.usage'), name: 'usage', icon: ChartLine },
{ title: t('sidebar.appearance'), name: 'appearance', icon: Palette },
{ title: t('sidebar.profile'), name: 'profile', icon: User },
{ title: t('sidebar.about'), name: 'about', icon: Info },
]
Expand Down
6 changes: 3 additions & 3 deletions apps/web/src/components/status-dot/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ const props = withDefaults(defineProps<{

const colorClass = computed(() => {
switch (props.status) {
case 'success': return 'bg-green-500'
case 'error': return 'bg-red-500'
case 'warning': return 'bg-yellow-500'
case 'success': return 'bg-success'
case 'error': return 'bg-destructive'
case 'warning': return 'bg-warning'
default: return 'bg-muted-foreground'
}
})
Expand Down
47 changes: 47 additions & 0 deletions apps/web/src/constants/color-schemes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
export const colorSchemeIds = ['memoh', 'ocean', 'forest', 'rose', 'amber'] as const

export type ColorSchemeId = typeof colorSchemeIds[number]

export interface ColorSchemeOption {
id: ColorSchemeId
labelKey: string
descriptionKey: string
swatches: string[]
}

export const colorSchemes: ColorSchemeOption[] = [
{
id: 'memoh',
labelKey: 'settings.appearance.colorSchemes.memoh',
descriptionKey: 'settings.appearance.colorSchemeDescriptions.memoh',
swatches: ['oklch(0.22 0.006 286)', 'oklch(0.985 0.001 286)', 'oklch(0.967 0.001 286.375)', 'oklch(0.92 0.004 286.32)', 'oklch(0.55 0.22 290)', 'oklch(0.62 0.16 150)', 'oklch(0.72 0.15 75)', 'oklch(0.60 0.19 355)'],
},
{
id: 'ocean',
labelKey: 'settings.appearance.colorSchemes.ocean',
descriptionKey: 'settings.appearance.colorSchemeDescriptions.ocean',
swatches: ['oklch(0.22 0.006 286)', 'oklch(0.985 0.001 286)', 'oklch(0.967 0.001 286.375)', 'oklch(0.92 0.004 286.32)', 'oklch(0.56 0.15 230)', 'oklch(0.62 0.14 170)', 'oklch(0.72 0.14 80)', 'oklch(0.60 0.17 345)'],
},
{
id: 'forest',
labelKey: 'settings.appearance.colorSchemes.forest',
descriptionKey: 'settings.appearance.colorSchemeDescriptions.forest',
swatches: ['oklch(0.22 0.006 286)', 'oklch(0.985 0.001 286)', 'oklch(0.967 0.001 286.375)', 'oklch(0.92 0.004 286.32)', 'oklch(0.50 0.14 150)', 'oklch(0.58 0.15 145)', 'oklch(0.72 0.14 80)', 'oklch(0.58 0.16 20)'],
},
{
id: 'rose',
labelKey: 'settings.appearance.colorSchemes.rose',
descriptionKey: 'settings.appearance.colorSchemeDescriptions.rose',
swatches: ['oklch(0.22 0.006 286)', 'oklch(0.985 0.001 286)', 'oklch(0.967 0.001 286.375)', 'oklch(0.92 0.004 286.32)', 'oklch(0.58 0.18 355)', 'oklch(0.62 0.14 155)', 'oklch(0.72 0.14 75)', 'oklch(0.58 0.14 250)'],
},
{
id: 'amber',
labelKey: 'settings.appearance.colorSchemes.amber',
descriptionKey: 'settings.appearance.colorSchemeDescriptions.amber',
swatches: ['oklch(0.22 0.006 286)', 'oklch(0.985 0.001 286)', 'oklch(0.967 0.001 286.375)', 'oklch(0.92 0.004 286.32)', 'oklch(0.62 0.15 70)', 'oklch(0.58 0.14 145)', 'oklch(0.70 0.15 75)', 'oklch(0.56 0.14 230)'],
},
]

export function isColorSchemeId(value: string): value is ColorSchemeId {
return colorSchemeIds.includes(value as ColorSchemeId)
}
23 changes: 23 additions & 0 deletions apps/web/src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"mcp": "MCP",
"platform": "Platform",
"usage": "Usage",
"appearance": "Appearance",
"supermarket": "Supermarket",
"about": "About"
},
Expand Down Expand Up @@ -114,6 +115,28 @@
"themePlaceholder": "Select theme",
"themeLight": "Light",
"themeDark": "Dark",
"appearance": {
"title": "Appearance",
"description": "Adjust language, theme, and the semantic color palette used across Memoh.",
"interface": "Interface",
"interfaceDescription": "These preferences apply immediately and are stored on this device.",
"colorScheme": "Color scheme",
"colorSchemeDescription": "Choose a palette for base, brand, status, event, chart, terminal, and diff colors.",
"colorSchemes": {
"memoh": "Memoh",
"ocean": "Ocean",
"forest": "Forest",
"rose": "Rose",
"amber": "Amber"
},
"colorSchemeDescriptions": {
"memoh": "The default restrained purple palette.",
"ocean": "Cool blue with clear info states.",
"forest": "Green-focused and quiet.",
"rose": "Warm rose accents with soft contrast.",
"amber": "Golden highlights with practical status colors."
}
},
"langZh": "中文",
"langEn": "English",
"version": "Version",
Expand Down
23 changes: 23 additions & 0 deletions apps/web/src/i18n/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"mcp": "MCP",
"platform": "接入平台",
"usage": "用量统计",
"appearance": "外观",
"supermarket": "市场",
"about": "关于"
},
Expand Down Expand Up @@ -110,6 +111,28 @@
"themePlaceholder": "选择主题",
"themeLight": "浅色",
"themeDark": "深色",
"appearance": {
"title": "外观",
"description": "调整语言、主题,以及 Memoh 全局使用的语义化配色。",
"interface": "界面",
"interfaceDescription": "这些偏好会立即生效,并保存在当前设备上。",
"colorScheme": "配色方案",
"colorSchemeDescription": "选择基础、品牌、状态、事件、图表、终端和 diff 颜色使用的调色盘。",
"colorSchemes": {
"memoh": "Memoh",
"ocean": "海洋",
"forest": "森林",
"rose": "玫瑰",
"amber": "琥珀"
},
"colorSchemeDescriptions": {
"memoh": "默认的克制紫色方案。",
"ocean": "冷静蓝色,信息状态更清晰。",
"forest": "以绿色为核心,更安静稳重。",
"rose": "温暖玫瑰色,保持柔和对比。",
"amber": "金色强调,搭配实用状态色。"
}
},
"langZh": "中文",
"langEn": "English",
"version": "版本",
Expand Down
60 changes: 4 additions & 56 deletions apps/web/src/pages/about/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,15 @@
v-if="checkResult.isUpToDate"
class="flex items-center gap-2 text-xs text-muted-foreground"
>
<CircleCheck class="size-3.5 text-green-500" />
<CircleCheck class="size-3.5 text-success" />
{{ $t('about.upToDate') }}
</div>

<template v-else>
<Separator />

<div class="flex items-center gap-2">
<Badge class="bg-[#8B56E3] text-white hover:bg-[#8B56E3]/90">
<Badge class="bg-primary text-primary-foreground hover:bg-primary/90">
{{ $t('about.newVersionAvailable', { version: checkResult.latestVersion }) }}
</Badge>
</div>
Expand All @@ -85,55 +85,6 @@

<section>
<Separator class="mb-4" />
<div class="grid grid-cols-[1fr_auto_1fr] gap-4 px-3 mb-3">
<div class="flex items-center gap-2">
<Globe class="size-3.5 shrink-0 text-muted-foreground" />
<span class="flex-1 text-xs">{{ $t('settings.language') }}</span>
<Select
:model-value="language"
@update:model-value="(v) => v && setLanguage(v as Locale)"
>
<SelectTrigger
class="w-24"
:aria-label="$t('settings.language')"
>
<SelectValue :placeholder="$t('settings.languagePlaceholder')" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="zh">
{{ $t('settings.langZh') }}
</SelectItem>
<SelectItem value="en">
{{ $t('settings.langEn') }}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
<Separator orientation="vertical" />
<div class="flex items-center gap-2">
<span class="flex-1 text-xs">{{ $t('settings.theme') }}</span>
<div class="flex h-9 items-center rounded-md border border-input p-1">
<button
class="flex size-7 items-center justify-center rounded-sm transition-colors"
:class="theme === 'light' ? 'bg-accent text-accent-foreground' : 'text-muted-foreground hover:text-foreground'"
:aria-label="$t('settings.themeLight')"
@click="setTheme('light')"
>
<Sun class="size-4" />
</button>
<button
class="flex size-7 items-center justify-center rounded-sm transition-colors"
:class="theme === 'dark' ? 'bg-accent text-accent-foreground' : 'text-muted-foreground hover:text-foreground'"
:aria-label="$t('settings.themeDark')"
@click="setTheme('dark')"
>
<Moon class="size-4" />
</button>
</div>
</div>
</div>
<div class="space-y-1">
<a
href="https://github.com/memohai/memoh"
Expand Down Expand Up @@ -176,12 +127,11 @@ import { computed, ref, onMounted } from 'vue'
import { storeToRefs } from 'pinia'
import { useI18n } from 'vue-i18n'
import { toast } from 'vue-sonner'
import { RefreshCw, ExternalLink, Github, BookOpen, MessageSquare, CircleCheck, Globe, Sun, Moon } from 'lucide-vue-next'
import { Badge, Button, Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, Separator, Spinner } from '@memohai/ui'
import { RefreshCw, ExternalLink, Github, BookOpen, MessageSquare, CircleCheck } from 'lucide-vue-next'
import { Badge, Button, Separator, Spinner } from '@memohai/ui'
import MarkdownRender from 'markstream-vue'
import { useCapabilitiesStore } from '@/store/capabilities'
import { useSettingsStore } from '@/store/settings'
import type { Locale } from '@/i18n'

const GITHUB_REPO = 'memohai/memoh'

Expand All @@ -200,8 +150,6 @@ const normalizeVersion = (version?: string | null) => (version ?? '').replace(/^
const normalizedServerVersion = computed(() => normalizeVersion(serverVersion.value))

const settingsStore = useSettingsStore()
const { language, theme } = storeToRefs(settingsStore)
const { setLanguage, setTheme } = settingsStore
const isDark = computed(() => settingsStore.theme === 'dark')

const checking = ref(false)
Expand Down
Loading
Loading