diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..0c0599de --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,3 @@ +# These are supported funding model platforms + +github: open-webui diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c8bbc44..95d15f22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.7.5] - 2026-07-02 + +### Added + +- 🎨 **Appearance controls.** Added a new Appearance settings page so you can adjust how Computer looks and feels without leaving the app. +- 🌳 **Git worktrees.** View, search, open, and create worktrees from the Git panel so you can keep separate branches in separate folders. + +### Changed + +- 🌍 **More complete language support.** Expanded translations across settings, chat, files, previews, and admin screens so the interface feels more consistent in every supported language. +- 🧩 **Cleaner everyday interface.** Polished menus, dialogs, chat controls, file previews, terminal views, and setup screens for a more consistent experience across desktop and mobile. +- 🌐 **Easier web setup.** Search providers and browser tools now show their keys, base URLs, and helper text in a cleaner layout. + ## [0.7.4] - 2026-06-30 ### Added diff --git a/README.md b/README.md index db9f35b6..11d27b0e 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ ![GitHub top language](https://img.shields.io/github/languages/top/open-webui/computer) ![GitHub last commit](https://img.shields.io/github/last-commit/open-webui/computer?color=red) [![Discord](https://img.shields.io/badge/Discord-Open_WebUI-blue?logo=discord&logoColor=white)](https://discord.gg/5rJgQTnV4s) -[![](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/tjbck) +[![](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/open-webui) ![Open WebUI Computer Demo](./demo.png) @@ -31,6 +31,8 @@ The Docker image includes all optional feature groups. Or with [uv](https://docs.astral.sh/uv/): `uvx cptr@latest run` +On Windows, if opening a terminal reports a missing `VCRUNTIME140.dll` or Universal CRT DLL, install Microsoft's [Visual C++ Redistributable](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist) and restart `cptr`. + Opens in your browser at `http://localhost:8000`. ### Access from your phone diff --git a/cptr/frontend/src/app.css b/cptr/frontend/src/app.css index 5927914d..4b10260c 100644 --- a/cptr/frontend/src/app.css +++ b/cptr/frontend/src/app.css @@ -23,13 +23,26 @@ --color-gray-950: oklch(0.16 0 0); } +:root { + --app-text-scale: 1; + --app-bg: #ffffff; + --app-fg: #525252; + --app-fg-muted: color-mix(in oklab, var(--app-fg) 62%, var(--app-bg)); + --app-fg-subtle: color-mix(in oklab, var(--app-fg) 48%, var(--app-bg)); + --app-border: color-mix(in oklab, var(--app-fg) 10%, transparent); + --app-divider: color-mix(in oklab, var(--app-fg) 8%, transparent); + --app-hover: color-mix(in oklab, var(--app-fg) 6%, transparent); + --app-active: color-mix(in oklab, var(--app-fg) 7%, transparent); + --app-ui-font: var(--font-sans); +} + @layer base { *, ::after, ::before, ::backdrop, ::file-selector-button { - border-color: var(--color-gray-200, currentColor); + border-color: var(--app-border, var(--color-gray-200, currentColor)); } html, @@ -40,6 +53,9 @@ overscroll-behavior: none; scrollbar-width: none; -ms-overflow-style: none; + background: var(--app-bg); + color: var(--app-fg); + font-family: var(--app-ui-font); } html::-webkit-scrollbar, @@ -50,6 +66,7 @@ html { color-scheme: dark light; touch-action: manipulation; + font-size: calc(1rem * var(--app-text-scale, 1)); } button { @@ -62,7 +79,7 @@ --tw-border-opacity: 1; background-color: rgba(215, 215, 215, 0.6); border-color: rgba(255, 255, 255, var(--tw-border-opacity)); - border-radius: 9999px; + border-radius: 624.9375rem; border-width: 1px; } @@ -79,7 +96,7 @@ ::-webkit-scrollbar-track { background-color: transparent; - border-radius: 9999px; + border-radius: 624.9375rem; } .scrollbar-hidden, @@ -99,6 +116,167 @@ visibility: visible; } +.app-theme { + background: var(--app-bg); + color: var(--app-fg); +} + +.app-surface { + background: var(--app-bg); + color: var(--app-fg); + border-color: var(--app-border); +} + +.app-subtle-surface { + background: var(--app-bg); + color: var(--app-fg); + border-color: var(--app-border); +} + +.app-divider { + background: var(--app-divider); +} + +.app-muted { + color: var(--app-fg-muted); +} + +.app-icon-muted { + color: var(--app-fg-subtle); +} + +.app-interactive:hover { + background: var(--app-hover); + color: var(--app-fg); +} + +.app-interactive-active { + background: var(--app-active); + color: var(--app-fg); +} + +.app-theme:where([class*='border-gray-'], [class*='border-black/'], [class*='border-white/']), +.app-theme :where([class*='border-gray-'], [class*='border-black/'], [class*='border-white/']) { + border-color: var(--app-border); +} + +.dark .app-theme:where([class*='dark:border-gray-'], [class*='dark:border-white/']), +.dark .app-theme :where([class*='dark:border-gray-'], [class*='dark:border-white/']) { + border-color: var(--app-border); +} + +.app-theme + :where( + [class*='divide-gray-'] > :not(:last-child), + [class*='divide-black/'] > :not(:last-child), + [class*='divide-white/'] > :not(:last-child) + ) { + border-color: var(--app-border); +} + +.dark .app-theme :where([class*='dark:divide-gray-'] > :not(:last-child)), +.dark .app-theme :where([class*='dark:divide-white/'] > :not(:last-child)) { + border-color: var(--app-border); +} + +.app-theme :where([class~='h-px'][class*='bg-gray-'], [class~='h-px'][class*='bg-black/']) { + background: var(--app-divider); +} + +.dark .app-theme :where([class~='h-px'][class*='dark:bg-white/']) { + background: var(--app-divider); +} + +.app-theme + :where( + [class~='bg-gray-50'], + [class~='bg-gray-50/50'], + [class~='bg-gray-100'], + [class~='bg-gray-200/50'] + ) { + background: var(--app-hover); +} + +.dark + .app-theme + :where( + [class~='dark:bg-white/3'], + [class~='dark:bg-white/4'], + [class~='dark:bg-white/5'], + [class~='dark:bg-white/6'], + [class~='dark:bg-white/8'], + [class~='dark:bg-white/10'] + ) { + background: var(--app-hover); +} + +.app-theme + :where( + [class~='hover:bg-gray-50']:hover, + [class~='hover:bg-gray-100']:hover, + [class~='hover:bg-gray-200']:hover, + [class~='hover:bg-gray-200/60']:hover, + [class~='hover:bg-gray-200/70']:hover + ) { + background: var(--app-active); +} + +.dark + .app-theme + :where( + [class~='dark:hover:bg-white/3']:hover, + [class~='dark:hover:bg-white/4']:hover, + [class~='dark:hover:bg-white/5']:hover, + [class~='dark:hover:bg-white/6']:hover, + [class~='dark:hover:bg-white/8']:hover, + [class~='dark:hover:bg-white/10']:hover, + [class~='dark:hover:bg-white/12']:hover + ) { + background: var(--app-active); +} + +.app-theme + :where( + [class~='text-gray-950'], + [class~='text-gray-900'], + [class~='text-gray-800'], + [class~='text-gray-700'] + ) { + color: var(--app-fg); +} + +.dark + .app-theme + :where( + [class~='dark:text-white'], + [class~='dark:text-gray-100'], + [class~='dark:text-gray-200'], + [class~='dark:text-gray-300'] + ) { + color: var(--app-fg); +} + +.app-theme + :where( + [class~='text-gray-600'], + [class~='text-gray-500'], + [class~='text-gray-400'], + [class~='text-gray-300'] + ) { + color: var(--app-fg-muted); +} + +.dark + .app-theme + :where( + [class~='dark:text-gray-400'], + [class~='dark:text-gray-500'], + [class~='dark:text-gray-600'], + [class~='dark:text-gray-700'] + ) { + color: var(--app-fg-muted); +} + /* CodeMirror - match Open WebUI */ .cm-editor { height: 100%; @@ -197,9 +375,9 @@ .tippy-box[data-theme~='cptr'] { background: #1a1a1a; color: #e0e0e0; - font-size: 11px; + font-size: 0.6875rem; font-weight: 500; - padding: 2px 4px; - border-radius: 6px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); + padding: 0.125rem 0.25rem; + border-radius: 0.375rem; + box-shadow: 0 0.125rem 0.5rem rgba(0, 0, 0, 0.3); } diff --git a/cptr/frontend/src/lib/apis/git.ts b/cptr/frontend/src/lib/apis/git.ts index 6bf00829..888ea7a2 100644 --- a/cptr/frontend/src/lib/apis/git.ts +++ b/cptr/frontend/src/lib/apis/git.ts @@ -45,6 +45,12 @@ export const getGitShow = (root: string, ref: string) => export const getGitBranches = (root: string) => fetchJSON(`/api/git/branches?root=${encodeURIComponent(root)}`); +export const getGitWorktrees = (root: string) => + fetchJSON(`/api/git/worktrees?root=${encodeURIComponent(root)}`); + +export const createGitWorktree = (root: string, branch: string, path?: string) => + fetchJSON('/api/git/worktrees', jsonBody({ root, branch, path })); + export const getGitStashes = (root: string) => fetchJSON(`/api/git/stashes?root=${encodeURIComponent(root)}`); diff --git a/cptr/frontend/src/lib/apis/memory.ts b/cptr/frontend/src/lib/apis/memory.ts index 2e3d935b..fb9bbcd8 100644 --- a/cptr/frontend/src/lib/apis/memory.ts +++ b/cptr/frontend/src/lib/apis/memory.ts @@ -63,8 +63,7 @@ export const updateMemory = ( scope: MemoryScope, workspace: string, operations: MemoryOperation[] -) => - fetchJSON('/api/memory/update', jsonBody({ scope, workspace, operations })); +) => fetchJSON('/api/memory/update', jsonBody({ scope, workspace, operations })); export const searchMemory = (body: { query?: string; diff --git a/cptr/frontend/src/lib/components/Admin/AgentProfileModal.svelte b/cptr/frontend/src/lib/components/Admin/AgentProfileModal.svelte index ca8d2383..57ffe39d 100644 --- a/cptr/frontend/src/lib/components/Admin/AgentProfileModal.svelte +++ b/cptr/frontend/src/lib/components/Admin/AgentProfileModal.svelte @@ -76,7 +76,7 @@ diff --git a/cptr/frontend/src/lib/components/Admin/Agents.svelte b/cptr/frontend/src/lib/components/Admin/Agents.svelte index 8cb9ec1f..5b20b124 100644 --- a/cptr/frontend/src/lib/components/Admin/Agents.svelte +++ b/cptr/frontend/src/lib/components/Admin/Agents.svelte @@ -262,23 +262,23 @@ > {profile.name} - + {profileSubtitle(profile)} {#if detected[profile.id]?.message} - + {detected[profile.id]?.message} {/if}