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">
|
||||
import { computed, onBeforeUnmount, ref, watch } from 'vue';
|
||||
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
||||
import { useDocument } from '../store/document';
|
||||
import { useTheme } from '../composables/useTheme';
|
||||
import { useToasts } from '../composables/useToasts';
|
||||
@@ -32,6 +32,52 @@ const { mode: themeMode, cycle: cycleTheme } = useTheme();
|
||||
const toasts = useToasts();
|
||||
|
||||
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);
|
||||
|
||||
// Close the Datei menu on Escape or on a press anywhere outside it. Capture
|
||||
@@ -249,13 +295,13 @@ function onSample() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header class="toolbar">
|
||||
<header ref="toolbarEl" class="toolbar">
|
||||
<div class="brand" title="Numolus — wicom, Vaduz (FL)">
|
||||
<TheLogo class="brand-mark" />
|
||||
<span v-show="showWordmark" ref="brandExtra" class="brand-extra">
|
||||
<span class="wordmark">numolus</span>
|
||||
<button class="by" type="button" @click="aboutOpen = true">
|
||||
wicom
|
||||
</button>
|
||||
<button class="by" type="button" @click="aboutOpen = true">wicom</button>
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
class="gear"
|
||||
@@ -517,6 +563,11 @@ function onSample() {
|
||||
height: 24px;
|
||||
flex: none;
|
||||
}
|
||||
.brand-extra {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 9px;
|
||||
}
|
||||
.wordmark {
|
||||
font-size: 17px;
|
||||
font-weight: 600;
|
||||
@@ -539,16 +590,6 @@ function onSample() {
|
||||
.by:hover {
|
||||
color: var(--accent);
|
||||
}
|
||||
@media (max-width: 720px) {
|
||||
.by {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@media (max-width: 520px) {
|
||||
.wordmark {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* --- Über-Dialog --- */
|
||||
.about-lead {
|
||||
|
||||
Reference in New Issue
Block a user