This commit is contained in:
2025-10-13 20:19:13 +02:00
parent c8f828bfb0
commit 6678cfda7d
20 changed files with 150 additions and 427 deletions

View File

@@ -0,0 +1,45 @@
<script lang="ts">
import { onMount } from "svelte";
function systemDarkModeEnabled() {
const computedStyle = window.getComputedStyle(document.body);
if (computedStyle?.colorScheme != null) {
return computedStyle.colorScheme.includes("dark");
}
return false;
}
let darkmode = $state(false);
const darkmodeToggleIcon = $derived(darkmode ? "🌝" : "🌚");
function toggleDarkmode() {
darkmode = !darkmode;
document.body.className = darkmode ? "dark" : "light";
}
onMount(() => darkmode = systemDarkModeEnabled())
</script>
<div class="darkToggle">
<span on:click={toggleDarkmode}>{ darkmodeToggleIcon }</span>
</div>
<style lang="scss" scoped>
.darkToggle {
height: 25px;
width: 25px;
cursor: pointer;
position: fixed;
margin-bottom: 1.5rem;
margin-right: 2px;
bottom: 0;
right: 0;
z-index: 10;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
</style>

View File

@@ -46,7 +46,7 @@
background: var(--theme); background: var(--theme);
padding: 0 1rem; padding: 0 1rem;
border-radius: 6px; border-radius: 6px;
color: white; color: var(--bg);
margin: 1rem 0.5rem 0 0.5rem; margin: 1rem 0.5rem 0 0.5rem;
font-weight: 400; font-weight: 400;
font-size: 1rem; font-size: 1rem;
@@ -66,7 +66,7 @@
font-size: 1.5rem; font-size: 1.5rem;
padding: 0; padding: 0;
font-weight: 300; font-weight: 300;
color: white !important; color: var(--bg) !important;
} }
img { img {

View File

@@ -33,6 +33,10 @@
</div> </div>
<style lang="scss"> <style lang="scss">
:global(body.dark .label-input .input) {
background: var(--highlight);
}
.label-input { .label-input {
width: 100%; width: 100%;
@@ -54,8 +58,9 @@
.input { .input {
position: relative; position: relative;
display: flex; display: flex;
--padding: 0.75rem; --padding-h: 0.25rem;
width: calc(100% - (var(--padding) * 2)); --padding-w: 0.75rem;
width: calc(100% - (var(--padding-w) * 2));
height: 2.5rem; height: 2.5rem;
background: #ffffff; background: #ffffff;
align-items: center; align-items: center;
@@ -66,7 +71,7 @@
outline: none; outline: none;
display: flex; display: flex;
align-items: center; align-items: center;
padding: 0px var(--padding); padding: var(--padding-h) var(--padding-w);
&.focus { &.focus {
box-shadow: 0px 0px 0px 4px #7d66654d; box-shadow: 0px 0px 0px 4px #7d66654d;

View File

@@ -69,133 +69,5 @@
</div> </div>
<style lang="scss"> <style lang="scss">
.card { @import "../styles/card.scss";
flex-grow: 1;
max-width: 550px;
background: #fbf6f4;
box-shadow: var(
--str-shadow-s,
0px 0px 2px #22242714,
0px 1px 4px #2224271f,
0px 4px 8px #22242729
);
pointer-events: all;
cursor: auto;
}
.header {
display: flex;
padding: 0.75rem;
background-color: white;
align-items: center;
font-size: 16px;
.icon {
height: 24px;
width: 24px;
margin-right: 0.75rem;
}
.status {
height: 1rem;
width: 1rem;
border-radius: 50%;
margin-left: auto;
position: relative;
&.ok {
background-color: var(--positive);
}
&.warning {
background-color: var(--warning);
}
&.error {
background-color: var(--negative);
}
}
}
.footer {
padding: 0.5rem;
background-color: white;
}
.resource {
display: grid;
grid-template-columns: auto auto;
padding: 0.5rem;
background-color: var(--bg);
row-gap: 6px;
column-gap: 20px;
> div,
span {
display: flex;
padding: 0 0.5rem;
}
}
:global(.resource .title svg) {
height: 1rem;
width: 1rem;
}
.footer {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 0.5rem;
margin-top: auto;
background: white;
padding: 0.5rem;
border-bottom-left-radius: 0.25rem;
border-bottom-right-radius: 0.25rem;
button {
border: none;
position: relative;
background: transparent;
height: unset;
border-radius: 0.5rem;
display: inline-block;
text-decoration: none;
padding: 0 0.5rem;
flex: 1;
span {
display: inline-flex;
align-items: center;
justify-content: center;
width: 100%;
height: 1.5rem;
padding: 0 0.5rem;
margin-left: -0.5rem;
border: 1px solid #eaddd5;
border-radius: inherit;
white-space: nowrap;
cursor: pointer;
font-weight: 700;
}
&::after {
content: '';
position: absolute;
right: 0;
top: 0;
border-radius: 0.5rem;
width: 100%;
height: 100%;
transition: transform 0.1s ease;
will-change: box-shadow 0.25s;
pointer-events: none;
}
}
}
.positive {
color: #077c35;
}
</style> </style>

View File

@@ -105,6 +105,8 @@
</div> </div>
<style lang="scss"> <style lang="scss">
@import "../styles/card.scss";
.card-container { .card-container {
background-color: #cab2aa40; background-color: #cab2aa40;
border-radius: 0.5rem; border-radius: 0.5rem;
@@ -122,99 +124,4 @@
gap: 2rem; gap: 2rem;
} }
} }
.card {
flex-grow: 1;
max-width: 550px;
background: #fbf6f4;
box-shadow: var(
--str-shadow-s,
0px 0px 2px #22242714,
0px 1px 4px #2224271f,
0px 4px 8px #22242729
);
pointer-events: all;
cursor: auto;
&.not-running {
border: 2px dashed var(--theme);
opacity: 0.6;
}
}
.header {
display: flex;
padding: 0.75rem;
background-color: white;
align-items: center;
font-size: 16px;
.icon {
height: 24px;
width: 24px;
margin-right: 0.75rem;
}
.status {
height: 1rem;
width: 1rem;
border-radius: 50%;
margin-left: auto;
position: relative;
&.ok {
background-color: var(--positive);
}
&.warning {
background-color: var(--warning);
}
&.error {
background-color: var(--negative);
}
}
}
.footer {
padding: 0.5rem;
background-color: white;
}
.resource {
display: grid;
grid-template-columns: auto auto;
padding: 0.5rem;
background-color: var(--bg);
row-gap: 6px;
column-gap: 20px;
> div,
span {
display: flex;
padding: 0 0.5rem;
}
}
:global(.resource .title svg) {
height: 1rem;
width: 1rem;
}
.footer {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 0.5rem;
margin-top: auto;
background: white;
padding: 0.5rem;
border-bottom-left-radius: 0.25rem;
border-bottom-right-radius: 0.25rem;
}
.positive {
color: #077c35;
}
</style> </style>

View File

@@ -126,163 +126,5 @@
</div> </div>
<style lang="scss"> <style lang="scss">
@keyframes pulse-live { @import '../styles/card.scss';
0% {
box-shadow: 0 0 0 0 rgba(0, 212, 57, 0.7);
box-shadow: 0 0 0 0 rgba(0, 212, 57, 0.7);
}
70% {
box-shadow: 0 0 0 10px rgba(0, 212, 57, 0);
box-shadow: 0 0 0 10px rgba(0, 212, 57, 0);
}
100% {
box-shadow: 0 0 0 0 rgba(0, 212, 57, 0);
box-shadow: 0 0 0 0 rgba(0, 212, 57, 0);
}
}
@mixin pulse-dot {
&::after {
content: '';
top: 50%;
margin-left: 0.4rem;
position: absolute;
display: block;
border-radius: 50%;
background-color: var(--color);
border-radius: 50%;
transform: translate(-50%, -50%);
animation: pulse-live 2s infinite;
height: 16px;
width: 16px;
}
}
.card {
background: #fbf6f4;
box-shadow: var(
--str-shadow-s,
0px 0px 2px #22242714,
0px 1px 4px #2224271f,
0px 4px 8px #22242729
);
pointer-events: all;
cursor: auto;
}
.header {
display: flex;
padding: 0.75rem;
background-color: white;
align-items: center;
font-size: 16px;
.icon {
height: 24px;
width: 24px;
margin-right: 0.75rem;
}
.status {
height: 1rem;
width: 1rem;
border-radius: 50%;
margin-left: auto;
position: relative;
&.ok {
--color: var(--positive);
@include pulse-dot;
}
&.warning {
background-color: var(--warning);
}
&.error {
background-color: var(--negative);
}
}
}
.footer {
padding: 0.5rem;
background-color: white;
}
.resource {
display: grid;
grid-template-columns: auto auto;
padding: 0.5rem;
background-color: var(--bg);
row-gap: 6px;
max-width: 330px;
> div,
span {
display: flex;
padding: 0 0.5rem;
}
}
:global(.resource .title svg) {
height: 1rem;
width: 1rem;
}
.footer {
display: flex;
align-items: center;
justify-content: space-evenly;
flex-wrap: wrap;
gap: 0.5rem;
margin-top: auto;
background: white;
padding: 0.5rem;
border-bottom-left-radius: 0.25rem;
border-bottom-right-radius: 0.25rem;
button {
border: none;
position: relative;
background: transparent;
height: unset;
border-radius: 0.5rem;
display: inline-block;
text-decoration: none;
padding: 0 0.5rem;
flex: 1;
span {
display: inline-flex;
align-items: center;
justify-content: center;
width: 100%;
height: 1.5rem;
padding: 0 0.5rem;
margin-left: -0.5rem;
border: 1px solid #eaddd5;
border-radius: inherit;
white-space: nowrap;
cursor: pointer;
font-weight: 700;
}
&::after {
content: '';
position: absolute;
right: 0;
top: 0;
border-radius: 0.5rem;
width: 100%;
height: 100%;
transition: transform 0.1s ease;
will-change: box-shadow 0.25s;
pointer-events: none;
}
}
}
.positive {
color: #077c35;
}
</style> </style>

View File

@@ -55,7 +55,7 @@
.description { .description {
font-size: 0.875rem; font-size: 0.875rem;
color: #666; opacity: 0.6;
margin-bottom: 12px; margin-bottom: 12px;
} }

View File

@@ -15,22 +15,6 @@
</div> </div>
<style lang="scss"> <style lang="scss">
button {
background: none;
border: none;
border-bottom: 2px solid transparent;
border-radius: 0;
margin: 0;
letter-spacing: 0.2px;
&.selected {
opacity: 1;
letter-spacing: unset;
border-bottom-color: var(--color) !important;
font-weight: 600 !important;
}
}
.tab { .tab {
&:not(&:first-of-type) { &:not(&:first-of-type) {
margin-left: 0.75rem; margin-left: 0.75rem;
@@ -40,10 +24,21 @@
font-size: 1.1rem; font-size: 1.1rem;
font-weight: 500; font-weight: 500;
cursor: pointer; cursor: pointer;
border-bottom: 2px solid transparent; background: none;
opacity: 0.7; opacity: 0.6;
margin: 0;
padding-bottom: 0.3rem; padding-bottom: 0.3rem;
transition: 0.3s ease-in-out all; border-radius: 0;
border: none;
border-bottom: 2px solid transparent;
letter-spacing: 0.2px;
&.selected {
opacity: 1;
letter-spacing: unset;
border-bottom-color: var(--color) !important;
font-weight: 600 !important;
}
} }
} }
</style> </style>

View File

@@ -8,7 +8,6 @@
> >
<g <g
transform="translate(0.000000,108.000000) scale(0.100000,-0.100000)" transform="translate(0.000000,108.000000) scale(0.100000,-0.100000)"
fill="#000000"
stroke="none" stroke="none"
> >
<path <path

Before

Width:  |  Height:  |  Size: 896 B

After

Width:  |  Height:  |  Size: 879 B

View File

@@ -8,7 +8,6 @@
> >
<g <g
transform="translate(0.000000,151.000000) scale(0.100000,-0.100000)" transform="translate(0.000000,151.000000) scale(0.100000,-0.100000)"
fill="#000000"
stroke="none" stroke="none"
> >
<path <path

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -8,7 +8,6 @@
> >
<g <g
transform="translate(0.000000,157.000000) scale(0.100000,-0.100000)" transform="translate(0.000000,157.000000) scale(0.100000,-0.100000)"
fill="#000000"
stroke="none" stroke="none"
> >
<path <path

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -8,7 +8,6 @@
> >
<g <g
transform="translate(0.000000,151.000000) scale(0.100000,-0.100000)" transform="translate(0.000000,151.000000) scale(0.100000,-0.100000)"
fill="#000000"
stroke="none" stroke="none"
> >
<path <path

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -8,7 +8,6 @@
> >
<g <g
transform="translate(0.000000,156.000000) scale(0.100000,-0.100000)" transform="translate(0.000000,156.000000) scale(0.100000,-0.100000)"
fill="#000000"
stroke="none" stroke="none"
> >
<path <path

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -8,7 +8,6 @@
> >
<g <g
transform="translate(0.000000,122.000000) scale(0.100000,-0.100000)" transform="translate(0.000000,122.000000) scale(0.100000,-0.100000)"
fill="#000000"
stroke="none" stroke="none"
> >
<path <path

Before

Width:  |  Height:  |  Size: 746 B

After

Width:  |  Height:  |  Size: 729 B

View File

@@ -8,7 +8,6 @@
> >
<g <g
transform="translate(0.000000,182.000000) scale(0.100000,-0.100000)" transform="translate(0.000000,182.000000) scale(0.100000,-0.100000)"
fill="#000000"
stroke="none" stroke="none"
> >
<path <path

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -8,7 +8,6 @@
> >
<g <g
transform="translate(0.000000,181.000000) scale(0.100000,-0.100000)" transform="translate(0.000000,181.000000) scale(0.100000,-0.100000)"
fill="#000000"
stroke="none" stroke="none"
> >
<path <path

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -28,17 +28,25 @@
} }
.card { .card {
background: #fbf6f4; box-shadow:
box-shadow: var(
--str-shadow-s,
0px 0px 2px #22242714, 0px 0px 2px #22242714,
0px 1px 4px #2224271f, 0px 1px 4px #2224271f,
0px 4px 8px #22242729 0px 4px 8px #22242729;
);
pointer-events: all; pointer-events: all;
cursor: auto; cursor: auto;
} }
:global(body.dark .card) {
box-shadow:
0px 0px 2px #eaddd514,
0px 1px 4px #eaddd515,
0px 4px 6px #eaddd520;
}
:global(body.dark .card .header, body.dark .card .footer) {
background-color: var(--highlight);
}
.header { .header {
display: flex; display: flex;
padding: 0.75rem; padding: 0.75rem;
@@ -54,7 +62,7 @@
.subtle { .subtle {
margin-left: 0.25rem; margin-left: 0.25rem;
color: rgba(0, 0, 0, 0.4); opacity: 0.4;
font-weight: 500; font-weight: 500;
font-size: 0.9rem; font-size: 0.9rem;
} }

View File

@@ -1,6 +1,7 @@
<script lang="ts"> <script lang="ts">
import Header from '$lib/components/Header.svelte'; import Header from '$lib/components/Header.svelte';
import Sidebar from '$lib/components/Sidebar.svelte'; import Sidebar from '$lib/components/Sidebar.svelte';
import DarkmodeToggle from '$lib/components/DarkmodeToggle.svelte';
import GlobalSearch from '$lib/components/GlobalSearch.svelte'; import GlobalSearch from '$lib/components/GlobalSearch.svelte';
</script> </script>
@@ -15,6 +16,7 @@
</main> </main>
</div> </div>
<DarkmodeToggle />
<GlobalSearch /> <GlobalSearch />
</div> </div>

View File

@@ -66,7 +66,7 @@
<PageHeader>Welcome to schleppe.cloud infra overview</PageHeader> <PageHeader>Welcome to schleppe.cloud infra overview</PageHeader>
<p> <p class="site-desc">
This site is a local-first dashboard for monitoring the state of digital and physical tools in a This site is a local-first dashboard for monitoring the state of digital and physical tools in a
workshop environment. It currently tracks servers (IP, cores, memory, uptime), 3D printers workshop environment. It currently tracks servers (IP, cores, memory, uptime), 3D printers
(status, history, filament stock), and other connected devices. Each device or system has its own (status, history, filament stock), and other connected devices. Each device or system has its own
@@ -74,7 +74,7 @@
general monitoring tools, IoT integrations, and project overviews. general monitoring tools, IoT integrations, and project overviews.
</p> </p>
<p> <p class="site-desc">
The system is intended for hybrid spaces where digital infrastructure coexists with hands-on work. The system is intended for hybrid spaces where digital infrastructure coexists with hands-on work.
Alongside real-time monitoring, Schleppe is expanding to reflect the broader physical Alongside real-time monitoring, Schleppe is expanding to reflect the broader physical
workspace—covering areas like tool usage, material stocks, and workstations for welding, workspace—covering areas like tool usage, material stocks, and workstations for welding,
@@ -96,18 +96,23 @@
</div> </div>
<style lang="scss"> <style lang="scss">
p { p.site-desc {
font-size: 1.1rem; font-size: 1.1rem;
line-height: 1.4; line-height: 1.4;
line-height: 1.7; line-height: 1.7;
color: #333; color: #333;
background-color: #fafafa; /* Subtle background to separate it from the rest */ background-color: #fafafa;
padding: 2rem; padding: 2rem;
border-radius: 1rem; /* Soft edges */ border-radius: 1rem; /* Soft edges */
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); /* Light shadow for depth */ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); /* Light shadow for depth */
} }
:global(body.dark p.site-desc) {
background-color: var(--highlight);
color: var(--color);
}
.shortcut-grid { .shortcut-grid {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));

View File

@@ -43,6 +43,34 @@
--border: 1px solid #eaddd5; --border: 1px solid #eaddd5;
--border-radius: 0.75rem; --border-radius: 0.75rem;
--card-bg: rgba(255, 255, 255, 0.7);
--key: #6e80d6;
--muted: #7a6d6e;
}
body.dark {
--bg: #121010;
--color: #f4eeeb;
--highlight: #2b2325;
--theme: #eaddd5;
--positive: #3ddc84;
--negative: #ff6b63;
--warning: #ffb74d;
--pulse-positive: rgba(61, 220, 132, 0.6);
--pulse-negative: rgba(255, 107, 99, 0.6);
--pulse-warning: rgba(255, 183, 77, 0.6);
--border: 1px solid #2b2325;
--key: #9fb3ff;
--muted: #b0b0b0;
--card-bg: #303037;
}
svg {
fill: var(--color);
} }
body { body {
@@ -54,6 +82,9 @@ body {
background-color: var(--bg); background-color: var(--bg);
color: var(--color); color: var(--color);
font-size: 14px; font-size: 14px;
transition:
background 0.3s ease,
color 0.3s ease;
} }
a, a,
@@ -99,6 +130,7 @@ button {
border: none; border: none;
position: relative; position: relative;
background: transparent; background: transparent;
color: var(--color);
height: 100%; height: 100%;
border-radius: 0.5rem; border-radius: 0.5rem;
display: inline-block; display: inline-block;
@@ -137,6 +169,20 @@ button.affirmative:hover span {
background-color: var(--highlight); background-color: var(--highlight);
} }
/* dark mode button overrides */
body.dark button span {
background-color: var(--theme);
}
body.dark button.affirmative span {
color: var(--bg);
}
body.dark button.affirmative:hover span {
color: var(--color);
background-color: var(--highlight);
border-color: var(--bg);
}
button:disabled { button:disabled {
cursor: not-allowed; cursor: not-allowed;
} }
@@ -194,7 +240,7 @@ table tr:not(table tr:last-of-type) {
table tr:hover > td { table tr:hover > td {
background-color: var(--highlight); background-color: var(--highlight);
background-color: #f5ede9; background-color: var(--bg);
} }
table tr.link { table tr.link {
@@ -213,6 +259,10 @@ table tr.link {
} }
} }
body.dark .main-container {
background: var(--highlight) !important;
}
.section-wrapper { .section-wrapper {
display: flex; display: flex;
flex-direction: column; flex-direction: column;