Skip to content
Merged
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
48 changes: 48 additions & 0 deletions src-tauri/tests/packaging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,3 +253,51 @@ fn debian_control_is_templated_for_per_series_rust() {
);
}
}

/// The permission dialog's action row must live OUTSIDE the scrolling body.
///
/// `.dialog-content` scrolls, and while the buttons were inside it the primary
/// action sat below the fold at the app's own 700px minimum window height, with
/// nothing indicating it was there. A first-run user could not find "Setup
/// Permissions" without discovering they had to scroll a dialog.
#[test]
fn dialog_actions_are_not_inside_the_scrolling_body() {
let html = read("src/templates/dialogs.html");

let actions = html
.find(r#"class="dialog-actions""#)
.expect("permission dialog has an action row");
let content_close = html[..actions]
.rfind("</div>")
.expect("something closes before the actions");

// The action row must come after .dialog-content closes. Comparing indices
// is enough because the row is the last element in the container.
assert!(
content_close < actions,
"the action row must follow the scrolling content, not sit inside it"
);

assert!(
html.contains(r#"id="setup-permissions""#),
"the primary action must still exist"
);
}

/// The pinned row only stays pinned if the container is a flex column. As a
/// plain block, the row is pushed past max-height rather than held in view --
/// which looks identical in a wide window and breaks in a short one.
#[test]
fn the_dialog_container_is_a_flex_column() {
let css = read("src/styles/dialogs.css");
let start = css
.find(".dialog-container {")
.expect(".dialog-container is styled");
let block = &css[start..start + css[start..].find('}').expect("rule closes")];

assert!(block.contains("display: flex"), "container must be flex");
assert!(
block.contains("flex-direction: column"),
"container must stack header, content and actions vertically"
);
}
37 changes: 36 additions & 1 deletion src/styles/dialogs.css
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@
max-width: 500px;
max-height: 90vh;
overflow: hidden;

/* Column layout so .dialog-content can scroll while .dialog-actions stays
pinned at the bottom. Without this the container is a block and the action
row is pushed past max-height instead of held in view. */
display: flex;
flex-direction: column;
box-shadow: 0 20px 60px rgb(0 0 0 / 50%);
animation: slideUp 0.3s ease;
}
Expand Down Expand Up @@ -112,7 +118,12 @@
.dialog-content {
padding: 24px 32px 32px;
overflow-y: auto;
max-height: calc(90vh - 180px);

/* Flex within the column rather than a fixed vh calculation: the old
calc(90vh - 180px) guessed at the header and footer heights and was wrong
whenever either changed. */
flex: 1 1 auto;
min-height: 0;
}

.dialog-description {
Expand Down Expand Up @@ -288,3 +299,27 @@
color: var(--text-primary);
border-color: var(--text-tertiary);
}

/* Action row, pinned below the scrolling body so the primary button is always
reachable.

Named separately from .dialog-footer, which the About dialog uses for centred
copyright text -- overloading it would have restyled that too.

The permission dialog's content is taller than .dialog-content allows at the
app's own 700px minimum window height, and while this lived inside that
scrolling element the Setup button sat below the fold with nothing indicating
it was there. */
.dialog-actions {
display: flex;
gap: 10px;
justify-content: flex-end;
padding: 16px 24px 20px;
border-top: 1px solid var(--border-color);
background: var(--bg-card);

/* Matches .dialog-container's 16px so the pinned row does not square off the
bottom corners. */
border-radius: 0 0 16px 16px;
flex-shrink: 0;
}
16 changes: 9 additions & 7 deletions src/templates/dialogs.html
Original file line number Diff line number Diff line change
Expand Up @@ -189,14 +189,16 @@ <h3>What will be configured:</h3>
You'll be prompted for your password once. After setup, no password will be required.
</p>
</div>
</div>

<div
class="dialog-footer"
style="display: flex; gap: 10px; justify-content: flex-end; margin-top: 20px"
>
<button id="skip-permissions" class="dialog-button-secondary">Skip for Now</button>
<button id="setup-permissions" class="dialog-button-primary">Setup Permissions</button>
</div>
<!-- Outside .dialog-content deliberately. That element scrolls
(max-height: calc(90vh - 180px)), so a footer inside it scrolled the
primary action out of view -- at the app's own 700px minimum window
height the Setup button was below the fold with nothing indicating it
was there. -->
<div class="dialog-actions">
<button id="skip-permissions" class="dialog-button-secondary">Skip for Now</button>
<button id="setup-permissions" class="dialog-button-primary">Setup Permissions</button>
</div>
</div>
</div>
Loading