Skip to content
Merged

0.8.3 #105

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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ 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.8.3] - 2026-07-07

### Fixed

- 💬 **Cleaner chat suggestions.** Slash commands, file matches, skill matches, and model choices now have a little more room and clearer hover hints, so longer names are easier to understand.
- 🧭 **Better menu hints.** Menus can now show helpful hover hints only when there is something useful to show, keeping empty tooltips out of the way.

## [0.8.2] - 2026-07-07

### Added
Expand Down
6 changes: 5 additions & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Open Use License

Copyright © 2026 Open WebUI Inc. All rights reserved.
Copyright © 2026 Open WebUI, Inc. All rights reserved.

This software is licensed under the Open Use License, which incorporates the
Elastic License 2.0 ("ELv2") in full with the additional conditions set forth
Expand Down Expand Up @@ -30,3 +30,7 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Commercial, organizational, or production use is subject to the applicable
commercial terms published at https://openwebui.com/terms, unless Open WebUI,
Inc. agrees otherwise in writing.
3 changes: 3 additions & 0 deletions cptr/frontend/src/lib/components/DropdownMenu.svelte
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
<script lang="ts">
import { onMount, type Snippet } from 'svelte';
import { tooltip } from '$lib/tooltip';
import Icon from './Icon.svelte';
import KeyPill from './KeyPill.svelte';

interface MenuItem {
label: string;
tooltip?: string;
icon?: string;
onclick: () => void;
active?: boolean;
Expand Down Expand Up @@ -374,6 +376,7 @@
>
<button
class="flex items-center gap-2 min-w-0 flex-1 h-full px-2 text-inherit"
use:tooltip={item.tooltip ? { content: item.tooltip, placement: 'top' } : null}
onclick={() => {
item.onclick();
onclose();
Expand Down
18 changes: 9 additions & 9 deletions cptr/frontend/src/lib/components/chat/ChatInput.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -1124,7 +1124,7 @@

{#if showSlashCommands}
<div
class="app-theme app-surface absolute left-2 bottom-full mb-1 z-50 w-60 max-h-40 overflow-y-auto rounded-xl border shadow-xl p-0.5"
class="app-theme app-surface absolute left-2 bottom-full mb-1 z-50 w-64 max-h-40 overflow-y-auto rounded-xl border shadow-xl p-0.5"
>
{#if slashCommandIds.length > 0}
<div class="app-muted mb-0.5 px-2 pt-1 pb-0.5 text-[0.625rem] leading-none">
Expand All @@ -1137,7 +1137,7 @@
aria-label="Compact: shorten older messages so this chat can keep going."
use:tooltip={{
content: 'Shorten older messages so this chat can keep going.',
placement: 'right'
placement: 'top'
}}
class="slash-command-row flex items-center gap-2 w-full h-6 px-2 rounded-xl text-xs text-left transition-colors duration-75
{selectedSlashCommand('compact') ? 'app-interactive-active' : ''} disabled:opacity-50"
Expand Down Expand Up @@ -1186,7 +1186,7 @@
aria-label="Plan: work out a plan first, then wait before changing files."
use:tooltip={{
content: 'Work out a plan first, then wait before changing files.',
placement: 'right'
placement: 'top'
}}
class="slash-command-row flex items-center gap-2 w-full h-6 px-2 rounded-xl text-xs text-left transition-colors duration-75
{selectedSlashCommand('plan') ? 'app-interactive-active' : ''}"
Expand Down Expand Up @@ -1227,7 +1227,7 @@
aria-label="Fork: clone this chat into a new copy."
use:tooltip={{
content: 'Clone this chat into a new copy.',
placement: 'right'
placement: 'top'
}}
class="slash-command-row flex items-center gap-2 w-full h-6 px-2 rounded-xl text-xs text-left transition-colors duration-75
{selectedSlashCommand('fork') ? 'app-interactive-active' : ''} disabled:opacity-50"
Expand Down Expand Up @@ -1255,7 +1255,7 @@
aria-label="Status: check what is running in this chat."
use:tooltip={{
content: 'Check what is running in this chat.',
placement: 'right'
placement: 'top'
}}
class="slash-command-row flex items-center gap-2 w-full h-6 px-2 rounded-xl text-xs text-left transition-colors duration-75
{selectedSlashCommand('status') ? 'app-interactive-active' : ''}"
Expand Down Expand Up @@ -1294,7 +1294,7 @@
aria-label="List skills: see the skills available in this workspace."
use:tooltip={{
content: 'See the skills available in this workspace.',
placement: 'right'
placement: 'top'
}}
class="slash-command-row flex items-center gap-2 w-full h-6 px-2 rounded-xl text-xs text-left transition-colors duration-75
{selectedSlashCommand('skills:list') ? 'app-interactive-active' : ''}"
Expand All @@ -1319,7 +1319,7 @@
aria-label="Create skill: teach Computer a reusable workflow."
use:tooltip={{
content: 'Teach Computer a reusable workflow.',
placement: 'right'
placement: 'top'
}}
class="slash-command-row flex items-center gap-2 w-full h-6 px-2 rounded-xl text-xs text-left transition-colors duration-75
{selectedSlashCommand('skills:create') ? 'app-interactive-active' : ''}"
Expand All @@ -1345,8 +1345,8 @@
type="button"
aria-label={`Use skill: ${skill.label}`}
use:tooltip={{
content: skill.description || 'Use this skill in the message.',
placement: 'right'
content: skill.label,
placement: 'top'
}}
class="slash-command-row flex items-center gap-2 w-full h-6 px-2 rounded-xl text-xs text-left transition-colors duration-75
{selectedSlashSkill(skill.id) ? 'app-interactive-active' : ''}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import Icon from '../Icon.svelte';
import { fileIconName } from '$lib/utils/fileIcon';
import { t } from '$lib/i18n';
import { tooltip } from '$lib/tooltip';

interface SuggestionItem {
id: string;
Expand Down Expand Up @@ -35,7 +36,7 @@
</script>

<div
class="app-theme app-surface fixed z-50 w-60 max-h-40 overflow-y-auto rounded-xl border shadow-xl p-0.5"
class="app-theme app-surface fixed z-50 w-64 max-h-40 overflow-y-auto rounded-xl border shadow-xl p-0.5"
>
{#if items.length === 0}
<div class="app-muted flex items-center h-6 px-2 text-xs">{$t('quickOpen.noFiles')}</div>
Expand All @@ -54,6 +55,7 @@
onselect(i);
}}
onmouseenter={() => (selectedIndex = i)}
use:tooltip={{ content: item.id, placement: 'top' }}
>
<span class="app-icon-muted flex items-center justify-center w-4 shrink-0">
<Icon name={fileIconName(item.label, item.type)} size={14} />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script lang="ts">
import Icon from '$lib/components/Icon.svelte';
import { t } from '$lib/i18n';
import { tooltip } from '$lib/tooltip';

interface SuggestionItem {
id: string;
Expand Down Expand Up @@ -28,7 +29,7 @@
</script>

<div
class="app-theme app-surface fixed z-50 w-60 max-h-40 overflow-y-auto rounded-xl border shadow-xl p-0.5"
class="app-theme app-surface fixed z-50 w-64 max-h-40 overflow-y-auto rounded-xl border shadow-xl p-0.5"
>
{#if items.length === 0}
<div class="app-muted flex items-center h-6 px-2 text-xs">{$t('chat.noSkillsFound')}</div>
Expand All @@ -47,7 +48,7 @@
onselect(i);
}}
onmouseenter={() => (selectedIndex = i)}
title={item.description}
use:tooltip={{ content: item.label, placement: 'top' }}
>
<span class="app-icon-muted flex items-center justify-center w-4 shrink-0">
<Icon name="spark" size={13} strokeWidth={1.7} />
Expand Down
3 changes: 2 additions & 1 deletion cptr/frontend/src/lib/components/common/ModelSelector.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
const menuItems = $derived(
filtered.map((m) => ({
label: m.name,
tooltip: m.name,
active: m.id === selectedModel,
check: true,
onclick: () => {
Expand Down Expand Up @@ -100,7 +101,7 @@
{preferAbove}
forceAbove={preferAbove}
maxHeight={selectorMaxHeight}
className="w-48"
className="w-52"
{align}
>
{#snippet header()}
Expand Down
50 changes: 34 additions & 16 deletions cptr/frontend/src/lib/tooltip.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,49 @@
import tippy, { type Props as TippyProps } from 'tippy.js';
import tippy, { type Instance, type Props as TippyProps } from 'tippy.js';
import 'tippy.js/dist/tippy.css';

type TooltipParams = string | Partial<TippyProps> | null | undefined | false;

/**
* Svelte action for tippy.js tooltips.
* Usage: <button use:tooltip={'New terminal'}>
* or: <button use:tooltip={{ content: 'New terminal', placement: 'bottom' }}>
*/
export function tooltip(node: HTMLElement, params: string | Partial<TippyProps>) {
const opts: Partial<TippyProps> = typeof params === 'string' ? { content: params } : params;
export function tooltip(node: HTMLElement, params: TooltipParams) {
function optsFor(value: TooltipParams): Partial<TippyProps> | null {
if (!value) return null;
const opts: Partial<TippyProps> = typeof value === 'string' ? { content: value } : value;
return opts.content ? opts : null;
}

function create(opts: Partial<TippyProps>) {
return tippy(node, {
arrow: false,
delay: [400, 0],
duration: [100, 75],
placement: 'bottom',
theme: 'cptr',
touch: false,
...opts
});
}

const instance = tippy(node, {
arrow: false,
delay: [400, 0],
duration: [100, 75],
placement: 'bottom',
theme: 'cptr',
touch: false,
...opts
});
let instance: Instance | null = null;
const opts = optsFor(params);
if (opts) instance = create(opts);

return {
update(newParams: string | Partial<TippyProps>) {
const newOpts = typeof newParams === 'string' ? { content: newParams } : newParams;
instance.setProps(newOpts);
update(newParams: TooltipParams) {
const newOpts = optsFor(newParams);
if (!newOpts) {
instance?.destroy();
instance = null;
return;
}
if (instance) instance.setProps(newOpts);
else instance = create(newOpts);
},
destroy() {
instance.destroy();
instance?.destroy();
}
};
}
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "cptr"
version = "0.8.2"
version = "0.8.3"
description = "Your computer, from anywhere. Code, manage, and control your machine from the web."
license = {file = "LICENSE"}
readme = "README.md"
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading