Symbolleiste professioneller gestaltet: echte SVG-Icons statt Unicode/Emoji

Neue ToolbarIcon.vue (hand-gezeichnete Strich-Icons: Einstellungen, Rückgängig/
Wiederholen, Tabelle/Diagramm/Text einfügen, Benannte Bereiche) ersetzt die
bisherigen ⚙ ↶ ↷ ▦ ▤ ¶ 🏷 Glyphen. Buttons sind jetzt in dezente,
segmentierte Gruppen ("Pills") statt einzeln umrandeter Kästchen mit dünnen
Trennstrichen gefasst, mit Ghost-Stil in Ruhe und Hover-/Aktiv-Zuständen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
wkh
2026-09-09 07:59:42 +02:00
co-authored by Claude Sonnet 5
parent 40adaa2e1c
commit 10efd6af2f
3 changed files with 204 additions and 78 deletions
+4 -4
View File
@@ -180,7 +180,7 @@ Point-Mode ändert nie die Tabellen-/Objektauswahl im Hintergrund.
### Benutzerdefinierte Funktionen ### Benutzerdefinierte Funktionen
Der Button **„𝑓 Funktionen"** in der Symbolleiste öffnet die einzige Stelle, an Der **„fx"-Button** in der Symbolleiste öffnet die einzige Stelle, an
der eigene, dokumentweite Funktionen angelegt, bearbeitet und gelöscht werden der eigene, dokumentweite Funktionen angelegt, bearbeitet und gelöscht werden
— kein JSON-Handedit, keine Konsole. Danach in jeder Zelle aufrufbar wie ein — kein JSON-Handedit, keine Konsole. Danach in jeder Zelle aufrufbar wie ein
eingebauter Funktionsname: `=MARGE(Umsatz!B2; Umsatz!C2)`. eingebauter Funktionsname: `=MARGE(Umsatz!B2; Umsatz!C2)`.
@@ -334,8 +334,8 @@ Bereich, über den sie selbst iteriert. Siehe „Bekannte Grenzen" unten.
### Benannte Bereiche ### Benannte Bereiche
Der Button **„🏷" (Benannte Bereiche)** in der Symbolleiste, direkt neben Der **„Benannte Bereiche"-Button** (Tag-Symbol) in der Symbolleiste, direkt
**„𝑓 Funktionen"**, öffnet die einzige Stelle, an der dokumentweite Namen für neben dem **„fx"-Button**, öffnet die einzige Stelle, an der dokumentweite Namen für
eine feste Zelle/einen festen Bereich angelegt, bearbeitet und gelöscht eine feste Zelle/einen festen Bereich angelegt, bearbeitet und gelöscht
werden — z. B. `Umsatz_Q1` statt `Umsatz!B2:B6`. Danach in **jeder** werden — z. B. `Umsatz_Q1` statt `Umsatz!B2:B6`. Danach in **jeder**
Top-Level-Formel unqualifiziert nutzbar, ohne Tabellen-Präfix: Top-Level-Formel unqualifiziert nutzbar, ohne Tabellen-Präfix:
@@ -676,7 +676,7 @@ das Dropdown, ohne die Bearbeitung selbst abzubrechen.
Sonst?)`, `AND(Bedingung1; Bedingung2; …)`, `OR(Bedingung1; Bedingung2; …)`, Sonst?)`, `AND(Bedingung1; Bedingung2; …)`, `OR(Bedingung1; Bedingung2; …)`,
`NOT(Bedingung)`, `DATE(Jahr; Monat; Tag)`, `TIME(Std; Min; Sek)`, `TODAY()`, `NOT(Bedingung)`, `DATE(Jahr; Monat; Tag)`, `TIME(Std; Min; Sek)`, `TODAY()`,
`NOW()`, `XLOOKUP(Suchwert; Suchbereich; Rückgabebereich; [WennNichtGefunden]; `NOW()`, `XLOOKUP(Suchwert; Suchbereich; Rückgabebereich; [WennNichtGefunden];
[Vergleichsmodus]; [Suchmodus])` — plus alle über **„𝑓 Funktionen"** angelegten [Vergleichsmodus]; [Suchmodus])` — plus alle über den **„fx"-Button** angelegten
benutzerdefinierten Funktionen (siehe „Benutzerdefinierte Funktionen" oben), benutzerdefinierten Funktionen (siehe „Benutzerdefinierte Funktionen" oben),
die sich für den Aufrufer identisch verhalten. Argumente gemischt: die sich für den Aufrufer identisch verhalten. Argumente gemischt:
Einzelzellen, Bereiche (lokal oder `Name!…`), Zahl-Literale — z. B. Einzelzellen, Bereiche (lokal oder `Name!…`), Zahl-Literale — z. B.
+85 -47
View File
@@ -7,6 +7,7 @@ import BaseModal from './BaseModal.vue';
import CustomFunctionsModal from './CustomFunctionsModal.vue'; import CustomFunctionsModal from './CustomFunctionsModal.vue';
import NamedRangesModal from './NamedRangesModal.vue'; import NamedRangesModal from './NamedRangesModal.vue';
import TheLogo from './TheLogo.vue'; import TheLogo from './TheLogo.vue';
import ToolbarIcon from './ToolbarIcon.vue';
import { WICOM, WICOM_SOCIAL } from '../config/brand'; import { WICOM, WICOM_SOCIAL } from '../config/brand';
import { import {
exportJson, exportJson,
@@ -210,55 +211,60 @@ function onReset() {
aria-label="Einstellungen" aria-label="Einstellungen"
@click="store.ui.settingsOpen = !store.ui.settingsOpen" @click="store.ui.settingsOpen = !store.ui.settingsOpen"
> >
⚙ <ToolbarIcon name="settings" />
</button> </button>
<span class="divider" /> <div class="tgroup">
<button <button
class="btn" class="ibtn"
title="Rückgängig (Strg/Cmd+Z)" title="Rückgängig (Strg/Cmd+Z)"
aria-label="Rückgängig"
:disabled="!store.canUndo.value" :disabled="!store.canUndo.value"
@click="store.undo()" @click="store.undo()"
> >
↶ <ToolbarIcon name="undo" />
</button> </button>
<button <button
class="btn" class="ibtn"
title="Wiederholen (Strg/Cmd+Y)" title="Wiederholen (Strg/Cmd+Y)"
aria-label="Wiederholen"
:disabled="!store.canRedo.value" :disabled="!store.canRedo.value"
@click="store.redo()" @click="store.redo()"
> >
↷ <ToolbarIcon name="redo" />
</button> </button>
</div>
<span class="divider" /> <div class="tgroup accent">
<button class="btn accent icon-btn" title="Tabelle einfügen" aria-label="Tabelle einfügen" @click="insertTable"> <button class="ibtn" title="Tabelle einfügen" aria-label="Tabelle einfügen" @click="insertTable">
▦ <ToolbarIcon name="table" />
</button> </button>
<button class="btn accent icon-btn" title="Diagramm einfügen" aria-label="Diagramm einfügen" @click="insertChart"> <button class="ibtn" title="Diagramm einfügen" aria-label="Diagramm einfügen" @click="insertChart">
▤ <ToolbarIcon name="chart" />
</button> </button>
<button class="btn accent icon-btn" title="Text einfügen" aria-label="Text einfügen" @click="insertText"> <button class="ibtn" title="Text einfügen" aria-label="Text einfügen" @click="insertText">
<ToolbarIcon name="text" />
</button> </button>
</div>
<span class="divider" /> <div class="tgroup accent">
<button <button
class="btn accent icon-btn" class="ibtn fx"
title="Benutzerdefinierte Funktionen" title="Benutzerdefinierte Funktionen"
aria-label="Benutzerdefinierte Funktionen" aria-label="Benutzerdefinierte Funktionen"
@click="functionsOpen = true" @click="functionsOpen = true"
> >
𝑓 <em>fx</em>
</button> </button>
<button <button
class="btn accent icon-btn" class="ibtn"
title="Benannte Bereiche" title="Benannte Bereiche"
aria-label="Benannte Bereiche" aria-label="Benannte Bereiche"
@click="namedRangesOpen = true" @click="namedRangesOpen = true"
> >
🏷 <ToolbarIcon name="tag" />
</button> </button>
</div>
<div class="spacer" /> <div class="spacer" />
@@ -410,8 +416,8 @@ function onReset() {
display: flex; display: flex;
align-items: center; align-items: center;
flex-wrap: wrap; flex-wrap: wrap;
gap: 8px; gap: 10px;
padding: 10px 14px; padding: 9px 16px;
background: var(--surface); background: var(--surface);
border-bottom: 1px solid var(--border); border-bottom: 1px solid var(--border);
box-shadow: var(--shadow-sm); box-shadow: var(--shadow-sm);
@@ -513,26 +519,72 @@ function onReset() {
color: var(--accent); color: var(--accent);
} }
.gear { .gear {
border: 1px solid var(--border); display: inline-flex;
background: var(--surface); align-items: center;
border-radius: 8px; justify-content: center;
width: 30px; border: 1px solid transparent;
height: 30px; background: transparent;
font-size: 15px; border-radius: 9px;
line-height: 1; width: 32px;
height: 32px;
cursor: pointer; cursor: pointer;
color: var(--text-dim); color: var(--text-dim);
transition: background-color 0.12s ease, color 0.12s ease, border-color 0.12s ease;
}
.gear:hover {
background: var(--surface-2);
color: var(--text);
} }
.gear:hover,
.gear.on { .gear.on {
background: var(--accent-weak);
border-color: var(--accent); border-color: var(--accent);
color: var(--accent); color: var(--accent);
} }
.divider {
width: 1px; /* --- grouped icon-button clusters (segmented-control look) --- */
align-self: stretch; .tgroup {
background: var(--border); display: flex;
margin: 2px 4px; align-items: center;
gap: 2px;
padding: 3px;
background: var(--surface-2);
border: 1px solid var(--border);
border-radius: 10px;
}
.ibtn {
display: inline-flex;
align-items: center;
justify-content: center;
width: 30px;
height: 28px;
border: 0;
border-radius: 7px;
background: transparent;
color: var(--text-dim);
cursor: pointer;
transition: background-color 0.12s ease, color 0.12s ease;
}
.tgroup.accent .ibtn {
color: var(--accent);
}
.ibtn:hover {
background: var(--surface);
color: var(--text);
box-shadow: var(--shadow-sm);
}
.tgroup.accent .ibtn:hover {
color: var(--accent);
}
.ibtn:disabled {
opacity: 0.35;
cursor: default;
pointer-events: none;
}
.ibtn.fx em {
font-style: italic;
font-weight: 700;
font-size: 14px;
font-family: Georgia, 'Times New Roman', serif;
} }
.spacer { .spacer {
flex: 1; flex: 1;
@@ -554,20 +606,6 @@ function onReset() {
cursor: default; cursor: default;
pointer-events: none; pointer-events: none;
} }
.btn.accent {
border-color: var(--accent);
color: var(--accent);
font-weight: 600;
}
.icon-btn {
display: inline-flex;
align-items: center;
justify-content: center;
width: 34px;
padding: 6px 0;
font-size: 14px;
line-height: 1;
}
.menu-wrap { .menu-wrap {
position: relative; position: relative;
} }
+88
View File
@@ -0,0 +1,88 @@
<script setup lang="ts">
/**
* Small hand-drawn line-icon set for the toolbar (no icon library/font —
* consistent with this project's "nothing off the shelf" approach). One
* shared <svg> shell (24x24, stroke-only) with a name-keyed set of shapes,
* since every icon needs the exact same viewBox/stroke setup and only the
* inner geometry differs.
*/
export type ToolbarIconName =
| 'settings'
| 'undo'
| 'redo'
| 'table'
| 'chart'
| 'text'
| 'tag';
defineProps<{ name: ToolbarIconName }>();
</script>
<template>
<svg
class="ti"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.75"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<template v-if="name === 'settings'">
<line x1="3" y1="6" x2="21" y2="6" />
<circle cx="9" cy="6" r="2" fill="currentColor" />
<line x1="3" y1="12" x2="21" y2="12" />
<circle cx="15" cy="12" r="2" fill="currentColor" />
<line x1="3" y1="18" x2="21" y2="18" />
<circle cx="7" cy="18" r="2" fill="currentColor" />
</template>
<template v-else-if="name === 'undo'">
<path d="M7 10 H15 a4 4 0 0 1 0 8 h-3" />
<polyline points="7 10 11 6" />
<polyline points="7 10 11 14" />
</template>
<template v-else-if="name === 'redo'">
<path d="M17 10 H9 a4 4 0 0 0 0 8 h3" />
<polyline points="17 10 13 6" />
<polyline points="17 10 13 14" />
</template>
<template v-else-if="name === 'table'">
<rect x="3" y="4" width="18" height="16" rx="2" />
<line x1="3" y1="10" x2="21" y2="10" />
<line x1="3" y1="16" x2="21" y2="16" />
<line x1="9" y1="4" x2="9" y2="20" />
<line x1="15" y1="4" x2="15" y2="20" />
</template>
<template v-else-if="name === 'chart'">
<line x1="4" y1="20" x2="20" y2="20" />
<rect x="6" y="13" width="3" height="7" />
<rect x="11" y="9" width="3" height="11" />
<rect x="16" y="5" width="3" height="15" />
</template>
<template v-else-if="name === 'text'">
<rect x="4" y="4" width="16" height="16" rx="2" />
<line x1="7" y1="9" x2="17" y2="9" />
<line x1="7" y1="13" x2="17" y2="13" />
<line x1="7" y1="17" x2="13" y2="17" />
</template>
<template v-else-if="name === 'tag'">
<polygon points="4,5 14,5 20,11 14,17 4,17" />
<circle cx="9" cy="9" r="1.6" fill="currentColor" />
</template>
</svg>
</template>
<style scoped>
.ti {
width: 17px;
height: 17px;
display: block;
}
</style>