Merge origin/main

This commit is contained in:
Gregory Schier
2026-08-17 06:54:10 -07:00
8 changed files with 43 additions and 13 deletions
+12 -6
View File
@@ -102,13 +102,19 @@ jobs:
if: matrix.os == 'ubuntu' if: matrix.os == 'ubuntu'
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install -y cmake ninja-build libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev libnss3 patchelf xdg-utils clang-15 llvm-15 sudo apt-get install -y cmake ninja-build libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev libnss3 patchelf xdg-utils
# crates/yaak-web compiles SQLite to wasm via sqlite-wasm-rs, whose C shim # crates/yaak-web compiles SQLite to wasm via sqlite-wasm-rs, whose C shim
# uses C23 [[noreturn]]. Ubuntu 22.04's default clang-14 rejects it; clang-15 # uses C23 [[noreturn]] and expects a freestanding wasm32 target. Ubuntu
# from the same repos accepts it. Only the wasm build uses this compiler, so # 22.04 ships only clang <=15: 14 rejects the attribute, and 15 falls
# the shipped binary keeps 22.04's glibc floor. # through to host glibc headers ("bits/libc-header-start.h" not found).
echo "CC_wasm32_unknown_unknown=/usr/bin/clang-15" >> "$GITHUB_ENV" # clang-18 handles it (it is what ubuntu-24.04 uses). Install it from
echo "AR_wasm32_unknown_unknown=/usr/bin/llvm-ar-15" >> "$GITHUB_ENV" # apt.llvm.org since 22.04's repos stop at 15. Only the wasm build uses
# this compiler, so the shipped binary keeps 22.04's glibc floor.
wget -qO /tmp/llvm.sh https://apt.llvm.org/llvm.sh
chmod +x /tmp/llvm.sh
sudo /tmp/llvm.sh 18
echo "CC_wasm32_unknown_unknown=/usr/bin/clang-18" >> "$GITHUB_ENV"
echo "AR_wasm32_unknown_unknown=/usr/bin/llvm-ar-18" >> "$GITHUB_ENV"
- name: Install Protoc for plugin-runtime - name: Install Protoc for plugin-runtime
uses: arduino/setup-protoc@v3 uses: arduino/setup-protoc@v3
+3 -1
View File
@@ -333,7 +333,9 @@ export function formatHotkeyString(trigger: string): string[] {
} else if (p === "Alt") { } else if (p === "Alt") {
labelParts.push("⌥"); labelParts.push("⌥");
} else if (p === "Enter") { } else if (p === "Enter") {
labelParts.push("↩"); // U+21A9 has an emoji presentation, which Chromium's font fallback picks
// (a blue glyph among monochrome ones). U+FE0E forces the text form.
labelParts.push("↩︎");
} else if (p === "Tab") { } else if (p === "Tab") {
labelParts.push("⇥"); labelParts.push("⇥");
} else if (p === "Backspace") { } else if (p === "Backspace") {
+1
View File
@@ -59,6 +59,7 @@ const ALL_CAPABILITIES: PlatformCapabilities = {
localFiles: true, localFiles: true,
timeline: true, timeline: true,
multiWindow: true, multiWindow: true,
windowChrome: true,
plugins: true, plugins: true,
encryption: true, encryption: true,
updater: true, updater: true,
+7
View File
@@ -257,6 +257,13 @@ export interface PlatformCapabilities {
timeline: boolean; timeline: boolean;
/** More than one window or tab on the same data. */ /** More than one window or tab on the same data. */
multiWindow: boolean; multiWindow: boolean;
/**
* The page is the window's titlebar: it draws the drag region and window
* controls, and leaves room for macOS traffic lights. False when something
* else owns the frame around the page (a browser tab), so none of that
* chrome should be reserved or drawn.
*/
windowChrome: boolean;
/** The plugin runtime. */ /** The plugin runtime. */
plugins: boolean; plugins: boolean;
/** Workspace encryption backed by a key the host keeps. */ /** Workspace encryption backed by a key the host keeps. */
+4 -1
View File
@@ -138,13 +138,16 @@ Reported honestly, so callers gate on the question rather than on the host:
| True | False | | True | False |
| --- | --- | | --- | --- |
| `httpSending`, `timeline`, `cookieJar` | `grpc`, `websocket`, `git`, `sync`, `tlsOptions`, `localFiles`, `multiWindow`, `plugins`, `encryption`, `updater`, `clipboardRead`, `systemFonts`, `license` | | `httpSending`, `timeline`, `cookieJar` | `grpc`, `websocket`, `git`, `sync`, `tlsOptions`, `localFiles`, `multiWindow`, `windowChrome`, `plugins`, `encryption`, `updater`, `clipboardRead`, `systemFonts`, `license` |
`multiWindow: false` means the host cannot open a *second window* on demand — `multiWindow: false` means the host cannot open a *second window* on demand —
what `cmd_new_child_window` does for Settings and workspace switching. It is not what `cmd_new_child_window` does for Settings and workspace switching. It is not
a claim that nothing else is looking: other tabs may well be open on the same a claim that nothing else is looking: other tabs may well be open on the same
worker, and it pushes every write to all of them regardless. worker, and it pushes every write to all of them regardless.
`windowChrome: false` means the browser owns the frame around the page, so the
header draws no window controls and reserves no room for macOS traffic lights.
## Multiple tabs ## Multiple tabs
Each tab mints a label at load (`tab_xxxxxxxx`) and sends it with every command; Each tab mints a label at load (`tab_xxxxxxxx`) and sends it with every command;
+3
View File
@@ -54,6 +54,9 @@ function capabilitiesFor(): PlatformCapabilities {
// else is looking: other tabs may well be open on the same worker, and it // else is looking: other tabs may well be open on the same worker, and it
// pushes every write to all of them regardless of this flag. // pushes every write to all of them regardless of this flag.
multiWindow: false, multiWindow: false,
// The browser draws the frame around the page. There are no traffic lights
// to leave room for and no window controls to draw.
windowChrome: false,
plugins: false, plugins: false,
encryption: false, encryption: false,
updater: false, updater: false,
+9 -4
View File
@@ -1,3 +1,4 @@
import { useCapability } from "@yaakapp-internal/platform";
import classNames from "classnames"; import classNames from "classnames";
import type { CSSProperties, HTMLAttributes, ReactNode } from "react"; import type { CSSProperties, HTMLAttributes, ReactNode } from "react";
import { useMemo } from "react"; import { useMemo } from "react";
@@ -31,6 +32,10 @@ export function HeaderSize({
interfaceScale, interfaceScale,
}: HeaderSizeProps) { }: HeaderSizeProps) {
const isFullscreen = useIsFullscreen(); const isFullscreen = useIsFullscreen();
// The header only doubles as the titlebar when the host hands the page the
// window frame (Tauri) and the user hasn't opted for the native one. In a
// browser tab the frame is the browser's: no controls, no traffic lights.
const drawsWindowChrome = useCapability("windowChrome") && !useNativeTitlebar;
const finalStyle = useMemo<CSSProperties>(() => { const finalStyle = useMemo<CSSProperties>(() => {
const s = { ...style }; const s = { ...style };
@@ -38,8 +43,8 @@ export function HeaderSize({
if (size === "md") s.minHeight = HEADER_SIZE_MD; if (size === "md") s.minHeight = HEADER_SIZE_MD;
if (size === "lg") s.minHeight = HEADER_SIZE_LG; if (size === "lg") s.minHeight = HEADER_SIZE_LG;
if (useNativeTitlebar) { if (!drawsWindowChrome) {
// No style updates when using native titlebar // No style updates when something else draws the titlebar
} else if (osType === "macos") { } else if (osType === "macos") {
if (!isFullscreen) { if (!isFullscreen) {
// Add large padding for window controls // Add large padding for window controls
@@ -57,7 +62,7 @@ export function HeaderSize({
interfaceScale, interfaceScale,
size, size,
style, style,
useNativeTitlebar, drawsWindowChrome,
osType, osType,
]); ]);
@@ -82,7 +87,7 @@ export function HeaderSize({
> >
{children} {children}
</div> </div>
{!hideControls && !useNativeTitlebar && ( {!hideControls && drawsWindowChrome && (
<WindowControls <WindowControls
onlyX={onlyXWindowControl} onlyX={onlyXWindowControl}
osType={osType} osType={osType}
+4 -1
View File
@@ -17,7 +17,10 @@ import { fileURLToPath } from "url";
const __dirname = path.dirname(fileURLToPath(import.meta.url)); const __dirname = path.dirname(fileURLToPath(import.meta.url));
const isBranchCheckout = process.argv[4] === "1"; // Git supplies three arguments when invoking this as a post-checkout hook. When run directly,
// assume the caller wants to configure the current worktree instead of requiring placeholder refs.
const isManualRun = process.argv.length === 2;
const isBranchCheckout = isManualRun || process.argv[4] === "1";
if (!isBranchCheckout) { if (!isBranchCheckout) {
process.exit(0); process.exit(0);