Show the "numolus" wordmark only when the toolbar has room for it
Instead of fixed breakpoints (wicom hidden below 720px, the wordmark below 520px -- while the toolbar already wrapped to two lines much earlier), the wordmark and "wicom" are shown only while the whole toolbar still fits on one line with them. Measured with a ResizeObserver; the wordmark's width is remembered while hidden, so it doesn't flip-flop at the threshold. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onBeforeUnmount, ref, watch } from 'vue';
|
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
||||||
import { useDocument } from '../store/document';
|
import { useDocument } from '../store/document';
|
||||||
import { useTheme } from '../composables/useTheme';
|
import { useTheme } from '../composables/useTheme';
|
||||||
import { useToasts } from '../composables/useToasts';
|
import { useToasts } from '../composables/useToasts';
|
||||||
@@ -32,6 +32,52 @@ const { mode: themeMode, cycle: cycleTheme } = useTheme();
|
|||||||
const toasts = useToasts();
|
const toasts = useToasts();
|
||||||
|
|
||||||
const fileMenuOpen = ref(false);
|
const fileMenuOpen = ref(false);
|
||||||
|
|
||||||
|
// ---- wordmark only when there's room ----------------------------------
|
||||||
|
// "numolus" + "wicom" next to the logo are shown only while the whole
|
||||||
|
// toolbar still fits on one line with them; otherwise just the logo. Measured
|
||||||
|
// rather than a fixed breakpoint, since what fits depends on the toolbar's
|
||||||
|
// actual contents. The wordmark's own width is remembered from the last time
|
||||||
|
// it was visible, so hiding it can't make it look like it would fit again
|
||||||
|
// (no flip-flopping at the threshold).
|
||||||
|
const toolbarEl = ref<HTMLElement | null>(null);
|
||||||
|
const brandExtra = ref<HTMLElement | null>(null);
|
||||||
|
const showWordmark = ref(true);
|
||||||
|
let wordmarkWidth = 0;
|
||||||
|
|
||||||
|
function fitWordmark() {
|
||||||
|
const bar = toolbarEl.value;
|
||||||
|
if (!bar) return;
|
||||||
|
const cs = getComputedStyle(bar);
|
||||||
|
const avail = bar.clientWidth - parseFloat(cs.paddingLeft) - parseFloat(cs.paddingRight);
|
||||||
|
const gap = parseFloat(cs.columnGap) || 0;
|
||||||
|
let need = 0;
|
||||||
|
let items = 0;
|
||||||
|
for (const child of Array.from(bar.children) as HTMLElement[]) {
|
||||||
|
if (getComputedStyle(child).display === 'none') continue;
|
||||||
|
items++;
|
||||||
|
if (!child.classList.contains('spacer')) need += child.getBoundingClientRect().width;
|
||||||
|
}
|
||||||
|
need += gap * Math.max(0, items - 1);
|
||||||
|
if (showWordmark.value && brandExtra.value) {
|
||||||
|
// plus the gap to the logo, which goes away with it
|
||||||
|
const brandGap = parseFloat(getComputedStyle(brandExtra.value.parentElement!).columnGap) || 0;
|
||||||
|
wordmarkWidth = brandExtra.value.getBoundingClientRect().width + brandGap;
|
||||||
|
} else {
|
||||||
|
need += wordmarkWidth;
|
||||||
|
}
|
||||||
|
showWordmark.value = need <= avail + 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
let resizeObs: ResizeObserver | null = null;
|
||||||
|
onMounted(() => {
|
||||||
|
resizeObs = new ResizeObserver(() => fitWordmark());
|
||||||
|
if (toolbarEl.value) resizeObs.observe(toolbarEl.value);
|
||||||
|
fitWordmark();
|
||||||
|
// web fonts arriving late change the measured widths
|
||||||
|
void document.fonts?.ready.then(fitWordmark);
|
||||||
|
});
|
||||||
|
onBeforeUnmount(() => resizeObs?.disconnect());
|
||||||
const fileMenuWrap = ref<HTMLElement | null>(null);
|
const fileMenuWrap = ref<HTMLElement | null>(null);
|
||||||
|
|
||||||
// Close the Datei menu on Escape or on a press anywhere outside it. Capture
|
// Close the Datei menu on Escape or on a press anywhere outside it. Capture
|
||||||
@@ -249,13 +295,13 @@ function onSample() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<header class="toolbar">
|
<header ref="toolbarEl" class="toolbar">
|
||||||
<div class="brand" title="Numolus — wicom, Vaduz (FL)">
|
<div class="brand" title="Numolus — wicom, Vaduz (FL)">
|
||||||
<TheLogo class="brand-mark" />
|
<TheLogo class="brand-mark" />
|
||||||
|
<span v-show="showWordmark" ref="brandExtra" class="brand-extra">
|
||||||
<span class="wordmark">numolus</span>
|
<span class="wordmark">numolus</span>
|
||||||
<button class="by" type="button" @click="aboutOpen = true">
|
<button class="by" type="button" @click="aboutOpen = true">wicom</button>
|
||||||
wicom
|
</span>
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
class="gear"
|
class="gear"
|
||||||
@@ -517,6 +563,11 @@ function onSample() {
|
|||||||
height: 24px;
|
height: 24px;
|
||||||
flex: none;
|
flex: none;
|
||||||
}
|
}
|
||||||
|
.brand-extra {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 9px;
|
||||||
|
}
|
||||||
.wordmark {
|
.wordmark {
|
||||||
font-size: 17px;
|
font-size: 17px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
@@ -539,16 +590,6 @@ function onSample() {
|
|||||||
.by:hover {
|
.by:hover {
|
||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
}
|
}
|
||||||
@media (max-width: 720px) {
|
|
||||||
.by {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (max-width: 520px) {
|
|
||||||
.wordmark {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* --- Über-Dialog --- */
|
/* --- Über-Dialog --- */
|
||||||
.about-lead {
|
.about-lead {
|
||||||
|
|||||||
Reference in New Issue
Block a user