Skip to main content

nightshade_api/web/
styles.rs

1//! Assembles and injects the component stylesheet, wrapped in an
2//! `@layer nightshade` cascade layer so app CSS always wins.
3
4use leptos::prelude::*;
5
6/// Concatenate every component stylesheet, wrapped in an
7/// `@layer nightshade { ... }` cascade layer.
8pub fn stylesheet() -> String {
9    let mut css = String::new();
10    css.push_str(include_str!("../../css/core.css"));
11    css.push_str(include_str!("../../css/forms.css"));
12    css.push_str(include_str!("../../css/menus.css"));
13    css.push_str(include_str!("../../css/palette.css"));
14    css.push_str(include_str!("../../css/code_editor.css"));
15    css.push_str(include_str!("../../css/table.css"));
16    css.push_str(include_str!("../../css/tree.css"));
17    css.push_str(include_str!("../../css/inspector.css"));
18    css.push_str(include_str!("../../css/dock.css"));
19    css.push_str(include_str!("../../css/overlays.css"));
20    css.push_str(include_str!("../../css/virtual_list.css"));
21    css.push_str(include_str!("../../css/diff.css"));
22    css.push_str(include_str!("../../css/drag.css"));
23    css.push_str(include_str!("../../css/undo_tree.css"));
24    css.push_str(include_str!("../../css/jump.css"));
25    css.push_str(include_str!("../../css/terminal.css"));
26    css.push_str(include_str!("../../css/workspace.css"));
27    css.push_str(include_str!("../../css/code_surface.css"));
28    css.push_str(include_str!("../../css/disclosure.css"));
29    css.push_str(include_str!("../../css/status_bar.css"));
30    css.push_str(include_str!("../../css/toolbar.css"));
31    css.push_str(include_str!("../../css/log.css"));
32    css.push_str(include_str!("../../css/markdown.css"));
33    css.push_str(include_str!("../../css/search_list.css"));
34    css.push_str(include_str!("../../css/asset_grid.css"));
35    css.push_str(include_str!("../../css/list_editor.css"));
36    css.push_str(include_str!("../../css/chat.css"));
37    css.push_str(include_str!("../../css/dynamic_form.css"));
38    css.push_str(include_str!("../../css/viewport.css"));
39    format!("@layer nightshade {{\n{css}\n}}\n")
40}
41
42const STYLE_ID: &str = "nightshade-styles";
43
44fn inject() {
45    let Some(document) = web_sys::window().and_then(|window| window.document()) else {
46        return;
47    };
48    if document.get_element_by_id(STYLE_ID).is_some() {
49        return;
50    }
51    let Some(head) = document.head() else {
52        return;
53    };
54    let Ok(element) = document.create_element("style") else {
55        return;
56    };
57    let _ = element.set_attribute("id", STYLE_ID);
58    element.set_text_content(Some(&stylesheet()));
59    let _ = head.append_child(&element);
60}
61
62/// Injects the [`stylesheet`] into `<head>` once (idempotent by element id).
63/// Render this near the root of your app.
64#[component]
65pub fn UiStyles() -> impl IntoView {
66    inject();
67}