generated from mountainridge-xyz/mont-fort-app-new
Initial commit
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
package-lock.json
|
||||||
|
Cargo.lock
|
||||||
|
/node_modules
|
||||||
|
/target
|
||||||
|
/dist
|
||||||
|
/.idea
|
||||||
|
/.git
|
||||||
+277
@@ -0,0 +1,277 @@
|
|||||||
|
|
||||||
|
### JetBrains template
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/**/usage.statistics.xml
|
||||||
|
.idea/**/dictionaries
|
||||||
|
.idea/**/shelf
|
||||||
|
|
||||||
|
# AWS User-specific
|
||||||
|
.idea/**/aws.xml
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
.idea/**/contentModel.xml
|
||||||
|
|
||||||
|
# Sensitive or high-churn files
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
.idea/**/dbnavigator.xml
|
||||||
|
|
||||||
|
# Gradle
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# Gradle and Maven with auto-import
|
||||||
|
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||||
|
# since they will be recreated, and may cause churn. Uncomment if using
|
||||||
|
# auto-import.
|
||||||
|
# .idea/artifacts
|
||||||
|
# .idea/compiler.xml
|
||||||
|
# .idea/jarRepositories.xml
|
||||||
|
# .idea/modules.xml
|
||||||
|
# .idea/*.iml
|
||||||
|
# .idea/modules
|
||||||
|
# *.iml
|
||||||
|
# *.ipr
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build-*/
|
||||||
|
|
||||||
|
# Mongo Explorer plugin
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
# File-based project format
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# SonarLint plugin
|
||||||
|
.idea/sonarlint/
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
# Editor-based Rest Client
|
||||||
|
.idea/httpRequests
|
||||||
|
|
||||||
|
# Android studio 3.1+ serialized cache file
|
||||||
|
.idea/caches/build_file_checksums.ser
|
||||||
|
|
||||||
|
### Rust template
|
||||||
|
# Generated by Cargo
|
||||||
|
# will have compiled files and executables
|
||||||
|
debug/
|
||||||
|
target/
|
||||||
|
dist/
|
||||||
|
|
||||||
|
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||||
|
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||||
|
Cargo.lock
|
||||||
|
|
||||||
|
# These are backup files generated by rustfmt
|
||||||
|
**/*.rs.bk
|
||||||
|
|
||||||
|
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||||
|
*.pdb
|
||||||
|
|
||||||
|
# RustRover
|
||||||
|
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||||
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
|
#.idea/
|
||||||
|
### Linux template
|
||||||
|
*~
|
||||||
|
|
||||||
|
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||||
|
.fuse_hidden*
|
||||||
|
|
||||||
|
# KDE directory preferences
|
||||||
|
.directory
|
||||||
|
|
||||||
|
# Linux trash folder which might appear on any partition or disk
|
||||||
|
.Trash-*
|
||||||
|
|
||||||
|
# .nfs files are created when an open file is removed but is still being accessed
|
||||||
|
.nfs*
|
||||||
|
|
||||||
|
### Node template
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
.pnpm-debug.log*
|
||||||
|
|
||||||
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# Snowpack dependency directory (https://snowpack.dev/)
|
||||||
|
web_modules/
|
||||||
|
|
||||||
|
# TypeScript cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional stylelint cache
|
||||||
|
.stylelintcache
|
||||||
|
|
||||||
|
# Microbundle cache
|
||||||
|
.rpt2_cache/
|
||||||
|
.rts2_cache_cjs/
|
||||||
|
.rts2_cache_es/
|
||||||
|
.rts2_cache_umd/
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variable files
|
||||||
|
.env
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
.env.local
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
.cache
|
||||||
|
.parcel-cache
|
||||||
|
|
||||||
|
# Next.js build output
|
||||||
|
.next
|
||||||
|
out
|
||||||
|
|
||||||
|
# Nuxt.js build / generate output
|
||||||
|
.nuxt
|
||||||
|
dist
|
||||||
|
|
||||||
|
# Gatsby files
|
||||||
|
.cache/
|
||||||
|
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||||
|
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||||
|
# public
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# vuepress v2.x temp and cache directory
|
||||||
|
.temp
|
||||||
|
.cache
|
||||||
|
|
||||||
|
# Docusaurus cache and generated files
|
||||||
|
.docusaurus
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless/
|
||||||
|
|
||||||
|
# FuseBox cache
|
||||||
|
.fusebox/
|
||||||
|
|
||||||
|
# DynamoDB Local files
|
||||||
|
.dynamodb/
|
||||||
|
|
||||||
|
# TernJS port file
|
||||||
|
.tern-port
|
||||||
|
|
||||||
|
# Stores VSCode versions used for testing VSCode extensions
|
||||||
|
.vscode-test
|
||||||
|
|
||||||
|
# yarn v2
|
||||||
|
.yarn/cache
|
||||||
|
.yarn/unplugged
|
||||||
|
.yarn/build-state.yml
|
||||||
|
.yarn/install-state.gz
|
||||||
|
.pnp.*
|
||||||
|
|
||||||
|
### macOS template
|
||||||
|
# General
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
Generated
+10
@@ -0,0 +1,10 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Ignored default folder with query files
|
||||||
|
/queries/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
Generated
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectRootManager" version="2">
|
||||||
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
# AGENTS.md
|
||||||
|
|
||||||
|
Iframe Leptos CSR aka "Mont Fort App" craft. Data from generated Matterhorn `*Api`. Theme is `mountainridge`. You implement pages. You do not own codegen, hosting, or the toolchain.
|
||||||
|
|
||||||
|
Use the injected workspace tools for git, check, build, issues, and Matterhorn deps. Do not shell out to `git` / `cargo` / `npm` / `trunk`. Commit only if asked (`feat:` / `fix:` / `docs:` / `refactor:`).
|
||||||
|
|
||||||
|
## Frozen
|
||||||
|
|
||||||
|
`src/codegen/**`, `schemas/`, `read_app_config`, `index.html` config script + `<base>` + asset `copy-dir`, `Router base`, `data-theme="mountainridge"`, `src/styles.css` theme block, `Cargo.toml`.
|
||||||
|
|
||||||
|
Missing entity → Matterhorn-search tool → Matterhorn-dep tool, then generate. Still missing → issue, stop. New crate or new CSS tokens → stop. Field not on the struct → migration, not a UI hack.
|
||||||
|
|
||||||
|
## Layout
|
||||||
|
|
||||||
|
```text
|
||||||
|
src/main.rs mount
|
||||||
|
src/app.rs App + Shell + routes + nav ← register here
|
||||||
|
src/context.rs AppCtx
|
||||||
|
src/components/ pages + PageHeader, EmptyView, ErrorView
|
||||||
|
src/codegen/ read-only types + *Api
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let ctx = expect_context::<AppCtx>();
|
||||||
|
let api = ThingApi::new(ctx.matterhorn_config.clone());
|
||||||
|
```
|
||||||
|
|
||||||
|
Pages never read `window.__embeddedAppConfig`. Config failure is handled in `App`.
|
||||||
|
|
||||||
|
## Page
|
||||||
|
|
||||||
|
`src/components/<entity>_list.rs` → export in `mod.rs` → one relative `<Route>` and one `href="./…"` `<A>` in `src/app.rs`. Do not touch `main.rs`.
|
||||||
|
|
||||||
|
Flat siblings under `/`. Nest a `ParentRoute` only for a second `<Outlet/>`. `path!("features")`, never `path!("/features")`.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let data = LocalResource::new(move || {
|
||||||
|
let api = api.clone();
|
||||||
|
async move { api.fetch_thing(vec![], vec![], HashMap::new(), 50, 0).await }
|
||||||
|
});
|
||||||
|
|
||||||
|
view! {
|
||||||
|
<PageHeader title="Things" subtitle="From Matterhorn."/>
|
||||||
|
{move || Suspend::new(async move {
|
||||||
|
match data.await {
|
||||||
|
Ok(rows) if rows.is_empty() => view! { <EmptyView title="No records" message="Nothing was returned."/> }.into_any(),
|
||||||
|
Ok(rows) => view! { /* Option<T> fields only */ }.into_any(),
|
||||||
|
Err(err) => view! { <ErrorView title="Could not load records" message=err.to_string()/> }.into_any(),
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Do not add `<Suspense>`. Do not call `.get()` on the resource. `store_*` / forms only if the user asked. Projections = schema names (`createdAt`, not `created_at`).
|
||||||
|
|
||||||
|
`view!` text is quoted. `leptos::prelude::*`, not `use leptos::*`. `<A>` takes `attr:class` (or `{..} class`). Brand/nav is not a `.btn`.
|
||||||
|
|
||||||
|
## UI
|
||||||
|
|
||||||
|
DaisyUI on `mountainridge`: `card`, `table`, `badge`, `menu`. Real `.btn` for submit/delete only. No `tailwind.config.*`. No page CSS. Scroll, if needed, is `min-h-0 flex-1 overflow-y-auto` on the page body — not `h-dvh`, not `html` overflow.
|
||||||
|
|
||||||
|
## Done
|
||||||
|
|
||||||
|
`check` + `build` clean. Diff = new page + `mod.rs` + `app.rs`. Theme, styles, codegen, Cargo untouched.
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
[package]
|
||||||
|
name = "r_155e2f5f_dc_9f_464d_bed2_18120959d71b"
|
||||||
|
repository = "http://mridge-gitea:3000/debbster/155e2f5f-dc9f-464d-bed2-18120959d71b.git"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
leptos = { version = "0.8", features = ["csr"] }
|
||||||
|
leptos_router = "0.8"
|
||||||
|
console_error_panic_hook = "0.1"
|
||||||
|
wasm-bindgen = "0.2"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
matterhorn-client = { version = "0.1" }
|
||||||
|
uuid = { version = "1", features = ["serde"] }
|
||||||
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
|
anyhow = "1.0"
|
||||||
|
serde_json = "1.0.149"
|
||||||
|
reqwest = { version = "0.13", features = ["json"] }
|
||||||
|
thiserror = "2.0"
|
||||||
|
once_cell = "1.21"
|
||||||
|
tokio = { version = "1.53", features = ["sync"] }
|
||||||
|
gloo-timers = { version = "0.4", features = ["futures"] }
|
||||||
|
base64 = "0.23"
|
||||||
|
regress = "0.12"
|
||||||
|
web-sys = "0.3"
|
||||||
|
wasm-bindgen-futures = "0.4"
|
||||||
|
js-sys = "0.3"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[build]
|
||||||
|
filehash = false
|
||||||
|
public_url = "/crafts/releases/debbster/155e2f5f-dc9f-464d-bed2-18120959d71b/"
|
||||||
|
|
||||||
|
[serve]
|
||||||
|
addresses = ["0.0.0.0"]
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 82 KiB |
+23
@@ -0,0 +1,23 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" data-theme="mountainridge">
|
||||||
|
<head>
|
||||||
|
<base data-trunk-public-url/>
|
||||||
|
<meta charset="UTF-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
|
<title>MountainRidge.xyz - Mont Fort App</title>
|
||||||
|
|
||||||
|
<link data-trunk rel="copy-dir" href="./assets"/>
|
||||||
|
<link rel="icon" href="assets/mridge-craft-icon.webp"/>
|
||||||
|
<link rel="stylesheet" type="text/css" href="assets/styles.css"/>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.__embeddedAppConfig = {};
|
||||||
|
window.addEventListener('message', function (e) {
|
||||||
|
if (e.data.type === 'APP_CONFIG') {
|
||||||
|
window.__embeddedAppConfig = e.data;
|
||||||
|
}
|
||||||
|
}, {once: true});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"@fontsource/geist": "^5.3.0",
|
||||||
|
"daisyui": "^5.5.18",
|
||||||
|
"tailwindcss": "^4.2.1"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build-craft": "npm install && tailwindcss -i src/styles.css -o assets/styles.css --minify && trunk build --config Trunk.toml",
|
||||||
|
"fmt": "cargo fmt",
|
||||||
|
"check": "cargo fmt && cargo check --all-targets --all-features -q --message-format short --color never",
|
||||||
|
"lint": "cargo clippy --all-targets --all-features -- -D warnings",
|
||||||
|
"test": "cargo test --all-targets --all-features"
|
||||||
|
}
|
||||||
|
}
|
||||||
+97
@@ -0,0 +1,97 @@
|
|||||||
|
use crate::components::{
|
||||||
|
ConfigError, ErrorView, Home, LoadingView, SoftwareFeatureList,
|
||||||
|
};
|
||||||
|
use crate::context::{read_app_config, AppCtx};
|
||||||
|
use leptos::prelude::*;
|
||||||
|
use leptos_router::components::{A, Outlet, ParentRoute, Route, Router, Routes};
|
||||||
|
use leptos_router::path;
|
||||||
|
|
||||||
|
/// Register new pages here: add a `<Route>` and a matching nav `<A>`.
|
||||||
|
#[component]
|
||||||
|
pub fn App() -> impl IntoView {
|
||||||
|
match read_app_config() {
|
||||||
|
None => view! { <ConfigError/> }.into_any(),
|
||||||
|
Some(config) => {
|
||||||
|
provide_context(config.clone());
|
||||||
|
view! {
|
||||||
|
<Router base=config.base_path>
|
||||||
|
<Routes fallback=|| view! { <p>"Not found"</p> }>
|
||||||
|
<ParentRoute path=path!("/") view=Shell>
|
||||||
|
<Route path=path!("") view=Home/>
|
||||||
|
</ParentRoute>
|
||||||
|
</Routes>
|
||||||
|
</Router>
|
||||||
|
}
|
||||||
|
.into_any()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn Shell() -> impl IntoView {
|
||||||
|
let ctx = expect_context::<AppCtx>();
|
||||||
|
let user = ctx.user.clone().unwrap_or_else(|| "Guest".to_string());
|
||||||
|
let logo = ctx.asset_path("mridge-craft-icon.webp");
|
||||||
|
|
||||||
|
view! {
|
||||||
|
<div class="drawer lg:drawer-open h-full max-h-full min-h-0 w-full overflow-hidden bg-base-200">
|
||||||
|
<input id="app-drawer" type="checkbox" class="drawer-toggle"/>
|
||||||
|
|
||||||
|
<div class="drawer-content flex h-full min-h-0 flex-col overflow-hidden bg-base-200">
|
||||||
|
<header class="navbar min-h-14 shrink-0 border-b border-base-300 bg-base-100 px-3">
|
||||||
|
<div class="navbar-start gap-3">
|
||||||
|
<label for="app-drawer" class="cursor-pointer p-2 lg:hidden" aria-label="Open menu">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/>
|
||||||
|
</svg>
|
||||||
|
</label>
|
||||||
|
<A href="./" attr:class="flex items-center gap-3 no-underline text-base-content">
|
||||||
|
<img class="h-8 w-8 shrink-0 object-contain" src=logo alt=""/>
|
||||||
|
<span class="text-base font-medium tracking-wide">"Mont Fort"</span>
|
||||||
|
</A>
|
||||||
|
</div>
|
||||||
|
<div class="navbar-end">
|
||||||
|
<span class="hidden px-2 text-sm opacity-70 sm:inline">{user.clone()}</span>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="flex min-h-0 flex-1 flex-col overflow-hidden p-4 sm:p-6">
|
||||||
|
<div class="mx-auto flex h-full min-h-0 w-full max-w-6xl flex-col">
|
||||||
|
<ErrorBoundary fallback=|errors| {
|
||||||
|
view! {
|
||||||
|
<ErrorView
|
||||||
|
title="Something went wrong"
|
||||||
|
message=format!("{errors:?}")
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
}>
|
||||||
|
<Suspense fallback=|| view! { <LoadingView/> }>
|
||||||
|
<Outlet/>
|
||||||
|
</Suspense>
|
||||||
|
</ErrorBoundary>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="drawer-side z-20 h-full">
|
||||||
|
<label for="app-drawer" class="drawer-overlay" aria-label="Close menu"></label>
|
||||||
|
<aside class="flex h-full w-72 flex-col bg-base-100">
|
||||||
|
<div class="flex items-center gap-3 border-b border-base-300 px-4 py-4">
|
||||||
|
<span class="font-semibold">"Navigation"</span>
|
||||||
|
</div>
|
||||||
|
<ul class="menu flex-1 gap-1 p-3">
|
||||||
|
<li>
|
||||||
|
<A href="./" exact=true>"Home"</A>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<A href="./features">"Features"</A>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="border-t border-base-300 p-4 text-sm opacity-70 lg:hidden">
|
||||||
|
{user}
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
use leptos::prelude::*;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn ConfigError() -> impl IntoView {
|
||||||
|
view! {
|
||||||
|
<div class="flex h-dvh w-full items-center justify-center bg-base-200 p-6">
|
||||||
|
<div class="card w-full max-w-lg bg-base-100 shadow-xl">
|
||||||
|
<div class="card-body">
|
||||||
|
<h1 class="card-title text-error">"Configuration unavailable"</h1>
|
||||||
|
<p>
|
||||||
|
"This craft did not receive APP_CONFIG from the host. "
|
||||||
|
"token and matterhorn_base_url are required."
|
||||||
|
</p>
|
||||||
|
<p class="text-sm opacity-70">
|
||||||
|
"Reload the preview after the host has posted the iframe message. Do not continue without config."
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
use leptos::prelude::*;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn EmptyView(
|
||||||
|
#[prop(default = "Nothing to show")] title: &'static str,
|
||||||
|
#[prop(default = "No records were returned.")] message: &'static str,
|
||||||
|
) -> impl IntoView {
|
||||||
|
view! {
|
||||||
|
<div class="flex flex-col items-center justify-center gap-2 py-12 text-center">
|
||||||
|
<h3 class="font-semibold">{title}</h3>
|
||||||
|
<p class="text-sm opacity-70">{message}</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
use leptos::prelude::*;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn ErrorView(
|
||||||
|
#[prop(default = "Something went wrong")] title: &'static str,
|
||||||
|
message: String,
|
||||||
|
) -> impl IntoView {
|
||||||
|
view! {
|
||||||
|
<div role="alert" class="alert alert-error">
|
||||||
|
<div>
|
||||||
|
<h3 class="font-bold">{title}</h3>
|
||||||
|
<p class="text-sm">{message}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
use crate::components::PageHeader;
|
||||||
|
use leptos::prelude::*;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn Home() -> impl IntoView {
|
||||||
|
view! {
|
||||||
|
<PageHeader title="Welcome" subtitle="MountainRidge craft is ready."/>
|
||||||
|
<div class="card bg-base-100 shadow-xl">
|
||||||
|
<div class="card-body">
|
||||||
|
<p>"Use the navigation to open generated entity pages."</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
use leptos::prelude::*;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn LoadingView(#[prop(default = "Loading…")] label: &'static str) -> impl IntoView {
|
||||||
|
view! {
|
||||||
|
<div class="flex items-center justify-center gap-3 py-12">
|
||||||
|
<span class="loading loading-spinner loading-md"></span>
|
||||||
|
<span class="text-sm opacity-70">{label}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
mod config_error;
|
||||||
|
mod empty_view;
|
||||||
|
mod error_view;
|
||||||
|
mod home;
|
||||||
|
mod loading_view;
|
||||||
|
mod page_header;
|
||||||
|
|
||||||
|
pub use config_error::ConfigError;
|
||||||
|
pub use empty_view::EmptyView;
|
||||||
|
pub use error_view::ErrorView;
|
||||||
|
pub use home::Home;
|
||||||
|
pub use loading_view::LoadingView;
|
||||||
|
pub use page_header::PageHeader;
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
use leptos::prelude::*;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn PageHeader(
|
||||||
|
title: &'static str,
|
||||||
|
#[prop(optional)] subtitle: Option<&'static str>,
|
||||||
|
#[prop(optional)] children: Option<Children>,
|
||||||
|
) -> impl IntoView {
|
||||||
|
view! {
|
||||||
|
<div class="mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||||
|
<div>
|
||||||
|
<h1 class="text-2xl font-semibold">{title}</h1>
|
||||||
|
{subtitle.map(|text| view! { <p class="text-sm opacity-70">{text}</p> })}
|
||||||
|
</div>
|
||||||
|
<div class="flex shrink-0 items-center gap-2">
|
||||||
|
{children.map(|c| c())}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
+100
@@ -0,0 +1,100 @@
|
|||||||
|
use matterhorn_client::ClientConfig;
|
||||||
|
use wasm_bindgen::JsValue;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct AppCtx {
|
||||||
|
pub user: Option<String>,
|
||||||
|
pub base_path: String,
|
||||||
|
pub matterhorn_config: ClientConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AppCtx {
|
||||||
|
pub fn asset_path(&self, file: &str) -> String {
|
||||||
|
format!("{}assets/{}", self.base_path, file.trim_start_matches('/'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clog(msg: impl AsRef<str>) {
|
||||||
|
web_sys::console::log_1(&JsValue::from_str(&format!(
|
||||||
|
"[craft config] {}",
|
||||||
|
msg.as_ref()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn js_type_name(value: &JsValue) -> String {
|
||||||
|
if value.is_undefined() {
|
||||||
|
"undefined".into()
|
||||||
|
} else if value.is_null() {
|
||||||
|
"null".into()
|
||||||
|
} else if let Some(s) = value.as_string() {
|
||||||
|
format!("string(len={})", s.len())
|
||||||
|
} else {
|
||||||
|
js_sys::Object::from(value.clone()).to_string().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn field_string(raw: &JsValue, key: &str) -> Option<String> {
|
||||||
|
let value = js_sys::Reflect::get(raw, &JsValue::from_str(key)).ok()?;
|
||||||
|
clog(format!("{key}: {}", js_type_name(&value)));
|
||||||
|
value.as_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads iframe-injected `window.__embeddedAppConfig`.
|
||||||
|
/// Expected payload:
|
||||||
|
/// `{ type: "APP_CONFIG", token, user, matterhorn_base_url }`
|
||||||
|
pub fn read_app_config() -> Option<AppCtx> {
|
||||||
|
clog("read_app_config()");
|
||||||
|
|
||||||
|
let base_path = web_sys::window()
|
||||||
|
.and_then(|w| w.document())
|
||||||
|
.and_then(|d| d.query_selector("base").ok().flatten())
|
||||||
|
.and_then(|el| el.get_attribute("href"))
|
||||||
|
.unwrap_or_else(|| "/".to_string());
|
||||||
|
|
||||||
|
let window = match web_sys::window() {
|
||||||
|
Some(w) => w,
|
||||||
|
None => {
|
||||||
|
clog("window is missing");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let embedded = js_sys::Reflect::get(&window, &"__embeddedAppConfig".into()).ok();
|
||||||
|
let raw = match embedded {
|
||||||
|
Some(value) if !value.is_undefined() && !value.is_null() => value,
|
||||||
|
_ => {
|
||||||
|
clog("no usable __embeddedAppConfig");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let token = match field_string(&raw, "token") {
|
||||||
|
Some(value) if !value.is_empty() => value,
|
||||||
|
Some(_) => {
|
||||||
|
clog("token is empty — host message not applied yet?");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
clog("token is not a string");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let base_url = match field_string(&raw, "matterhorn_base_url") {
|
||||||
|
Some(value) if !value.is_empty() => value,
|
||||||
|
Some(_) => {
|
||||||
|
clog("matterhorn_base_url is empty");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
clog("matterhorn_base_url is not a string");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let user = field_string(&raw, "username");
|
||||||
|
|
||||||
|
Some(AppCtx {
|
||||||
|
user,
|
||||||
|
base_path,
|
||||||
|
matterhorn_config: ClientConfig { base_url, token },
|
||||||
|
})
|
||||||
|
}
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
mod app;
|
||||||
|
mod context;
|
||||||
|
mod components;
|
||||||
|
mod codegen;
|
||||||
|
|
||||||
|
use app::App;
|
||||||
|
use leptos::mount::mount_to_body;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
console_error_panic_hook::set_once();
|
||||||
|
mount_to_body(App);
|
||||||
|
}
|
||||||
+315
@@ -0,0 +1,315 @@
|
|||||||
|
@import "@fontsource/geist/200.css";
|
||||||
|
@import "@fontsource/geist/300.css";
|
||||||
|
@import "@fontsource/geist/400.css";
|
||||||
|
@import "@fontsource/geist/500.css";
|
||||||
|
@import "@fontsource/geist/600.css";
|
||||||
|
@import "tailwindcss";
|
||||||
|
|
||||||
|
@plugin "daisyui" {
|
||||||
|
themes: mountainridge --default;
|
||||||
|
darkTheme: mountainridge;
|
||||||
|
base: true;
|
||||||
|
styled: true;
|
||||||
|
utils: true;
|
||||||
|
logs: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@plugin "daisyui/theme" {
|
||||||
|
name: "mountainridge";
|
||||||
|
default: true;
|
||||||
|
prefersdark: true;
|
||||||
|
color-scheme: "dark";
|
||||||
|
font-family: "Geist", system-ui, sans-serif;
|
||||||
|
/* Backgrounds — charcoal scale */
|
||||||
|
--color-base-100: oklch(16% 0.02 214);
|
||||||
|
--color-base-200: oklch(13% 0.02 214);
|
||||||
|
--color-base-300: oklch(10% 0.02 214);
|
||||||
|
--color-base-content: oklch(92% 0.005 214);
|
||||||
|
|
||||||
|
/* Primary — sea-grass green rgb(88, 191, 177) */
|
||||||
|
--color-primary: oklch(72% 0.097 183);
|
||||||
|
--color-primary-content: oklch(13% 0.02 214);
|
||||||
|
|
||||||
|
/* Secondary — glacier light blue rgb(94, 150, 159) */
|
||||||
|
--color-secondary: oklch(60% 0.055 205);
|
||||||
|
--color-secondary-content: oklch(13% 0.02 214);
|
||||||
|
|
||||||
|
/* Accent — flamingo pink rgba(253, 117, 127) */
|
||||||
|
--color-accent: oklch(72% 0.155 14); /* flamingo pink */
|
||||||
|
--color-accent-content: oklch(13% 0.02 214);
|
||||||
|
|
||||||
|
|
||||||
|
/* Neutral — charcoal slate */
|
||||||
|
--color-neutral: oklch(28% 0.02 214);
|
||||||
|
--color-neutral-content: oklch(80% 0.01 214);
|
||||||
|
|
||||||
|
/* Semantic */
|
||||||
|
--color-info: oklch(60% 0.055 205);
|
||||||
|
--color-info-content: oklch(13% 0.02 214);
|
||||||
|
--color-success: oklch(72% 0.097 183);
|
||||||
|
--color-success-content: oklch(13% 0.02 214);
|
||||||
|
--color-warning: oklch(68% 0.16 42); /* alpenglow orange */
|
||||||
|
--color-warning-content: oklch(13% 0.02 214);
|
||||||
|
--color-error: oklch(72% 0.155 14); /* flamingo pink */
|
||||||
|
--color-error-content: oklch(13% 0.02 214);
|
||||||
|
|
||||||
|
/* Shape */
|
||||||
|
--radius-selector: 1.5rem;
|
||||||
|
--radius-field: 0.48rem;
|
||||||
|
--radius-box: 0.48rem;
|
||||||
|
--size-selector: 0.25rem;
|
||||||
|
--size-field: 0.25rem;
|
||||||
|
--border: 1px;
|
||||||
|
--depth: 1;
|
||||||
|
--noise: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
all: inherit;
|
||||||
|
color: var(--color-base-content); /* DaisyUI's base text color */
|
||||||
|
/* font-family: "Geist", system-ui, sans-serif;*/
|
||||||
|
/* creating the perfect shadow according to twitter/X
|
||||||
|
- https://codepen.io/jh3y/pen/yLWgjpd
|
||||||
|
- https://x.com/jh3yy/status/1796208073830232574
|
||||||
|
*/
|
||||||
|
--tint: 214;
|
||||||
|
--alpha: 4;
|
||||||
|
--base: hsl(var(--tint, 214) 80% 27% / calc(var(--alpha, 4) * 1%));
|
||||||
|
--shade: hsl(from var(--base) calc(h + 8) 25 calc(l - 5));
|
||||||
|
|
||||||
|
--perfect-shadow: 0 0 0 1px var(--base),
|
||||||
|
0 1px 1px -0.5px var(--shade),
|
||||||
|
0 3px 3px -1.5px var(--shade),
|
||||||
|
0 6px 6px -3px var(--shade),
|
||||||
|
0 12px 12px -6px var(--base),
|
||||||
|
0 24px 24px -12px var(--base);
|
||||||
|
|
||||||
|
|
||||||
|
--shade-active: hsla(173, 41%, 53%, 0.66);
|
||||||
|
--base-active: hsl(var(--tint, 214) 80% 27% / calc(var(--alpha, 4) * 1%));
|
||||||
|
|
||||||
|
--perfect-shadow-active: 0 0 0 1px var(--base-active),
|
||||||
|
0 1px 1px -0.5px var(--shade-active),
|
||||||
|
0 3px 3px -1.5px var(--shade-active),
|
||||||
|
0 6px 6px -3px var(--shade-active),
|
||||||
|
0 12px 12px -6px var(--base-active),
|
||||||
|
0 24px 24px -12px var(--base-active);
|
||||||
|
|
||||||
|
--perfect-shadow-thin-active: 0 0 0 1px var(--base-active),
|
||||||
|
0 1px 2px -0.5px var(--shade-active),
|
||||||
|
0 2px 4px -1px var(--shade-active),
|
||||||
|
0 4px 8px -2px var(--shade-active);
|
||||||
|
|
||||||
|
--shade-active-warn: rgba(253, 117, 127, 0.66);
|
||||||
|
--perfect-shadow-warn: 0 0 0 1px var(--shade-active-warn),
|
||||||
|
0 1px 1px -0.5px var(--shade-active-warn),
|
||||||
|
0 3px 3px -1.5px var(--shade-active-warn),
|
||||||
|
0 6px 6px -3px var(--shade-active-warn),
|
||||||
|
0 12px 12px -6px var(--base-active),
|
||||||
|
0 24px 24px -12px var(--base-active);
|
||||||
|
|
||||||
|
|
||||||
|
--base-thin: hsl(var(--tint, 214) 80% 27% / calc(var(--alpha, 4) * 1%));
|
||||||
|
--shade-thin: hsl(from var(--base-thin) calc(h + 8) 25 calc(l - 5));
|
||||||
|
|
||||||
|
--perfect-shadow-thin: 0 0 0 1px var(--base-thin),
|
||||||
|
0 1px 2px -0.5px var(--shade-thin),
|
||||||
|
0 3px 6px -1px var(--shade-thin);
|
||||||
|
--perfect-shadow-light: 0px 6px 20px -4px rgba(0, 0, 0, 0.40), 0px 0px 30px -8px rgba(123, 94, 248, 0.10);
|
||||||
|
/* === DARK BACKGROUND SHADOWS === */
|
||||||
|
|
||||||
|
/* Tinted with glacier blue for atmosphere */
|
||||||
|
--tint-dark: 205;
|
||||||
|
--alpha-dark: 30;
|
||||||
|
|
||||||
|
--base-dark: hsl(var(--tint-dark) 60% 60% / calc(var(--alpha-dark) * 1%));
|
||||||
|
--shade-dark: hsl(from var(--base-dark) calc(h + 8) 70 calc(l + 10));
|
||||||
|
|
||||||
|
/* Full shadow — for cards, modals, elevated surfaces */
|
||||||
|
--perfect-shadow-dark: 0 0 0 1px hsl(205 40% 50% / 15%),
|
||||||
|
0 1px 1px -0.5px var(--base-dark),
|
||||||
|
0 3px 3px -1.5px var(--base-dark),
|
||||||
|
0 6px 6px -3px var(--shade-dark),
|
||||||
|
0 12px 12px -6px var(--shade-dark),
|
||||||
|
0 24px 24px -12px var(--base-dark);
|
||||||
|
|
||||||
|
/* Thin shadow — for buttons, inputs, small elements */
|
||||||
|
--perfect-shadow-thin-dark: 0 0 0 1px hsl(205 40% 50% / 12%),
|
||||||
|
0 1px 2px -0.5px var(--base-dark),
|
||||||
|
0 3px 6px -1px var(--shade-dark);
|
||||||
|
|
||||||
|
/* Active/focus state — sea-grass green glow */
|
||||||
|
--shade-active-dark: hsla(183, 35%, 55%, 0.45); /* sea-grass green */
|
||||||
|
|
||||||
|
--perfect-shadow-thin-active-dark: 0 0 0 1px hsla(183, 35%, 55%, 0.3),
|
||||||
|
0 1px 2px -0.5px var(--shade-active-dark),
|
||||||
|
0 2px 4px -1px var(--shade-active-dark),
|
||||||
|
0 4px 8px -2px var(--shade-active-dark);
|
||||||
|
|
||||||
|
/* Warning/error active state — flamingo pink glow */
|
||||||
|
--shade-active-warn-dark: rgba(253, 117, 127, 0.45);
|
||||||
|
|
||||||
|
--perfect-shadow-warn-dark: 0 0 0 1px rgba(253, 117, 127, 0.3),
|
||||||
|
0 1px 1px -0.5px var(--shade-active-warn-dark),
|
||||||
|
0 3px 3px -1.5px var(--shade-active-warn-dark),
|
||||||
|
0 6px 6px -3px var(--shade-active-warn-dark),
|
||||||
|
0 12px 12px -6px var(--shade-active-warn-dark);
|
||||||
|
|
||||||
|
--mountain-white-dark: rgb(245, 242, 242); /* ≈ 80% – popular "dark mode off-white" */
|
||||||
|
--mountain-white: rgb(255, 252, 252, 1);
|
||||||
|
--ghost-white: rgb(248, 248, 255, 1);
|
||||||
|
|
||||||
|
/* Very subtle darkening – still very bright */
|
||||||
|
--mountain-white-darker-1: rgb(245, 242, 242); /* ≈ 96% brightness */
|
||||||
|
--mountain-white-darker-2: rgb(235, 232, 232); /* ≈ 92% */
|
||||||
|
|
||||||
|
/* Noticeably darker but still clearly a very light / "off-white" */
|
||||||
|
--mountain-white-darker-3: rgb(230, 227, 227); /* ≈ 90% */
|
||||||
|
--mountain-white-darker-4: rgb(220, 217, 217); /* ≈ 86% */
|
||||||
|
--mountain-white-darker-5: rgb(204, 201, 201); /* ≈ 80% – popular "dark mode off-white" */
|
||||||
|
|
||||||
|
/* Deeper / moodier off-whites – start feeling more greyish */
|
||||||
|
--mountain-white-darker-6: rgb(189, 186, 186); /* ≈ 74% */
|
||||||
|
--mountain-white-darker-7: rgb(170, 167, 167); /* ≈ 67% – quite smoky now */
|
||||||
|
--mountain-white-darker-8: rgb(150, 147, 147); /* ≈ 59% – very muted/dark off-white */
|
||||||
|
|
||||||
|
--charcoal-deep: rgb(15, 20, 25);
|
||||||
|
--charcoal-dark: rgb(25, 30, 35); /* +10 */
|
||||||
|
--charcoal-medium: rgb(35, 40, 48); /* +20ish */
|
||||||
|
--charcoal-soft: rgb(45, 50, 58); /* noticeably lighter but still moody */
|
||||||
|
--charcoal-slate: rgb(55, 60, 68); /* good background / surface color */
|
||||||
|
--charcoal-lighter: rgb(70, 75, 85); /* readable dark gray, modern UI feel */
|
||||||
|
--deep-night-black: rgb(8, 18, 28);
|
||||||
|
--abyss-black: rgb(6, 15, 22);
|
||||||
|
|
||||||
|
--bs-dark: var(--charcoal-medium); /* changes the base dark color */
|
||||||
|
--bs-dark-rgb: 35, 40, 48;
|
||||||
|
--bs-blue: var(--glacier-blue);
|
||||||
|
|
||||||
|
/* custom colors */
|
||||||
|
--flamingo-pink: rgba(253, 117, 127, 1);
|
||||||
|
--sea-grass-green: rgba(88, 191, 177, 1);
|
||||||
|
|
||||||
|
--mountain-darkgray: rgb(12, 31, 49, 1);
|
||||||
|
--mountain-gray: rgb(102, 133, 139, 1);
|
||||||
|
--mountain-lightgray: rgb(121, 152, 155, 1);
|
||||||
|
|
||||||
|
--glacier-blue: rgb(28, 80, 101);
|
||||||
|
--glacier-darkblue: rgb(12, 39, 49);
|
||||||
|
--glacier-lightblue: rgb(94, 150, 159);
|
||||||
|
--glacier-blue-rgb: 94, 150, 159;
|
||||||
|
|
||||||
|
/* borders, corners, and shadows */
|
||||||
|
--perfect-border-radius: 0.48em;
|
||||||
|
--backdrop-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 1px 3px 0 rgba(0, 0, 0, 0.19);
|
||||||
|
--backdrop-transition: all 0.3s ease;
|
||||||
|
|
||||||
|
/* global overwrites of bootstrap vars */
|
||||||
|
--text-bg-primary-badge-color: var(--glacier-blue);
|
||||||
|
|
||||||
|
/* White to Darker Blue diagonal gradient */
|
||||||
|
--gradient-white-dark-blue: linear-gradient(
|
||||||
|
142deg,
|
||||||
|
var(--ghost-white) 0%,
|
||||||
|
var(--ghost-white) 55%,
|
||||||
|
var(--glacier-lightblue) 67%,
|
||||||
|
var(--glacier-lightblue) 75%,
|
||||||
|
var(--glacier-blue) 100%
|
||||||
|
);
|
||||||
|
--gradient-dark: linear-gradient(135deg, var(--mountain-white) 0%, var(--mountain-darkgray) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
scrollbar-width: thin;
|
||||||
|
scrollbar-color: color-mix(in oklch, var(--color-base-content) 28%, transparent) var(--color-base-200);
|
||||||
|
}
|
||||||
|
|
||||||
|
*::-webkit-scrollbar {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
*::-webkit-scrollbar-track {
|
||||||
|
background: var(--color-base-200);
|
||||||
|
}
|
||||||
|
|
||||||
|
*::-webkit-scrollbar-thumb {
|
||||||
|
background-color: color-mix(in oklch, var(--color-base-content) 28%, transparent);
|
||||||
|
border-radius: var(--radius-field);
|
||||||
|
border: 2px solid var(--color-base-200);
|
||||||
|
}
|
||||||
|
|
||||||
|
*::-webkit-scrollbar-thumb:hover {
|
||||||
|
background-color: color-mix(in oklch, var(--color-primary) 65%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
*::-webkit-scrollbar-corner {
|
||||||
|
background: var(--color-base-200);
|
||||||
|
}
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: var(--color-base-200);
|
||||||
|
color: var(--color-base-content);
|
||||||
|
}
|
||||||
|
|
||||||
|
body > * {
|
||||||
|
height: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drawer,
|
||||||
|
.drawer-content,
|
||||||
|
.drawer-side {
|
||||||
|
height: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
min-height: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drawer-content {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
html, :root, body {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
font-family: "Geist Variable", "Geist", system-ui, sans-serif;
|
||||||
|
font-weight: 300;
|
||||||
|
font-synthesis: none; /* no fake 700 from 400 */
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3 {
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4, h5, h6, p {
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
box-shadow: var(--perfect-shadow-thin-dark);
|
||||||
|
transition: transform 0.3s ease-out, box-shadow 0.3s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:hover {
|
||||||
|
transform: scale(1.1) translateY(-2px);
|
||||||
|
box-shadow: var(--perfect-shadow-thin-active-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:not(.btn-ghost):not(.btn-outline):hover {
|
||||||
|
transform: scale(1.1) translateY(-2px);
|
||||||
|
box-shadow: var(--perfect-shadow-thin-active-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn,
|
||||||
|
.menu a,
|
||||||
|
.tab,
|
||||||
|
.table :where(th) {
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user