Open isolated node login surfaces as native macOS tabs with a centered black plus control
Hop-State: A_06FPHFY6SA0R5CXMBRZHG08 Hop-Proposal: R_06FPHFX326Q7FJA5Z4Y4Y08 Hop-Task: T_06FPHEQ8RZX6R1ZVV8WQ43R Hop-Attempt: AT_06FPHEQ8RZVSEZXZ9E88YP0
This commit is contained in:
+21
-14
@@ -328,12 +328,12 @@ fn new_window_button_script(accent_color: Option<&str>) -> String {
|
|||||||
position: fixed; right: 28px; bottom: 28px; z-index: 2147483647;
|
position: fixed; right: 28px; bottom: 28px; z-index: 2147483647;
|
||||||
width: 54px; height: 54px; display: grid; place-items: center;
|
width: 54px; height: 54px; display: grid; place-items: center;
|
||||||
padding: 0; border: 1px solid rgba(255,255,255,.22); border-radius: 50%;
|
padding: 0; border: 1px solid rgba(255,255,255,.22); border-radius: 50%;
|
||||||
color: #fff; background: ${accent};
|
background: ${accent};
|
||||||
box-shadow: 0 13px 34px rgba(0,0,0,.38), 0 0 22px color-mix(in srgb, ${accent} 38%, transparent);
|
box-shadow: 0 13px 34px rgba(0,0,0,.38), 0 0 22px color-mix(in srgb, ${accent} 38%, transparent);
|
||||||
font: 300 32px/1 -apple-system, BlinkMacSystemFont, sans-serif;
|
cursor: pointer;
|
||||||
cursor: pointer; -webkit-font-smoothing: antialiased;
|
|
||||||
transition: transform 160ms ease, filter 160ms ease, opacity 160ms ease;
|
transition: transform 160ms ease, filter 160ms ease, opacity 160ms ease;
|
||||||
}
|
}
|
||||||
|
#${id} svg { display: block; width: 22px; height: 22px; }
|
||||||
#${id}:hover { transform: translateY(-2px) scale(1.04); filter: brightness(1.08); }
|
#${id}:hover { transform: translateY(-2px) scale(1.04); filter: brightness(1.08); }
|
||||||
#${id}:active { transform: scale(.96); }
|
#${id}:active { transform: scale(.96); }
|
||||||
#${id}:focus-visible { outline: 2px solid #fff; outline-offset: 4px; }
|
#${id}:focus-visible { outline: 2px solid #fff; outline-offset: 4px; }
|
||||||
@@ -344,15 +344,15 @@ fn new_window_button_script(accent_color: Option<&str>) -> String {
|
|||||||
const button = document.createElement("button");
|
const button = document.createElement("button");
|
||||||
button.id = id;
|
button.id = id;
|
||||||
button.type = "button";
|
button.type = "button";
|
||||||
button.textContent = "+";
|
button.innerHTML = '<svg viewBox="0 0 22 22" aria-hidden="true"><path d="M11 2.5V19.5M2.5 11H19.5" fill="none" stroke="black" stroke-width="2.5" stroke-linecap="round"/></svg>';
|
||||||
button.setAttribute("aria-label", "Open another Synapsis node window");
|
button.setAttribute("aria-label", "Open another Synapsis node tab");
|
||||||
button.title = "Open another node";
|
button.title = "Open another node tab";
|
||||||
button.addEventListener("click", async () => {
|
button.addEventListener("click", async () => {
|
||||||
button.disabled = true;
|
button.disabled = true;
|
||||||
try {
|
try {
|
||||||
await window.__TAURI_INTERNALS__.invoke("open_login_window");
|
await window.__TAURI_INTERNALS__.invoke("open_login_window");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Could not open another Synapsis window", error);
|
console.error("Could not open another Synapsis node tab", error);
|
||||||
} finally {
|
} finally {
|
||||||
button.disabled = false;
|
button.disabled = false;
|
||||||
}
|
}
|
||||||
@@ -384,22 +384,28 @@ async fn open_login_window(
|
|||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let sequence = state.window_sequence.fetch_add(1, Ordering::Relaxed);
|
let sequence = state.window_sequence.fetch_add(1, Ordering::Relaxed);
|
||||||
let label = format!("node-{sequence}");
|
let label = format!("node-{sequence}");
|
||||||
WebviewWindowBuilder::new(
|
let builder = WebviewWindowBuilder::new(
|
||||||
&app,
|
&app,
|
||||||
label,
|
label,
|
||||||
WebviewUrl::App("index.html?newWindow=1".into()),
|
WebviewUrl::App("index.html?newWindow=1".into()),
|
||||||
)
|
)
|
||||||
|
.initialization_script("window.__SYNAPSIS_FRESH_LOGIN__ = true;")
|
||||||
|
.incognito(true)
|
||||||
.title("Synapsis")
|
.title("Synapsis")
|
||||||
.inner_size(1280.0, 820.0)
|
.inner_size(1280.0, 820.0)
|
||||||
.min_inner_size(720.0, 560.0)
|
.min_inner_size(720.0, 560.0)
|
||||||
.center()
|
.center()
|
||||||
.hidden_title(true)
|
|
||||||
.title_bar_style(tauri::TitleBarStyle::Visible)
|
|
||||||
.theme(Some(tauri::Theme::Dark))
|
.theme(Some(tauri::Theme::Dark))
|
||||||
.background_color(tauri::webview::Color(8, 9, 9, 255))
|
.background_color(tauri::webview::Color(8, 9, 9, 255));
|
||||||
.build()
|
#[cfg(target_os = "macos")]
|
||||||
.map(|_| ())
|
let builder = builder
|
||||||
.map_err(|error| format!("Couldn’t open another Synapsis window: {error}"))
|
.hidden_title(true)
|
||||||
|
.title_bar_style(tauri::TitleBarStyle::Visible)
|
||||||
|
.tabbing_identifier("synapsis-node-tabs");
|
||||||
|
builder
|
||||||
|
.build()
|
||||||
|
.map(|_| ())
|
||||||
|
.map_err(|error| format!("Couldn’t open another Synapsis node tab: {error}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
@@ -565,6 +571,7 @@ mod tests {
|
|||||||
|
|
||||||
assert!(script.contains(r##"const requestedAccent = "#12abef\"; alert(1); //";"##));
|
assert!(script.contains(r##"const requestedAccent = "#12abef\"; alert(1); //";"##));
|
||||||
assert!(script.contains("CSS.supports"));
|
assert!(script.contains("CSS.supports"));
|
||||||
|
assert!(script.contains("stroke=\"black\""));
|
||||||
assert!(script.contains("open_login_window"));
|
assert!(script.contains("open_login_window"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
"center": true,
|
"center": true,
|
||||||
"hiddenTitle": true,
|
"hiddenTitle": true,
|
||||||
"titleBarStyle": "Visible",
|
"titleBarStyle": "Visible",
|
||||||
|
"tabbingIdentifier": "synapsis-node-tabs",
|
||||||
"theme": "Dark",
|
"theme": "Dark",
|
||||||
"backgroundColor": "#080909"
|
"backgroundColor": "#080909"
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-1
@@ -3,6 +3,12 @@ import { invoke, isTauri } from "@tauri-apps/api/core";
|
|||||||
import { isPermissionGranted, requestPermission } from "@tauri-apps/plugin-notification";
|
import { isPermissionGranted, requestPermission } from "@tauri-apps/plugin-notification";
|
||||||
import "./App.css";
|
import "./App.css";
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
__SYNAPSIS_FRESH_LOGIN__?: boolean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type Screen = "node" | "login" | "register" | "home";
|
type Screen = "node" | "login" | "register" | "home";
|
||||||
|
|
||||||
type NodeInfo = {
|
type NodeInfo = {
|
||||||
@@ -268,7 +274,8 @@ function App() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const launchParams = new URLSearchParams(window.location.search);
|
const launchParams = new URLSearchParams(window.location.search);
|
||||||
if (launchParams.has("newWindow")) {
|
if (window.__SYNAPSIS_FRESH_LOGIN__ || launchParams.has("newWindow")) {
|
||||||
|
window.__SYNAPSIS_FRESH_LOGIN__ = false;
|
||||||
window.history.replaceState({}, "", window.location.pathname);
|
window.history.replaceState({}, "", window.location.pathname);
|
||||||
setScreen("node");
|
setScreen("node");
|
||||||
setBootstrapping(false);
|
setBootstrapping(false);
|
||||||
|
|||||||
Reference in New Issue
Block a user