refined colors, added multiple color themes, and added window control titlebar

This commit is contained in:
2026-01-18 20:31:40 +01:00
parent a4c6e0661b
commit 4ff3e30348
28 changed files with 526 additions and 117 deletions

View File

@@ -17,6 +17,7 @@
"@tauri-apps/plugin-fs": "~2",
"@tauri-apps/plugin-http": "~2",
"@tauri-apps/plugin-opener": "^2",
"@tauri-apps/plugin-os": "~2",
"@tauri-apps/plugin-store": "~2",
"@tauri-apps/plugin-upload": "~2",
"@tauri-apps/plugin-websocket": "~2",

83
src-tauri/Cargo.lock generated
View File

@@ -1028,6 +1028,7 @@ dependencies = [
"tauri-plugin-fs",
"tauri-plugin-http",
"tauri-plugin-opener",
"tauri-plugin-os",
"tauri-plugin-store",
"tauri-plugin-upload",
"tauri-plugin-websocket",
@@ -1263,6 +1264,16 @@ dependencies = [
"version_check",
]
[[package]]
name = "gethostname"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8"
dependencies = [
"rustix",
"windows-link 0.2.1",
]
[[package]]
name = "getrandom"
version = "0.1.16"
@@ -2315,6 +2326,16 @@ dependencies = [
"objc2-foundation",
]
[[package]]
name = "objc2-core-location"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009"
dependencies = [
"objc2",
"objc2-foundation",
]
[[package]]
name = "objc2-core-text"
version = "0.3.2"
@@ -2419,8 +2440,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22"
dependencies = [
"bitflags 2.10.0",
"block2",
"objc2",
"objc2-cloud-kit",
"objc2-core-data",
"objc2-core-foundation",
"objc2-core-graphics",
"objc2-core-image",
"objc2-core-location",
"objc2-core-text",
"objc2-foundation",
"objc2-quartz-core",
"objc2-user-notifications",
]
[[package]]
name = "objc2-user-notifications"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e"
dependencies = [
"objc2",
"objc2-foundation",
]
@@ -2474,6 +2514,22 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "os_info"
version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4022a17595a00d6a369236fdae483f0de7f0a339960a53118b818238e132224"
dependencies = [
"android_system_properties",
"log",
"nix",
"objc2",
"objc2-foundation",
"objc2-ui-kit",
"serde",
"windows-sys 0.61.2",
]
[[package]]
name = "pango"
version = "0.18.3"
@@ -3782,6 +3838,15 @@ dependencies = [
"syn 2.0.111",
]
[[package]]
name = "sys-locale"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4"
dependencies = [
"libc",
]
[[package]]
name = "system-configuration"
version = "0.6.1"
@@ -4091,6 +4156,24 @@ dependencies = [
"zbus",
]
[[package]]
name = "tauri-plugin-os"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8f08346c8deb39e96f86973da0e2d76cbb933d7ac9b750f6dc4daf955a6f997"
dependencies = [
"gethostname",
"log",
"os_info",
"serde",
"serde_json",
"serialize-to-javascript",
"sys-locale",
"tauri",
"tauri-plugin",
"thiserror 2.0.17",
]
[[package]]
name = "tauri-plugin-store"
version = "2.4.1"

View File

@@ -28,4 +28,5 @@ tauri-plugin-websocket = "2"
tauri-plugin-upload = "2"
tauri-plugin-dialog = "2"
tauri-plugin-fs = "2"
tauri-plugin-os = "2"

View File

@@ -7,6 +7,12 @@
],
"permissions": [
"core:default",
"core:window:allow-maximize",
"core:window:allow-minimize",
"core:window:allow-close",
"core:window:allow-toggle-maximize",
"core:window:allow-start-dragging",
"core:window:allow-set-fullscreen",
"opener:default",
"store:default",
{
@@ -47,7 +53,7 @@
"allow": [
"*"
]
}
},
"os:default"
]
}

View File

@@ -7,6 +7,7 @@ fn greet(name: &str) -> String {
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_os::init())
.plugin(tauri_plugin_fs::init())
.plugin(tauri_plugin_dialog::init())
.plugin(tauri_plugin_upload::init())

View File

@@ -15,7 +15,7 @@
"title": "frangipane",
"width": 800,
"height": 600,
"decorations": true,
"decorations": false,
"resizable": true,
"fullscreen": false,
"center": true,

View File

@@ -1,16 +1,35 @@
<template>
<div id="page">
<main id="content">
<router-view />
</main>
<VersionWarningModal v-if="showVersionWarningModal" :appVersion="appVersion" :backendVersion="backendVersion"
:expectedBackendVersion="expectedBackendVersion" @close="showVersionWarningModal = false" />
<footer v-if="!$route.meta.hideNavbar">
<Navbar />
</footer>
<div id="page">
<div v-if="currentPlatform != 'android' && currentPlatform != 'ios'" data-tauri-drag-region class="titlebar">
<div class="titlebar-button" @click="minimize">
<svg width="12" height="12" viewBox="0 0 12 12">
<rect fill="currentColor" width="10" height="1" x="1" y="6" />
</svg>
</div>
<div class="titlebar-button" @click="toggleMaximize">
<svg width="12" height="12" viewBox="0 0 12 12">
<rect fill="none" stroke="currentColor" stroke-width="1" width="9" height="9" x="1.5" y="1.5" />
</svg>
</div>
<div class="titlebar-button" id="close-btn" @click="close">
<svg width="12" height="12" viewBox="0 0 12 12">
<path fill="currentColor"
d="M11 1.57L10.43 1 6 5.43 1.57 1 1 1.57 5.43 6 1 10.43 1.57 11 6 6.57 10.43 11 11 10.43 6.57 6z" />
</svg>
</div>
</div>
<main id="content">
<router-view />
</main>
<VersionWarningModal v-if="showVersionWarningModal" :appVersion="appVersion" :backendVersion="backendVersion"
:expectedBackendVersion="expectedBackendVersion" @close="showVersionWarningModal = false" />
<footer v-if="!$route.meta.hideNavbar">
<Navbar />
</footer>
</div>
</template>
<script setup lang="ts">
@@ -19,6 +38,12 @@ import Navbar from './components/Navbar.vue'
import VersionWarningModal from './components/VersionWarningModal.vue'
import { apiFetch } from './api/client'
import { VersionResponse } from './types'
import { getCurrentWindow } from '@tauri-apps/api/window'
import { platform } from '@tauri-apps/plugin-os';
const currentPlatform = ref('')
const appWindow = getCurrentWindow()
const showVersionWarningModal = ref(false)
const backendVersion = ref('')
@@ -26,52 +51,97 @@ const backendVersion = ref('')
const appVersion = __APP_VERSION__
const expectedBackendVersion = __BACKEND_VERSION__
const isFullScreen = ref(false)
onMounted(async () => {
backendVersion.value = (await getBackendVersion()).version
if (backendVersion.value !== expectedBackendVersion) {
showVersionWarningModal.value = true
}
backendVersion.value = (await getBackendVersion()).version
if (backendVersion.value !== expectedBackendVersion) {
showVersionWarningModal.value = true
}
currentPlatform.value = platform()
})
const minimize = () => appWindow.minimize()
const toggleMaximize = () => {
appWindow.setFullscreen(!isFullScreen.value)
isFullScreen.value = !isFullScreen.value
}
const close = () => appWindow.close()
async function getBackendVersion() {
return await apiFetch<VersionResponse>('/version')
return await apiFetch<VersionResponse>('/version')
}
</script>
<style scoped>
#page {
background: var(--bg);
height: 100dvh;
display: flex;
flex-direction: column;
align-items: center;
background: var(--bg);
height: 100dvh;
display: flex;
flex-direction: column;
align-items: center;
}
#content {
width: 100%;
max-width: 1100px;
padding: 2rem;
width: 100%;
max-width: 1100px;
/* padding: 2rem; */
padding: calc(20px + 2rem) 2rem 2rem 2rem;
flex: 1;
overflow-y: auto;
flex: 1;
overflow-y: auto;
}
.titlebar {
height: 30px;
background: var(--panel);
user-select: none;
display: flex;
justify-content: flex-end;
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 9999;
}
.titlebar-button {
display: inline-flex;
justify-content: center;
align-items: center;
width: 45px;
height: 30px;
transition: background-color 0.2s;
color: var(--text-color);
cursor: pointer;
}
.titlebar-button:hover {
background: var(--panel-accent)
}
#close-btn:hover {
background: #e81123;
color: white;
}
footer {
width: 100%;
display: flex;
justify-content: center;
padding-bottom: 24px;
background: var(--bg);
width: 100%;
display: flex;
justify-content: center;
padding-bottom: 24px;
background: var(--bg);
}
@media (max-width: 720px) {
#content {
padding: 12px;
padding-top: 30px;
}
#content {
padding: 12px;
padding-top: 30px;
}
footer {
padding-bottom: 56px;
}
footer {
padding-bottom: 56px;
}
}
</style>

View File

@@ -16,6 +16,7 @@ body,
overflow-y: hidden;
}
/* This is overwritten by the theme configuration */
:root {
--bg: #0f1116;
--panel: #171922;
@@ -23,6 +24,7 @@ body,
--text: #e6e6eb;
--muted: #9aa0aa;
--accent: #f27aa3;
--accent-rgb: 242, 122, 163;
--accent-hover: #ff91b3;
--accent-second: #96CDFB;
--border: #2a2f3b;
@@ -30,6 +32,10 @@ body,
--radius: 8px;
}
* {
transition: background-color 0.2s ease, border-color 0.2s ease;
}
body {
font-family: system-ui, -apple-system, BlinkMacSystemFont,
"Segoe UI", sans-serif;
@@ -59,7 +65,8 @@ input:focus, textarea:focus {
button, .button {
font-size: 1rem;
background: var(--accent);
color: #0b0d12;
color: var(--bg);
/* color: var(--btn-text); */
border: none;
border-radius: var(--radius);
padding: 0.6rem 1rem;
@@ -74,6 +81,19 @@ button:hover, .button:hover {
background: var(--accent-hover);
}
.secondary {
background: transparent;
color: var(--text);
border: 1px solid var(--border);
padding: 8px 16px;
border-radius: var(--radius);
cursor: pointer;
}
.secondary:hover {
background: var(--panel-hover);
}
input[type="checkbox"] {
appearance: none;
-webkit-appearance: none;

View File

@@ -347,7 +347,7 @@ async function onSend(content: string) {
border-radius: var(--radius);
border: none;
background: transparent;
color: white;
color: var(--text);
cursor: pointer;
font-size: 1.6rem;
@@ -386,7 +386,7 @@ async function onSend(content: string) {
}
.retry-btn:hover {
background: rgba(255, 255, 255, 0.05);
background: var(--panel-hover);
}
.no-room {

View File

@@ -76,15 +76,6 @@ const emit = defineEmits(['yes', 'no']);
color: var(--text);
}
.secondary {
cursor: pointer;
padding: 8px 16px;
border-radius: var(--radius);
background: transparent;
color: var(--text);
border: 1px solid var(--border);
}
.btn-danger {
border-color: var(--error);
color: var(--error);

View File

@@ -92,14 +92,4 @@ async function submit() {
justify-content: flex-end;
gap: 0.5rem;
}
.secondary {
background: transparent;
color: var(--text);
border: 1px solid var(--border);
}
.secondary:hover {
background: rgba(255, 255, 255, 0.05);
}
</style>

View File

@@ -120,14 +120,4 @@ async function submit() {
justify-content: flex-end;
gap: 0.5rem;
}
.secondary {
background: transparent;
color: var(--text);
border: 1px solid var(--border);
}
.secondary:hover {
background: rgba(255, 255, 255, 0.05);
}
</style>

View File

@@ -76,7 +76,7 @@ onMounted(() => {
top: 4px;
right: 4px;
background-color: var(--accent);
color: black;
color: var(--bg);
font-size: 0.65rem;
font-weight: bold;
min-width: 18px;
@@ -92,7 +92,7 @@ onMounted(() => {
@media (hover: hover) {
.nav-item:hover {
background: rgba(255, 255, 255, 0.04);
background: var(--panel-hover);
}
.nav-item:not(.router-link-active):hover i {

View File

@@ -205,15 +205,6 @@ const handleAvatarError = (event: Event) => {
gap: 0.5rem;
}
.secondary {
background: transparent;
color: var(--text);
border: 1px solid var(--border);
padding: 8px 16px;
border-radius: var(--radius);
cursor: pointer;
}
.member-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));

View File

@@ -138,7 +138,7 @@ onMounted(async () => {
}
.retry-btn:hover {
background: rgba(255, 255, 255, 0.05);
background: var(--panel-hover);
}
.room-content-wrapper {
@@ -150,7 +150,7 @@ onMounted(async () => {
.unread-badge {
background-color: var(--accent);
color: black;
color: var(--bg);
font-size: 0.75rem;
font-weight: bold;
min-width: 20px;
@@ -193,7 +193,7 @@ onMounted(async () => {
}
.room-item:hover {
background: rgba(255, 255, 255, 0.05);
background: var(--panel-hover);
color: var(--text);
}
@@ -236,6 +236,6 @@ onMounted(async () => {
}
.create-btn:hover {
background: rgba(255, 255, 255, 0.05);
background: var(--panel-hover);
}
</style>

View File

@@ -112,7 +112,6 @@ async function submit() {
display: flex;
flex-direction: column;
gap: 1.2rem;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
}
.subtitle {
@@ -154,10 +153,4 @@ button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.secondary {
background: transparent;
color: var(--text);
border: 1px solid var(--border);
}
</style>

View File

@@ -202,7 +202,7 @@ async function handleUpload() {
text-align: center;
cursor: pointer;
transition: all 0.2s ease;
background: rgba(255, 255, 255, 0.02);
background: var(--panel-accent);
min-height: 180px;
display: flex;
align-items: center;
@@ -221,7 +221,7 @@ async function handleUpload() {
.drop-zone:hover {
border-color: var(--accent);
background: rgba(255, 255, 255, 0.05);
background: var(--panel-hover);
}
.drop-content i {
@@ -299,10 +299,4 @@ async function handleUpload() {
justify-content: flex-end;
gap: 0.5rem;
}
.secondary {
background: transparent;
color: var(--text);
border: 1px solid var(--border);
}
</style>

View File

@@ -49,10 +49,4 @@ const emit = defineEmits(['close']);
justify-content: flex-end;
gap: 0.5rem;
}
.secondary {
background: transparent;
color: var(--text);
border: 1px solid var(--border);
}
</style>

View File

@@ -79,6 +79,7 @@ settings-loading = Loading settings...
settings-title = Settings
settings-account = Account
settings-language = Language
settings-appearance = Appearance
settings-label-username = Username:
settings-label-email = Email:
settings-update-btn = Update

View File

@@ -79,6 +79,7 @@ settings-loading = Chargement des paramètres...
settings-title = Paramètres
settings-account = Compte
settings-language = Langue
settings-appearance = Apparence
settings-label-username = Nom d'utilisateur :
settings-label-email = Email :
settings-update-btn = Modifier

View File

@@ -1,7 +1,7 @@
import { createApp } from 'vue'
import router from './router.ts'
import App from './App.vue'
import { validateToken } from './store.ts'
import { validateToken, initTheme } from './store.ts'
import { fluent, setLanguage } from './i18n'
import './base.css'
@@ -17,6 +17,8 @@ async function init() {
const savedLocale = await getLocalePreference();
const osLocale = navigator.language;
await initTheme();
if (savedLocale) {
setLanguage(savedLocale);
} else {

View File

@@ -152,7 +152,7 @@ const handleNotification = (roomUuid: string) => {
.sidebar-overlay {
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.3);
/* background: rgba(0, 0, 0, 0.3); */
z-index: 15;
}

View File

@@ -182,7 +182,7 @@ async function declineRoom(senderUuid: string, roomUuid: string) {
}
.decline-btn:hover {
background-color: rgba(255, 255, 255, 0.05);
background-color: var(--panel-hover);
}
@media (max-width: 720px) {

View File

@@ -38,6 +38,14 @@
</div>
</div>
<h2>{{ $t('settings-appearance') || 'Appearance' }}</h2>
<div class="theme-grid">
<button v-for="theme in availableThemes" :key="theme.id" class="theme-btn"
:class="{ active: currentTheme === theme.id }" @click="changeTheme(theme.id)">
{{ theme.name }}
</button>
</div>
<button class="logout-btn" @click="logout">
<i class="fa-solid fa-right-from-bracket"></i>
<span>{{ $t('settings-logout-btn') }}</span>
@@ -49,6 +57,7 @@
import { ref, onMounted, computed } from 'vue'
import { useRouter } from 'vue-router'
import { logout as authLogout } from '../store.ts'
import { saveThemePreference, getThemePreference } from "../store.ts"
import { getAuthData } from "../store.ts"
import type { User } from "../types"
import UpdateAccountModal from '../components/UpdateAccountModal.vue'
@@ -58,6 +67,7 @@ import { getSupportedLanguagesMetadata, setLanguage } from '../i18n'
import UploadAvatarModal from '../components/UploadAvatarModal.vue'
import defaultAvatar from '../assets/default-avatar.png'
import { getAvatarUrl } from '../store.ts'
import { getAvailableThemes } from '../themeLoader';
const handleAvatarError = (event: Event) => {
const img = event.target as HTMLImageElement;
@@ -73,6 +83,8 @@ const { $t } = useFluent()
const currentLang = ref('')
const languages = computed(() => getSupportedLanguagesMetadata())
const currentTheme = ref('default');
const availableThemes = getAvailableThemes();
async function fetchUserData() {
try {
@@ -85,8 +97,8 @@ async function fetchUserData() {
onMounted(async () => {
const pref = await getLocalePreference()
// Synchronize the UI state with the actual active language
currentLang.value = pref || (navigator.language.split('-')[0])
currentTheme.value = await getThemePreference()
fetchUserData()
})
@@ -97,6 +109,11 @@ async function changeLanguage(code: string) {
await saveLocalePreference(actual)
}
async function changeTheme(theme: string) {
currentTheme.value = theme
await saveThemePreference(theme)
}
function logout() {
authLogout()
router.push('/login')
@@ -171,12 +188,44 @@ h2 {
margin: 0;
}
.lang-btn:hover:not(.active) {
background: rgba(var(--accent-rgb), 0.1);
border-color: var(--accent);
}
.lang-btn.active {
background: var(--accent);
color: #000;
border-color: var(--accent);
}
.theme-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
gap: 0.5rem;
margin-top: 0.5rem;
}
.theme-btn {
background: var(--panel);
border: 1px solid var(--border);
color: var(--text);
margin: 0;
padding: 12px;
font-size: 0.9rem;
}
.theme-btn.active {
background: var(--accent);
color: var(--bg);
border-color: var(--accent);
}
.theme-btn:hover:not(.active) {
background: rgba(var(--accent-rgb), 0.1);
border-color: var(--accent);
}
.logout-btn {
cursor: pointer;
display: flex;
@@ -193,11 +242,11 @@ h2 {
}
.logout-btn:hover {
color: rgba(255, 80, 80, 0.8);
color: var(--error);
}
.logout-btn:hover i {
color: rgba(255, 80, 80, 0.8);
color: var(--error);
}
.logout-btn i {

View File

@@ -8,6 +8,7 @@ import { load, Store } from '@tauri-apps/plugin-store'
import { UpdateUserResponse } from './types'
import { reactive } from 'vue'
import { API } from './main'
import { applyTheme } from './themeLoader.ts';
let store: Store | null = null
export const initAuth = getAuthData
@@ -184,3 +185,28 @@ export function getAvatarUrl(uuid: string | undefined | null) {
export function refreshAvatar(uuid: string) {
avatarTimestamps[uuid] = Date.now()
}
// ==== Color themes ====
export async function saveThemePreference(themeId: string) {
const s = await getStore();
await s.set('theme', themeId);
await s.save();
applyTheme(themeId);
}
export async function initTheme() {
const s = await getStore();
const themeId = (await s.get<string>('theme')) || 'default';
applyTheme(themeId);
}
export async function getThemePreference(): Promise<string> {
const s = await getStore()
return (await s.get<string>('theme')) ?? 'default'
}
export async function applyStoredTheme() {
const theme = await getThemePreference();
document.documentElement.setAttribute('data-theme', theme);
}

26
src/themeLoader.ts Normal file
View File

@@ -0,0 +1,26 @@
import themes from './themes.json';
export type ThemeKey = keyof typeof themes;
export function applyTheme(themeKey: string) {
const theme = (themes as any)[themeKey] || themes.default;
const root = document.documentElement;
// Convert json keys to css Variables
Object.entries(theme.colors).forEach(([key, value]) => {
root.style.setProperty(`--${key}`, value as string);
});
// if (themeKey.includes('light')) {
// root.style.setProperty('--btn-text', theme.colors.bg);
// } else {
// root.style.setProperty('--btn-text', '#0b0d12');
// }
}
export function getAvailableThemes() {
return Object.entries(themes).map(([id, data]) => ({
id,
name: data.name
}));
}

172
src/themes.json Normal file
View File

@@ -0,0 +1,172 @@
{
"frangipane-dark": {
"name": "Frangipane Dark",
"colors": {
"bg": "#0f1116",
"panel": "#171922",
"panel-accent": "#12141B",
"panel-hover": "#22242D",
"text": "#e6e6eb",
"muted": "#9aa0aa",
"accent": "#f27aa3",
"accent-rgb": "242, 122, 163",
"accent-hover": "#ff91b3",
"accent-second": "#96CDFB",
"border": "#2a2f3b",
"error": "#ff5050"
}
},
"catppuccin-latte": {
"name": "Catppuccin Latte",
"colors": {
"bg": "#eff1f5",
"panel": "#e6e9ef",
"panel-hover": "#bcc0cc",
"panel-accent": "#ccd0da",
"text": "#4c4f69",
"muted": "#7c7f93",
"accent": "#ea76cb",
"accent-rgb": "234, 118, 203",
"accent-hover": "#d20f39",
"accent-second": "#1e66f5",
"border": "#dce0e8",
"error": "#d20f39"
}
},
"catppuccin-frappe": {
"name": "Catppuccin Frappé",
"colors": {
"bg": "#303446",
"panel": "#292c3c",
"panel-accent": "#232634",
"panel-hover": "#414559",
"text": "#c6d0f5",
"muted": "#838ba7",
"accent": "#a6d189",
"accent-rgb": "166, 209, 137",
"accent-hover": "#81c8be",
"accent-second": "#f2d5cf",
"border": "#414559",
"error": "#e78284"
}
},
"catppuccin-macchiato": {
"name": "Catppuccin Macchiato",
"colors": {
"bg": "#24273a",
"panel": "#1e2030",
"panel-accent": "#181926",
"panel-hover": "#363a4f",
"text": "#cad3f5",
"muted": "#8087a2",
"accent": "#c6a0f6",
"accent-rgb": "198, 160, 246",
"accent-hover": "#f5bde6",
"accent-second": "#8aadf4",
"border": "#494d64",
"error": "#ed8796"
}
},
"catppuccin-mocha": {
"name": "Catppuccin Mocha",
"colors": {
"bg": "#1e1e2e",
"panel": "#181825",
"panel-accent": "#11111b",
"panel-hover": "#313244",
"text": "#cdd6f4",
"muted": "#7f849c",
"accent": "#89b4fa",
"accent-rgb": "137, 180, 250",
"accent-hover": "#89dceb",
"accent-second": "#f5c2e7",
"border": "#313244",
"error": "#f38ba8"
}
},
"nord": {
"name": "Nordic",
"colors": {
"bg": "#2e3440",
"panel": "#3b4252",
"panel-accent": "#242933",
"panel-hover": "#434c5e",
"text": "#eceff4",
"muted": "#d8dee9",
"accent": "#88c0d0",
"accent-rgb": "136, 192, 208",
"accent-hover": "#8fbcbb",
"accent-second": "#81a1c1",
"border": "#4c566a",
"error": "#bf616a"
}
},
"tokyo-night": {
"name": "Tokyo Night",
"colors": {
"bg": "#1a1b26",
"panel": "#16161e",
"panel-accent": "#1f2335",
"panel-hover": "#292e42",
"text": "#a9b1d6",
"muted": "#565f89",
"accent": "#7aa2f7",
"accent-rgb": "122, 162, 247",
"accent-hover": "#7dcfff",
"accent-second": "#bb9af7",
"border": "#24283b",
"error": "#f7768e"
}
},
"gruvbox-dark": {
"name": "Gruvbox Dark",
"colors": {
"bg": "#282828",
"panel": "#3c3836",
"panel-accent": "#282828",
"panel-hover": "#504945",
"text": "#ebdbb2",
"muted": "#a89984",
"accent": "#fabd2f",
"accent-rgb": "250, 189, 47",
"accent-hover": "#fe8019",
"accent-second": "#b8bb26",
"border": "#504945",
"error": "#fb4934"
}
},
"gruvbox-light": {
"name": "Gruvbox Light",
"colors": {
"bg": "#fbf1c7",
"panel": "#f2e5bc",
"panel-accent": "#d5c4a1",
"panel-hover": "#ebdbb2",
"text": "#3c3836",
"muted": "#7c6f64",
"accent": "#d65d0e",
"accent-rgb": "214, 93, 14",
"accent-hover": "#9d0006",
"accent-second": "#458588",
"border": "#bdae93",
"error": "#cc241d"
}
},
"solarized-dark": {
"name": "Solarized Dark",
"colors": {
"bg": "#002b36",
"panel": "#073642",
"panel-accent": "#00212b",
"panel-hover": "#586e75",
"text": "#839496",
"muted": "#657b83",
"accent": "#268bd2",
"accent-rgb": "38, 139, 210",
"accent-hover": "#2aa198",
"accent-second": "#859900",
"border": "#073642",
"error": "#dc322f"
}
}
}

View File

@@ -430,6 +430,13 @@
dependencies:
"@tauri-apps/api" "^2.8.0"
"@tauri-apps/plugin-os@~2":
version "2.3.2"
resolved "https://registry.yarnpkg.com/@tauri-apps/plugin-os/-/plugin-os-2.3.2.tgz#de916a82d8d955bba59a2ffdba7f7aaa29397246"
integrity sha512-n+nXWeuSeF9wcEsSPmRnBEGrRgOy6jjkSU+UVCOV8YUGKb2erhDOxis7IqRXiRVHhY8XMKks00BJ0OAdkpf6+A==
dependencies:
"@tauri-apps/api" "^2.8.0"
"@tauri-apps/plugin-store@~2":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@tauri-apps/plugin-store/-/plugin-store-2.4.1.tgz#5e2d3362e41861d2fa79a3f1a78c091e12963236"