/** Datei: themes/lcars/library/ARUNOX/Themes/LCARS/Theme.php **/ * @copyright 2025 ARUNOX * @version 1.0.0 * @since 1.0.0 File is created */ namespace ARUNOX\Themes\LCARS; use ARUNOX\Core; use ARUNOX\Plugins; class Theme extends Core\Theme { /* ### PUBLIC FUNCTIONS ######################################### # */ public function getLable() : string { return 'LCARS Theme'; } } /** Datei: themes/lcars/hooks/init.php **/ * @copyright 2025 ARUNOX * @version 1.0.0 * @since 1.0.0 File is created */ use ARUNOX\Core\Hooks; use ARUNOX\API\Filesystem; use ARUNOX\Themes\LCARS\Theme; Hooks::add("theme::scripts->before", function() { ?>before", function() { $root = realpath( ROOT_DIR ); $assetsDir = THEME->dir . "/assets/js"; $hooks = Filesystem::getDir( "{$assetsDir}/hooks" ); $hooks = array_map( fn( $file ) => $file->filename, $hooks->files ); $templates = []; $diretories = [ "{$assetsDir}/templates", "{$assetsDir}/components", ]; foreach( $diretories as $directory ) { $files = Filesystem::getDir( $directory ); $files = array_map( fn( $file ) => [ "name" => $file->filename, "file" => str_replace( $root, "", $file->path ), ], $files->files( TRUE ) ); array_push( $templates, ...$files ); } $layouts = Filesystem::getDir( "{$assetsDir}/layouts", ); $layouts = array_map( fn( $file ) => [ "name" => str_replace( "{$assetsDir}/layouts", "layout", $file->dirname ) . "/". $file->filename, "file" => str_replace( $root, "", $file->path ), ], $layouts->files( TRUE ) ); array_push( $templates, ...$layouts ); $templates = array_column( $templates, "file","name" ); ?> * { z-index: 1; } &::after { content: ''; position: absolute; top: #{$frame-border-width *-1}; left: #{$frame-border-width *-1}; right: #{$frame-border-width *-1}; bottom: #{$frame-border-width *-1}; z-index: -1; background-color: var( --color-background ); } --size: calc( min( 100cqi, var( --height, #{$frame-inner-button} ) ) - #{($frame-padding + $frame-border-width) * 2} ); min-height: 30px; .icon { order: 1; height: var( --size ); font-size: var( --size ); aspect-ratio: 1; pointer-events: none; display: inline-flex; align-items: center; justify-content: center; &::before { vertical-align: -0.01em; } } .label { order: 2; height: var( --size ); font-size: min( var(--size), 20px ); white-space: nowrap; display: block; overflow: hidden; text-overflow: ellipsis; line-height: 1em; flex: 1; min-inline-size: 0; } &:hover, &:focus-within{ max-inline-size: 100vw !important; } } &label { // overflow: hidden; // text-overflow: ellipsis; // display: block; padding-top: #{$frame-spacing}; } &button { $frame-button: & !global; cursor: pointer; &.active, &:active { --color-background: var( --color-background-active ); --color-border: var( --color-border-active ); --color-text: var( --color-text-active ); } &.inactive { filter: brightness( 50% ); } &[disabled] { pointer-events: none; filter: brightness(50%); } &:hover { --color-background: var( --color-background-hover ); --color-border: var( --color-border-hover ); --color-text: var( --color-text-hover ); } } &corner { $frame-corner: & !global; width: calc( var( --sidebar ) - #{$frame-border-width} ) !important; height: var( --navbar ); position: relative; &::after { content: ''; display: block; position: absolute; background-color: var( --color-background ); border-color: var( --color-border ); border-width: #{$frame-border-width}; border-style: solid; height: var( --navbar ); width: #{$frame-spacing + $frame-border-width}; } } } } &sidebar { $frame-sidebar: & !global; position: relative; display: flex; flex-direction: column; gap: var( --gap ); grid-column: var( --side ); grid-row: 2 / -2; --width: var( --sidebar ); container-type: inline-size; > * { width: var( --sidebar ); } #{$frame-wrapper} { flex-direction: column; z-index: 10; } &:has( > #{$frame-wrapper}:first-child ) { &::before { content: ''; display: block; background-color: var( --color-background ); border-color: var( --color-border ); border-width: #{$frame-border-width}; border-style: solid; width: var( --sidebar ); height: #{$frame-spacing + $frame-border-width}; border-top-width: 0; } } > #{$frame-wrapper} { // overflow-y: auto; } #{$frame-label} { flex: 0 0 auto; inline-size: max-content; min-inline-size: var(--sidebar); max-inline-size: var(--sidebar); transition: max-inline-size 200ms ease; } #{$frame-fill} { &:has( + #{$frame-fill} ) { margin-bottom: var( --gap-negate ); border-bottom-width: 0; } &:last-child { margin-bottom: 0; border-top-width: 0; border-bottom-width: 0; } &:first-child { margin-top: 0; border-top-width: 0; } } } &navbar { $frame-navbar: & !global; position: relative; display: flex; container-type: size; flex-direction: row; gap: var( --gap ); --navbar: var( --height ); grid-column: 1 / -1; // #{$frame-button} { // max-width: var( --navbar ); // width: var( --navbar ); // } #{$frame-label} { flex: 0 0 auto; // inline-size: max-content; min-inline-size: var(--navbar); max-inline-size: var(--navbar); transition: max-inline-size 200ms ease; } #{$frame-wrapper} { flex-direction: row; } &-- { &header { $frame-header: & !global; --height: var( --header ); grid-row: 1; #{$frame-corner} { border-bottom-width: 0; &::after { top: #{$frame-border-width * -1}; } } #{$frame-wrapper} { align-items: start; gap: var( --gap ); } } &footer { $frame-footer: & !global; --height: var( --footer ); grid-row: 5; #{$frame-corner} { border-top-width: 0; &::after { bottom: #{$frame-border-width * -1}; } } } &left, &right { width: var(--height); } &after, &before, ¢er { &:empty { display: contents; } } } } §ion { $frame-section: & !global; --columWidth: calc( var( --sidebar ) + #{$frame-spacing} ); grid-template-rows: var( --header ) #{$frame-spacing} 1fr #{$frame-spacing} var( --footer ); grid-template-columns: var( --sidebar ) #{$frame-spacing} 1fr #{$frame-spacing} var( --sidebar ); position: relative; flex: 1 1 auto; display: grid; margin: 0; overflow: hidden; grid-area: content; // gap: var( --gap ); container: section / size; height: 100%; width: 100%; } &content { display: flex; overflow: auto; container: content / size; gap: calc( var( --gap ) * 2 + #{$frame-spacing} ); margin: var( --gap ); & > * { flex: 1 1 100%; } } &content, §ion { $frame-content: & !global; grid-column: 1 / -1; grid-row: 3; } &corner { aspect-ratio: 1; } &title { margin: 0; height: var( --height ); font-weight: bold; @extend .font--headline; font-size: 100cqmin; line-height: 1; display: flex; align-items: center; text-transform: uppercase; flex: 0 0 auto; padding-inline: calc( var( --height ) / 2 - var( --gap ) ); } } &--{ &sidebar { &-left { $frame-is-left: & !global; > #{$frame-sidebar} { --side: 1; } > #{$frame-navbar} { #{$frame-corner} { border-right-width: 0; margin-right: #{$frame-spacing + $frame-border-width}; &::after { left: 100%; border-left-width: 0; } } } > #{$frame-content} { grid-column: 3 / -1; margin-right: 0; } } &-right { $frame-is-right: & !global; > #{$frame-sidebar} { --side: -2; align-items: end; #{$frame-label} { flex-direction: row-reverse; text-align: left; } } #{$frame-section}:not( & ) { > #{$frame-navbar} { #{$frame-fill} { &:has( + #{$frame-fill} ) { margin-right: var( --gap-negate ); border-right-width: 0; } + #{$frame-fill} { border-left-width: 0; } } #{$frame-corner} { &:has( + #{$frame-fill} ) { margin-right: #{$frame-spacing + $frame-border-width - $frame-gap}; &::after { border-right-width: 0; } } + #{$frame-fill} { border-left-width: 0; } } } } > #{$frame-navbar} { flex-direction: row-reverse; #{$frame-corner} { border-left-width: 0; margin-left: #{$frame-spacing + $frame-border-width}; &:has( + #{$frame-fill} ) { margin-left: #{$frame-spacing + $frame-border-width - $frame-gap}; &::after { border-left-width: 0; } + #{$frame-fill} { border-right-width: 0; } } &::after { right: 100%; border-right-width: 0; } } #{$frame-fill} { &:has( + #{$frame-fill} ) { margin-left: var( --gap-negate ); border-left-width: 0; } + #{$frame-fill} { border-left-width: #{$frame-border-width}; border-right-width: 0; } } > #{$frame-navbar} { &-- { &after { #{$frame-label} { flex-direction: row; } } &before { #{$frame-label} { flex-direction: row-reverse; text-align: left; } } } } } > #{$frame-content} { grid-column: 1 / -3; margin-left: 0; } } @each $size, $value in $frame-sizes { &-#{$size} { --sidebar: var( --maxSidebar, #{$value} ); } } } &header { @each $size, $value in $frame-sizes { &-#{$size} { --header: #{$value}; } } } &footer { @each $size, $value in $frame-sizes { &-#{$size} { --footer: #{$value}; } } } } } .frame__sidebar { .frame__wrapper{ overflow: visible; } } .button { &__ { &wrapper { &:is( #{$frame-is-right} #{$frame-navbar}--before * ) { align-items: end; } } &dropdown { &:is( #{$frame-header} * ) { } &:is( #{$frame-is-right} #{$frame-navbar}--before * ) { left: auto; right: 0; } } &dropdown, &wrapper.is--open { #{$frame-label} { max-inline-size: 100%; inline-size: 100%; } } } } input, select { color: #fff !important; -webkit-text-fill-color: #fff !important; -webkit-background-clip: text !important; background-clip: text !important; } /** Datei: themes/lcars/assets/scss/frame/_mixins.scss **/ @mixin element--box() { @include theme-element( $height : var( --height ), $border : '0 0, 0 100%, 100% 100%, 100% 0, #{$theme-element-border} 0, #{$theme-element-border} #{$theme-element-border}, calc( 100% - #{$theme-element-border} ) #{$theme-element-border}, calc( 100% - #{$theme-element-border} ) calc( 100% - #{$theme-element-border} ), #{$theme-element-border} calc( 100% - #{$theme-element-border} ), #{$theme-element-border} 0', ); } @mixin element--break-right() { @include theme-element( $height : var( --height ), $width : calc( var( --height ) / 2), $border : '0 100%, 100% 100%, 100% 0, 0 0, 0 #{$theme-element-border}, calc( 100% - #{$theme-element-border} ) #{$theme-element-border}, calc( 100% - #{$theme-element-border} ) calc( 100% - #{$theme-element-border} ), 0 calc( 100% - #{$theme-element-border})', ); margin-right: $theme-element-gap; } @mixin element--break-left() { @include theme-element( $height : var( --height ), $width : calc( var( --height ) / 2), $border : '100% 100%, 0 100%, 0 0, 100% 0, 100% #{$theme-element-border}, #{$theme-element-border} #{$theme-element-border}, #{$theme-element-border} calc( 100% - #{$theme-element-border} ), 100% calc( 100% - #{$theme-element-border})', ); } @mixin element--corner-left() { @include theme-element( $height : var( --height ), $width : calc( var( --height ) / 2 + #{floor($theme-line-offset)} ), $polygon: '100% 0, 100% 100%, calc( 100% - #{$theme-line-offset}) 100%, 0 50%, calc( 100% - #{$theme-line-offset}) 0', $border : '100% 100%, calc( 100% - #{$theme-line-offset} ) 100%, 0 50%, calc( 100% - #{$theme-line-offset} ) 0, 100% 0, 100% #{$theme-element-border}, #{$theme-element-border + $theme-line-offset} 50%, 100% calc( 100% - #{$theme-element-border})', ); } @mixin element--corner-right() { @include theme-element( $height : var( --height ), $width : calc( var( --height ) / 2 + #{floor($theme-line-offset)} ), $polygon: '0 0, 0 100%, #{$theme-line-offset} 100%, 100% 50%, #{$theme-line-offset} 0', $border :'0 100%, #{$theme-line-offset} 100%, 100% 50%, #{$theme-line-offset} 0, 0 0, 0 #{$theme-element-border}, calc( 100% - #{$theme-element-border + $theme-line-offset}) 50%, 0 calc( 100% - #{$theme-element-border})', ); } @mixin element--corner-top-left() { @include theme-element( $width : calc( var( --width ) + var( --height ) / 3 ), $height : calc( var( --height ) + var( --height ) / 3 ), $polygon: 'var( --height ) 0px, 0px var( --height ), 0px 100%, calc( 100% - var( --height, var( --height ) ) / 3 ) 100%, 100% var( --height ), 100% 0', $border : '0px 100%, 0px var( --height ), var( --height ) 0px, 100% 0px, 100% #{$theme-element-border}, calc( var( --height ) + #{$theme-line-offset} ) #{$theme-element-border}, #{$theme-element-border} calc( var( --height ) + #{$theme-line-offset} ), #{$theme-element-border} 100%, calc( 100% - var( --height ) / 3 ) 100%, 100% var( --height ), 100% calc( var( --height ) - #{$theme-element-border} ), calc( 100% - #{$theme-line-offset} ) calc( var( --height ) - #{$theme-element-border} ), calc( 100% - var( --height ) / 3 - #{$theme-element-border} ) calc( 100% - #{$theme-line-offset} ), calc( 100% - var( --height ) / 3 - #{$theme-element-border} ) 100%' ); } @mixin element--corner-top-right() { @include theme-element( $width : calc( var( --width ) + var( --height ) / 3 ), $height : calc( var( --height ) + var( --height ) / 3 ), $polygon: 'var( --height ) 0px, 0px var( --height ), 0px 100%, calc( 100% - var( --height, var( --height ) ) / 3 ) 100%, 100% var( --height ), 100% 0', $border : '0px 100%, 0px var( --height ), var( --height ) 0px, 100% 0px, 100% #{$theme-element-border}, calc( var( --height ) + #{$theme-line-offset} ) #{$theme-element-border}, #{$theme-element-border} calc( var( --height ) + #{$theme-line-offset} ), #{$theme-element-border} 100%, calc( 100% - var( --height, var( --height ) ) / 3 ) 100%, 100% var( --height ), 100% calc( var( --height ) - #{$theme-element-border} ), calc( 100% - #{$theme-line-offset} ) calc( var( --height ) - #{$theme-element-border} ), calc( 100% - var( --height ) / 3 - #{$theme-element-border} ) calc( 100% - #{$theme-line-offset} ), calc( 100% - var( --height ) / 3 - #{$theme-element-border} ) 100%' ); scale: -1 1; } @mixin element--corner-bottom-left() { @include theme-element( $width : calc( var( --width ) + var( --height ) / 3 ), $height : calc( var( --height ) + var( --height ) / 3 ), $polygon: 'var( --height ) 0px, 0px var( --height ), 0px 100%, calc( 100% - var( --height, var( --height ) ) / 3 ) 100%, 100% var( --height ), 100% 0', $border : '0px 100%, 0px var( --height ), var( --height ) 0px, 100% 0px, 100% #{$theme-element-border}, calc( var( --height ) + #{$theme-line-offset} ) #{$theme-element-border}, #{$theme-element-border} calc( var( --height ) + #{$theme-line-offset} ), #{$theme-element-border} 100%, calc( 100% - var( --height, var( --height ) ) / 3 ) 100%, 100% var( --height ), 100% calc( var( --height ) - #{$theme-element-border} ), calc( 100% - #{$theme-line-offset} ) calc( var( --height ) - #{$theme-element-border} ), calc( 100% - var( --height ) / 3 - #{$theme-element-border} ) calc( 100% - #{$theme-line-offset} ), calc( 100% - var( --height ) / 3 - #{$theme-element-border} ) 100%' ); scale: 1 -1; } @mixin element--corner-bottom-right() { @include theme-element( $width : calc( var( --width ) + var( --height ) / 3 ), $height : calc( var( --height ) + var( --height ) / 3 ), $polygon: 'var( --height ) 0px, 0px var( --height ), 0px 100%, calc( 100% - var( --height, var( --height ) ) / 3 ) 100%, 100% var( --height ), 100% 0', $border : '0px 100%, 0px var( --height ), var( --height ) 0px, 100% 0px, 100% #{$theme-element-border}, calc( var( --height ) + #{$theme-line-offset} ) #{$theme-element-border}, #{$theme-element-border} calc( var( --height ) + #{$theme-line-offset} ), #{$theme-element-border} 100%, calc( 100% - var( --height, var( --height ) ) / 3 ) 100%, 100% var( --height ), 100% calc( var( --height ) - #{$theme-element-border} ), calc( 100% - #{$theme-line-offset} ) calc( var( --height ) - #{$theme-element-border} ), calc( 100% - var( --height ) / 3 - #{$theme-element-border} ) calc( 100% - #{$theme-line-offset} ), calc( 100% - var( --height ) / 3 - #{$theme-element-border} ) 100%' ); scale: -1 -1; } @mixin theme-background( $polygon: 0 ) { position: relative; &::before { @include transition(); content: ''; display: block; z-index: -1; position: absolute; top: 0; left: 0; width: 100%; height: 100%; @if $polygon != 0 { clip-path: polygon( #{$polygon} ); } } @if $polygon != 0 { clip-path: polygon( #{$polygon} ); } backdrop-filter: blur( $theme-bg-blur ); } @mixin theme-border( $width: 0, $color: var( --brand-primary-alpha2 ) ) { border-color: $color; border-style: solid; border-width: $width; } @mixin theme-border-shape( $polygon ) { &::after { @include transition(); z-index: -1; content: ''; display: block; position: absolute; top: 0; left: 0; width: 100%; height: 100%; @if $polygon != 0 { clip-path: polygon( #{$polygon} ); } } } @mixin theme-element( $flex: 0 0 auto, $width: auto, $height: auto, $polygon: 0, $border: 0 ) { flex: $flex; width: $width; height: $height; position: relative; @include transition(); @include theme-background( $polygon ); @include theme-border-shape( $border ); } /** Datei: themes/lcars/assets/scss/_fonts.scss **/ @import url('https://fonts.googleapis.com/css2?family=Source+Sans+3:ital,wght@0,200..900;1,200..900&family=Titillium+Web:ital,wght@0,200;0,300;0,400;0,600;0,700;0,900;1,200;1,300;1,400;1,600;1,700&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Source+Code+Pro:ital,wght@0,200..900;1,200..900&family=Source+Sans+3:ital,wght@0,200..900;1,200..900&family=Titillium+Web:ital,wght@0,200;0,300;0,400;0,600;0,700;0,900;1,200;1,300;1,400;1,600;1,700&display=swap'); @font-face { font-family: 'Antonio'; font-style: normal; font-weight: 100 700; font-display: swap; src: url(https://fonts.gstatic.com/s/antonio/v19/gNMEW3NwSYq_9WD3yHQiFQ.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; size-adjust: 110%; ascent-override: 97%; } .font--text { font-family: 'Source Sans 3', sans-serif; font-weight: 350; } .font--monospace { font-family: 'Source Code Pro', monospace; font-weight: 350; } .font--headline { font-family: 'Antonio', sans-serif; font-weight: 600; text-transform: uppercase; } .font--button { font-family: 'Antonio', sans-serif; font-weight: 500; text-transform: uppercase; } .font-size--dynamic { --font-size: max( 1rem, calc( var( --font-size--max, 100cqmin ) * var( --font-size--factor, 1 ) ) ); container-type: size; font-size: var( --font-size ); } @for $i from 1 through 100 { .font-size--dynamic-#{$i} { --font-size--max: #{$i}cqmin; @extend .font-size--dynamic; } } /** Datei: themes/lcars/assets/scss/_mixins.scss **/ @mixin glass( $color: #000, $alpha : 0.3, $radius : 1rem ) { background: rgba( #{red( $color )}, #{green( $color )}, #{blue( $color )}, $alpha ); border-radius: $radius; box-shadow: 0 4px #{$radius * 2} rgba(0, 0, 0, 0.1); backdrop-filter: blur( 5px ); @include glass-border( $color, $alpha - 0.1 ); } @mixin glass-border( $color: #000, $alpha : 0.2 ) { border: 1px solid rgba( #{red( $color )}, #{green( $color )}, #{blue( $color )}, #{$alpha * 1.1 } ); } @mixin transition( $transition: $transition ) { transition: #{$transition}; } /** Datei: themes/lcars/assets/scss/styles.scss **/ @import '#{$restdir}/colors/mixins.scss'; @import '#{$restdir}/colors/functions.scss'; @import '#{$restdir}/colors/variables.scss'; @import 'fonts.scss'; @import 'mixins.scss'; @import "functions.scss"; @import "variables.scss"; @import '#{$restdir}/colors/styles.scss'; *, ::before, ::after { box-sizing: border-box !important; } html { font-family: sans-serif; font-size: 18px !important; line-height: 1.2222222222; height: 100%; // width: 100%; max-height: var( --app-h, 100dvh ); // max-width: var( --app-w, 100vw ); margin: 0; padding: 0; background: #000; color: #FFF; container: root / size; --app-k-top: env(keyboard-inset-top); --app-k-left: env(keyboard-inset-left); --app-k-right: env(keyboard-inset-right); --app-k-bottom: env(keyboard-inset-bottom); --app-k-height: env(keyboard-inset-height); --app-k-width: env(keyboard-inset-width); // position: absolute; // // top: env( safe-area-inset-top, 0px ); // left: env( safe-area-inset-left, 0px ); // right: env( safe-area-inset-right, 0px ); // bottom: env( safe-area-inset-bottom, 0px ); } body { padding: 0; margin: 0; display: flex; flex-direction: column; width: 100%; height: 100%; } .theme { background: #000000; color: #ffffff; @media ( max-width: 600px ) { --maxSidebar: #{map-get( $frame-sizes, sm )}; } > * { padding: 10px; } } .tooltip { position: absolute; z-index: 100; background: #000; color: #fff; border: 1px solid #fff; padding: 5px 10px; border-radius: 5px; &__ { &anchor { cursor: pointer; * { pointer-events: none; } } &top { translate: -50% 5px; } &right { translate: 5px -50%; } &left { translate: calc(-100% - 5px) -50%; } } } @import 'frame/styles.scss'; //@import '#{$restdir}/functions'; @import '#{$restdir}/layout/form'; @import '#{$restdir}/layout/tabs'; @import '#{$restdir}/layout/table'; @import '#{$restdir}/layout/button'; //@import '#{$restdir}/wrapper/dialog'; .menu__item, .menu__category, .menu__sub { display: contents; } .form { } .notification { $notify: & !global; border-radius: 0; border-width: #{$frame-border-width}; border-style: solid; background-color: var( --color-background ); border-color: var( --color-border ); color: var( --color-text ); font-family: sans-serif; padding: #{$frame-padding}; display: flex; justify-content: flex-start; align-items: flex-start; gap: #{$frame-padding * 2 + $frame-border-width}; --size: calc( min( 100cqi, var( --height, #{$frame-inner-button} ) ) - #{($frame-padding + $frame-border-width) * 2} ); &__ { &wrapper { $notify-wrapper: & !global; position: relative; height: var( --navbar ); overflow: hidden; display: flex; flex-direction: column; justify-content: end; } &close { $notify-close: & !global; display: none; } &inner { $notify-inner: & !global; font-size: calc( ( var( --size ) - #{$frame-padding} ) / 2 ); white-space: nowrap; overflow: hidden; height: var( --size ); display: flex; flex-direction: column; justify-content: space-between; } &title { $notify-title: & !global; text-transform: uppercase; font-weight: 600; } } .icon { height: var( --size ); font-size: var( --size ); aspect-ratio: 1; display: inline-flex; align-items: center; justify-content: center; &::before { vertical-align: -0.01em; } } &-- { &stacked { flex-direction: column !important; #{$notify} { z-index: 1; position: relative; margin-top: 0; } } &show-on-hover { #{$notify} { gap: 0rem; cursor: help; transition: all 200ms ease-in-out; } #{$notify-inner} { max-width: 0; transition: all 200ms ease-in-out; } &.hover, &:hover { #{$notify-inner} { margin-left: #{$frame-padding * 2 + $frame-border-width}; max-width: 400px; } } } } } .keyboard { --count: calc( var( --tiles ) - var( --columns ) * ( var( --rows ) - 1 ) ); --height: calc( ( 100cqh - ( ( var( --rows ) - 1 ) * var( --gap ) ) ) / var( --rows ) ); display: grid; grid-template-columns: repeat( var( --columns ), 1fr ); // grid-template-rows: repeat( sqrt( var( --count ) ), 1fr ); gap: var(--gap); overflow: hidden; .button { // aspect-ratio: 1; align-self: stretch; justify-self: stretch; .label { height: 100%; font-size: calc( var( --height ) / 2 ); display: flex; align-items: end; } &:last-child { grid-column-end: -1; grid-column-start: var( --count ); } } } .template { &-- { &login { @container root ( width > 800px ) and ( height > 800px ) { #main_section_content { width: min( 800px, 100% ); height: min( 400px, 100% ); align-self: center; justify-self: center; @container root (orientation: landscape) and (aspect-ratio > 1.5) { flex-direction: row; } } } #content_section_content { gap: #{$frame-spacing}; > * { flex: 1 1 50%; justify-content: center; } @container content (orientation: landscape) and (aspect-ratio > 1.5) { flex-direction: row; > * { flex-basis: 50%; } } } } } } #main_section:not(.frame--aside-left):not(.frame--aside-right) { #content_section { &.frame--aside-left { #content_section_content { margin-right: calc( var( --header, var( --footet, 0px ) ) + #{$frame-gap} ); } } } } .error { display: flex; justify-content: center; align-items: center; width: 100%; gap: #{$frame-spacing}; @container error (aspect-ratio < 1.5) { flex-direction: column; --error-w: 6cqw; } @container error (aspect-ratio >= 1.5) { flex-direction: row; } @container error (orientation: landscape) { } &__ { &wrapper { @include colorize( get_color( 'danger' ) ); color: var( --color-border-hover ); display: flex; flex-direction: column; justify-content: center; align-items: center; width: 100%; gap: #{$frame-spacing}; container: error / size; --error-h: 20cqh; --error-w: 4cqw; --error-i: 5; --error-c: 2; --error-m: 1; } &icon { svg { display: block; height: auto; width: auto; height: calc( min( var(--error-h), var(--error-w ) ) * var( --error-i ) ); @container root ( width <= 800px ) or ( height <= 800px ) { @container content (orientation: portrait) { // height: min( #{$error-iconsvg-min * $error-faktor-portrait}, #{$error-iconsvg-max * $error-faktor-portrait} ); } @container content (orientation: landscape) { // height: min( #{$error-iconsvg-min}, #{$error-iconsvg-max} ); } } } } &text { display: flex; flex-direction: column; align-items: center; @container root ( width <= 800px ) or ( height <= 800px ) { @container content (orientation: landscape) { align-items: start; } } } &caption { font-size: calc( min( var(--error-h), var(--error-w ) ) * var( --error-c ) ); text-align: center; gap: #{$frame-gap}; margin: 0; @container root ( width <= 800px ) or ( height <= 800px ) { @container content (orientation: portrait) { // font-size: min( #{$error-caption-min * $error-faktor-portrait}, #{$error-caption-max * $error-faktor-portrait} ); } @container content (orientation: landscape) { // font-size: min( #{$error-caption-min}, #{$error-caption-max} ); } } } &message { font-size: calc( min( var(--error-h), var(--error-w ) ) * var( --error-m ) ); text-align: center; margin: 0; @container root ( width <= 800px ) or ( height <= 800px ) { @container content (orientation: portrait) { // font-size: min( #{$error-message-min * $error-faktor-portrait}, #{$error-message-max * $error-faktor-portrait} ); } @container content (orientation: landscape) { // font-size: min( #{$error-message-min}, #{$error-message-max} ); } } } } } .tabs__item--active { @include colorize( get_color( 'secondary' ) ); max-inline-size: 100vw !important; } .dialog { backdrop-filter: blur( 3px ); background: get_color( 'black', 0.8 ); color: inherit; outline: 0; position: relative; display: contents; &__{ &wrapper { flex-basis: 50%; min-height: #{$frame-gap * 4 + map-get( $frame-sizes, 'sm' ) * 5 }; background: transparent; border-radius: #{$frame-border-radius}; display: grid; box-shadow: none; padding: 0; height: calc( var(--height) + #{$frame-gap * 4 + map-get( $frame-sizes, 'sm' ) * 4 } ); > .frame__section { grid-column: auto; grid-row: auto; } max-width: 100%; height: 100%; } } } /** Datei: themes/lcars/assets/js/components/dynamic.js **/ /** * /lcars/components/dynamic.js * * Some Javascript codes without further description * * @author Sparky * @copyright 2025 ARUNOX * @version 1.0.0 * @since 1.0.0 File is created */ ARUNOX.Templates.register( 'dynamic', { extends : 'layout/section', hooks : { config : { priority : 5, callback : function( config, data ) { return { name : 'main_section_content', color : 'primary', backlink : config.backlink || {}, header : { html : 'h2', after : config.title, }, aside : 'right', content : ARUNOX.Templates.config( 'div', { classes : [ 'frame__content' ], datasets : { arx : { node : 'content', }, }, content : config?.content, }), footer : { after : config.copyright, }, }; }, }, afterRender : function( config, data ) { if( config.backlink?.route ) { this.instance.nodes.header.nodes.right.replace( 'button', { color : 'default', action : config.backlink, icon : 'bi-arrow-left', title : 'Zurück zur Übersicht', }); } }, }, }); /** Datei: themes/lcars/assets/js/hooks/button.js **/ /** * /lcars/hooks/button.js * * Some Javascript codes without further description * * @author Sparky * @copyright 2025 ARUNOX * @version 1.0.0 * @since 1.0.0 File is created */ import '/plugins/rest/assets/js/components/button.js'; ARUNOX.Hooks.register( 'button->config', function( config ) { return Object.assignRecursive( config, { block : 'frame', color : Object.assign( { color : 'primary', prefix : 'theme', }, config.color ), classes : [ config.classes, [ 'frame__element', 'frame__element--button', ]].flat().filter(Boolean), }); }, 5 ); if( 'vibrate' in navigator ) { ARUNOX.Hooks.register( 'button->afterRender', function() { this.instance.element.addEventListener( 'touchstart', event => { navigator.vibrate(50); }); }); } /** Datei: themes/lcars/assets/js/hooks/tabs.js **/ /** * /lcars/hooks/tabs.js * * Some Javascript codes without further description * * @author Sparky * @copyright 2025 ARUNOX * @version 1.0.0 * @since 1.0.0 File is created */ ARUNOX.Hooks.register( 'tabs->afterRender', function( config ) { const section = this.instance.closest( 'layout/section' ); const tabs = this.instance.closest( 'tabs' ); const buttons = this.instance.nodes.buttons; const actions = buttons.root.querySelectorAll( '.tabs__item--action' ); if( buttons ) { section.nodes.header.nodes.after.render(); section.nodes.header.nodes.after.root.append( buttons.root ); } if( actions.length ) { section.nodes.header.nodes.before.render(); section.nodes.header.nodes.before.nodes.inner.root.append( ...actions ); } }); /** Datei: themes/lcars/assets/js/hooks/menus.js **/ /** * /lcars/hooks/_general.js * * Some Javascript codes without further description * * @author Sparky * @copyright 2025 ARUNOX * @version 1.0.0 * @since 1.0.0 File is created */ import '/themes/lcars/assets/js/hooks/button.js'; ARUNOX.Hooks.register( 'addMenus', async function( anchor ) { const wrapper = this.instance.replace( 'div' ); const routes = ( await ARUNOX.Router.routes() ).map( item => { if( !Array.isArray( item.menu ) ) { item.menu = [ item.menu ]; } return item; }); const filtered = routes.filter( item => item.menu.includes( anchor ) ); for( const route of filtered ) { if( route.path ) { wrapper.apply( 'addMenus->item', route ); continue; } wrapper.apply( 'addMenus->category', route, routes ); } }); ARUNOX.Hooks.register( 'addMenus->category', async function( route, routes ) { const filtered = routes.filter( item => item.menu.includes( route.name ) ); const wrapper = this.instance.render( 'div', { classes : [ 'frame__wrapper' ], content : ARUNOX.Templates.config( 'div', { classes : [ 'frame__element', 'frame__element--label' ], content : ARUNOX.Templates.config( 'span', { classes : [ 'label' ], content : route.label, }), styles : { order : 0, } }), styles : { order : route?.order ?? 1, } }); for( const route of filtered ) { wrapper.apply( 'addMenus->item', route ); } }); ARUNOX.Hooks.register( 'addMenus->item', async function( route ) { this.instance.render( 'button', { label : route.label, icon : route.icon, action : route.path, styles : { order : route?.order ?? 1, } }); }); /** Datei: themes/lcars/assets/js/hooks/table.js **/ /** * /lcars/hooks/table.js * * Some Javascript codes without further description * * @author Sparky * @copyright 2025 ARUNOX * @version 1.0.0 * @since 1.0.0 File is created */ ARUNOX.Hooks.register( 'table->afterRender', function( config ) { const section = this.instance.closest( 'layout/section' ); const toolbar = this.instance.nodes.toolbar; const search = this.instance.nodes.searchContainer; const filter = this.instance.nodes.filterContainer; const buttons = this.instance.nodes.buttons; const wrapper = this.instance.nodes.wrapper; if( search ) { section.nodes.footer.nodes.after.render(); section.nodes.footer.nodes.after.nodes.inner.replace( search ); section.nodes.aside.nodes.before.render(); section.nodes.aside.nodes.before.replace( filter ); } if( buttons ) { section.nodes.header.nodes.before.render(); section.nodes.header.nodes.before.replace( buttons ); } toolbar.root.remove(); }); ARUNOX.Hooks.register( 'table->config', function( config ) { if( config.buttons ) { for( const button of config.buttons ) { button.config.color = 'secondary'; } } return config; }); ARUNOX.Hooks.register( 'button->config.node->filterReset', function( config ) { config.styles.order = 1; config.color = 'primary'; return config; }); ARUNOX.Hooks.register( 'button->active', function( active ) { const config = this.instance.config; const nodeName = config?.nodeName; // console.log( nodeName, active ); if( nodeName == 'searchReset' ) { this.instance.root.style.display = !active ? 'none' : null; return; } if( nodeName == 'filterReset' ) { this.instance.root.disabled = !active; return; } if( nodeName.match( /^filter[A-Z][a-zA-Z]*-.*/ ) ) { // if( active ) this.instance.root.classList.remove( 'inactive' ); // else this.instance.root.classList.add( 'inactive' ); if( active ) this.instance.root.classList.add( 'active' ); else this.instance.root.classList.remove( 'active' ); return; } }); /** Datei: themes/lcars/assets/js/hooks/notifications.js **/ /** * /lcars/hooks/notifications.js * * Some Javascript codes without further description * * @author Sparky * @copyright 2025 ARUNOX * @version 1.0.0 * @since 1.0.0 File is created */ import '/plugins/rest/assets/js/components/notifications.js'; ARUNOX.Hooks.register( 'notifications->afterRender', function() { const section = this.instance.closest( 'layout/section' ); if( section ) { section.nodes.header.nodes.before.render(); section.nodes.header.nodes.before.replace( this.instance ); this.instance.addNotification({ duration : 0, icon : 'bi-bell', title : 'Benachrichtigungen', message : 'Keine Benachrichtigungen', style : { order : -1, }, }); } }); ARUNOX.Hooks.register( 'notification->afterRender', function( config ) { if( config.duration === 0 ) return; config.delay ??= 2000; config.animate ??= config.delay <= 500 ? 100 : 500; if( typeof ARUNOX.Tools?.Beep === 'function' ) { if( config.type == 'danger' ) ARUNOX.Tools.Beep.alert(); else if( config.type == 'success' ) ARUNOX.Tools.Beep.short(); else if( config.type == 'warning' ) ARUNOX.Tools.Beep.long(); } window.setTimeout( () => { this.instance.parent.root.classList.add( 'hover' ); window.setTimeout( () => { this.instance.parent.root.classList.remove('hover'); // if( config.redirect !== false && config.redirect.url !== false ) { // if( config.redirect === true ) location.reload(); // else location.href = config.redirect.url; // } window.setTimeout( () => { this.instance.root.classList.add( 'fade-out' ); window.setTimeout( () => { this.instance.root.remove(); }, 250 ); }, config.message ? 2000 : 0 ); }, config.delay || 2000 ); }, config.animate || 500 ); }); /** Datei: themes/lcars/assets/js/templates/default.js **/ import '/themes/lcars/assets/js/hooks/menus.js'; ARUNOX.Templates.register( 'default', { extends : 'layout/section', hooks : { config : { priority : 5, callback : function( config, data ) { return { name : 'main_section', header : { html : 'h1', size : ARUNOX.Utils.device.isMobile ? 'sm' : 'md', after : config.title, }, aside : { size : 'xl', }, content : ARUNOX.Templates.config( 'div', { classes : [ 'frame__content' ], datasets : { arx : { node : 'content', }, }, content : config?.content, }), footer : { after : config.copyright, }, }; }, }, afterRender : function( config, data ) { this.instance.container.classList.removeRexEx( /template--.*/ ); this.instance.container.classList.add( 'theme' ); this.instance.nodes.footer.nodes.before.apply( 'addMenus', 'tools' ); this.instance.nodes.aside.nodes.before.apply( 'addMenus', 'sidebar' ); this.instance.render( 'notifications' ); }, }, }); /** Datei: themes/lcars/assets/js/templates/dialog.js **/ /** * /components/dialog.js * * Dialog-Component für LCARS - schiebt sich von rechts rein * * @author Sparky * @copyright 2025 ARUNOX * @version 1.0.0 * @since 1.0.0 File created */ ARUNOX.Templates.register('dialog', { extends : 'layout/section', hooks : { config : { priority : 5, callback : function( config, data ) { return { name : 'dialog_section', color : 'secondary', header : { html : 'h3', size : 'sm', after : config.title, right : config.close ? { content : [ ARUNOX.Templates.config('button', { icon : 'bi bi-x-lg', color : 'danger', title : 'Schließen', datasets : { arx : { action : 'close-dialog' } } }) ] } : undefined }, aside : true, content : ARUNOX.Templates.config('div', { classes : ['frame__content'], content : config?.content, }), // footer : false, }; }, }, afterRender1 : function(config, data) { const mainSection = document.querySelector('[data-arx-node="main_section_content"]'); // Dialog-Wrapper erstellen falls nicht vorhanden let dialogWrapper = document.querySelector('.dialog__wrapper'); if (!dialogWrapper) { dialogWrapper = document.createElement('div'); dialogWrapper.classList.add('dialog__wrapper'); // Nach der main_section_content einfügen if (mainSection) { mainSection.parentElement.appendChild(dialogWrapper); } } // Dialog in Wrapper verschieben dialogWrapper.appendChild(this.instance.root); // Size-Klasse setzen const size = config.size || 'md'; this.instance.root.classList.add('dialog', `dialog--size-${size}`); // Animation triggern requestAnimationFrame(() => { this.instance.root.classList.add('dialog--open'); }); // Backdrop hinzufügen wenn gewünscht if (config.backdrop) { const backdrop = document.createElement('div'); backdrop.classList.add('dialog__backdrop'); dialogWrapper.appendChild(backdrop); // Backdrop verschieben damit es hinter dem Dialog ist dialogWrapper.insertBefore(backdrop, this.instance.root); requestAnimationFrame(() => { backdrop.classList.add('dialog__backdrop--visible'); }); } // Content-Section Größe anpassen if (mainSection) { mainSection.classList.add(`dialog-active--${size}`); } // Close-Handler this.instance.root.addEventListener('click', (event) => { const closeBtn = event.target.closest('[data-arx-action="close-dialog"]'); if (closeBtn || (config.backdrop && event.target.classList.contains('dialog__backdrop'))) { this.instance.apply('close'); } }); }, close : function() { const mainSection = document.querySelector('[data-arx-node="main_section_content"]'); const dialogWrapper = this.instance.root.closest('.dialog__wrapper'); const backdrop = dialogWrapper?.querySelector('.dialog__backdrop'); // Animation rückwärts this.instance.root.classList.remove('dialog--open'); if (backdrop) backdrop.classList.remove('dialog__backdrop--visible'); // Content-Section zurücksetzen if (mainSection) { mainSection.classList.removeRexEx(/dialog-active--.*/); } // Nach Animation entfernen setTimeout(() => { if (backdrop) backdrop.remove(); this.instance.root.remove(); // Wrapper entfernen wenn leer if (dialogWrapper && !dialogWrapper.querySelector('.dialog')) { dialogWrapper.remove(); } }, 300); } }, }); /** Datei: themes/lcars/assets/js/layouts/section/navbar.js **/ /** * /lcars/components/section/navbar.js * * Some Javascript codes without further description * * @author Sparky * @copyright 2025 ARUNOX * @version 2.0.0 * @since 2.0.0 Adaptation to new ctx method * @since 1.0.0 File is created */ ARUNOX.Templates.register( 'layout/section/navbar', { htmlTag : 'nav', hooks : { config : function( config ) { config.datasets.arx.node = this.instance.htmlTag; config.classes.push( 'frame__navbar', `frame__navbar--${this.instance.htmlTag}` ); return config; }, corner : function( config, position ) { return Object.assign( { id : `${this.instance.parent.config.name}_${position}`, classes : [ 'frame__wrapper', 'frame__element', `frame__navbar--${position}` ], keepOnReplace : { classes : [ 'frame__*' ], }, content : [ ARUNOX.Templates.config( 'div', { classes : [ 'frame__wrapper__inner' ], }), ], }, config || {} ); }, toolbar : function( config, position ) { return Object.assign( { id : `${this.instance.parent.config.name}_${position}`, classes : [ 'frame__wrapper', `frame__navbar--${position}` ], keepOnReplace : { classes : [ 'frame__*' ], }, content : [ ARUNOX.Templates.config( 'div', { nodeName : 'inner', classes : [ 'frame__wrapper__inner' ], content : typeof config.textNode === 'string' ? [ ARUNOX.Templates.config( this.instance.config.html || 'div', { classes : [ 'frame__title' ], content : config.textNode, }) ] : config.content, }), ], }, config || {} ); }, nodeRight : function( config ) { return this.instance.filter( 'corner', config || {}, 'right' ); }, nodeBefore : function( config ) { return this.instance.filter( 'toolbar', config || {}, 'before' ); }, nodeCenter : function( config ) { return this.instance.filter( 'toolbar', config || {}, 'center' ); }, nodeAfter : function( config ) { return this.instance.filter( 'toolbar', config || {}, 'after' ); }, nodeLeft : function( config ) { if( this.instance.parent.config.aside.visibility ) { config = Object.assignRecursive( {}, config || {}, { classes : [ 'frame__element', 'frame__element--corner' ], datasets : { arx : { node : 'corner', }, }, }); } return this.instance.filter( 'corner', config || {}, 'left' ); }, }, builder : function( config, data ) { const fillBefore= this.render( 'div', { classes : [ 'frame__element', 'frame__element--fill' ], datasets : { arx : { node : 'fillBefore', }, } }); const fillAfter = this.render( 'div', { classes : [ 'frame__element', 'frame__element--fill' ], datasets : { arx : { node : 'fillAfter', }, } }); this.parent.root.classList.add( `frame--${this.htmlTag}-${config.size}` ); this.node( 'left', config.left || {}, 'prepend' ).render(); this.node( 'before', config.before, 'before', fillBefore ); this.node( 'center', config.center, 'before', fillAfter ); this.node( 'after', config.after, 'after', fillAfter ); this.node( 'right', config.right || {}, 'append' ).render(); if( config.before ) this.nodes.before.render(); if( config.center ) this.nodes.center.render(); if( config.after ) this.nodes.after.render(); }, }); ARUNOX.Templates.register( 'layout/section/header', { htmlTag : 'header', extends : 'layout/section/navbar', }); ARUNOX.Templates.register( 'layout/section/footer', { htmlTag : 'footer', extends : 'layout/section/navbar', }); /** Datei: themes/lcars/assets/js/layouts/section/sidebar.js **/ /** * /lcars/components/section/sidebar.js * * Some Javascript codes without further description * * @author Sparky * @copyright 2025 ARUNOX * @version 1.0.0 * @since 1.0.0 File is created */ ARUNOX.Templates.register( 'layout/section/sidebar', { htmlTag : 'aside', hooks : { config : function( config ) { config.datasets.arx.node = this.instance.htmlTag; config.classes.push( 'frame__sidebar' ); return config; }, toolbar : function( config, position ) { return Object.assign( { id : `${this.instance.parent.config.name}_${position}`, classes : [ 'frame__wrapper', `frame__sidebar--${position}` ], keepOnReplace : { classes : [ 'frame__*' ], }, content : [ ARUNOX.Templates.config( 'div', { nodeName : 'inner', classes : [ 'frame__wrapper__inner' ], content : config.content, }), ], }, config || {} ); }, nodeBefore : function( config ) { return this.instance.filter( 'toolbar', config || {}, 'before' ); }, nodeCenter : function( config ) { return this.instance.filter( 'toolbar', config || {}, 'center' ); }, nodeAfter : function( config ) { return this.instance.filter( 'toolbar', config || {}, 'after' ); }, shouldRender : function( render, config, data ) { return this.instance.parent.config.aside.visibility; }, }, builder : function( config, data ) { const fillBefore= this.render( 'div', { classes : [ 'frame__element', 'frame__element--fill' ], datasets : { arx : { node : 'fillBefore', }, } }); const fillAfter = this.render( 'div', { classes : [ 'frame__element', 'frame__element--fill' ], datasets : { arx : { node : 'fillAfter', }, } }); this.parent.root.classList.add( `frame--sidebar-${config.size}`, `frame--sidebar-${config.side}` ); this.node( 'before', config.before, 'before', fillBefore ); this.node( 'center', config.center, 'before', fillAfter ); this.node( 'after', config.after, 'after', fillAfter ); if( config.before ) this.nodes.before.render(); if( config.center ) this.nodes.center.render(); if( config.after ) this.nodes.after.render(); }, }); /** Datei: themes/lcars/assets/js/layouts/section.js **/ /** * /lcars/components/section.js * * Some Javascript codes without further description * * @author Sparky * @copyright 2025 ARUNOX * @version 2.0.0 * @since 2.0.0 Adaptation to new ctx method * @since 1.0.0 File is created */ import '/themes/lcars/assets/js/layouts/section/navbar.js'; import '/themes/lcars/assets/js/layouts/section/sidebar.js'; ARUNOX.Templates.register( 'layout/section', { htmlTag : 'section', hooks : { config : function( config, data ) { // console.log( 'SECTION', config ); config.size ??= 'sm'; config.aside ??= false; config.header ??= {}; config.footer ??= {}; config.content ??= true; config.color ??= 'default'; if( typeof config.aside !== 'undefined' ) { if( typeof config.aside === 'string' ) config.aside = { side : config.aside }; if( typeof config.aside === 'boolean' ) config.aside = { visibility : config.aside }; config.aside.visibility ??= true; config.aside.side ??= config.side || 'left'; config.aside.size ??= config?.size; } if( config.header ) { if( typeof config.header === 'string' ) config.header = { after : config.header }; if( typeof config.header === 'boolean' ) config.header = { visibility : config.header }; config.header.visibility ??= true; config.header.size ??= config?.size; } if( config.footer ) { if( typeof config.footer === 'string' ) config.footer = { after : config.footer }; if( typeof config.footer === 'boolean' ) config.footer = { visibility : config.footer }; config.footer.visibility ??= true; config.footer.size ??= config?.size; } // if( config.content ) { // if( typeof config.content === 'string' ) config.content = { textNode : config.content }; // // config.content.visibility = true; // } return config; }, content : function( content ) { if( content.length > 1 ) { return ARUNOX.Templates.config( 'div', { classes : [ 'frame__content' ], content : content, }); } if( content.length == 1 ) { content[0].config.classes ??= []; content[0].config.classes.push( 'frame__content' ); } return content; }, }, builder : function( config, data ) { config.name = config.name || 'section'; this.root.id = config.name; this.root.classList.add( 'frame__section' ); this.render( 'layout/section/header', config.header, data ); this.render( 'layout/section/sidebar', config.aside, data ); this.render( 'layout/section/footer', config.footer, data ); } }); /** Datei: themes/lcars/assets/js/app.js **/ ARUNOX.Utils.dom.ready(async () => { try { await ARUNOX.Loader.loadAll([ '/plugins/rest/assets/js/hooks/_general.js', ]); ARUNOX.currentTheme = 'lcars'; ARUNOX.themeHookPath = `/themes/${ARUNOX.currentTheme}/assets/js/hooks`; ARUNOX.themeComponentPath = `/plugins/rest/assets/js/components`; await ARUNOX.Router.handle( window.location.pathname + window.location.hash, {}, {}, 'rest' ); } catch( error ) { console.error( 'Failed to initialize app:', error ); } }); /** Datei: themes/lcars/templates/index.php **/ ARUNOX Framework
/** Datei: themes/lcars/assets.OLD/scss/_variables.scss **/ $frame-gap : 7px !default; $frame-padding : 5px !default; $frame-padding-small : 3px !default; $frame-spacing : 20px !default; $frame-border-radius : 0px !default; $frame-border-width : 1px !default; $frame-inner-button : 30px - $frame-border-width * 2; $frame-sizes : ( 'xs' : 21px, 'sm' : 30px, 'md' : 45px, 'lg' : 120px, 'xl' : 180px, ) !default; $icon-font-family : bootstrap-icons; $theme-breakpoints : ( '400px' : ( 'width' : ( 'xs' : 10px, 'sm' : 15px, 'md' : 30px, 'lg' : 60px, 'xl' : 120px, ), 'height' : ( 'sm' : 15px, 'md' : 21px, 'lg' : 30px, ) ), ); $theme-bg-blur : 5px !default; $transition : all 200ms ease-in-out; $transition-slow : all 2000ms ease-in-out; :root { --grid-quantity: 60px; --grid-amount: 75px; --grid-label: 100px; --grid-icon: 30px; } $theme-colors : map-merge( $theme-colors, ( background : get_color( black ), color : get_color( white ), content : get_color( black ), )); // Layoutvariablen für REST //$sidebar-width : 250px; //$header-height : 60px; //$rest-gap-tiny : 5px; //$rest-gap-small : 10px; //$rest-gap-default : 15px; //$rest-gap-wide : 20px; //$rest-border-radius : frame-border-radius; //$rest-frame-font-family : Antonio, sans-serif; $theme-font-family : sans-serif; $theme-icon-font-family : bootstrap-icons; $theme-colorize-alpha : .4; $theme-colorize-bg-alpha : .0; $theme-colorize-border-alpha : .1; $theme-colorize-active-alpha : .1; $theme-colorize-hover-alpha : .2; $table-font-family : $theme-font-family; $table-border-spacing : $frame-gap; $table-header-font-family : $theme-icon-font-family; $table-header-border-width : $frame-border-width; $table-header-bg-color : get_colorize_bg( secondary ); $table-header-bg-color-hover : get_colorize_bg( secondary, $theme-colorize-hover-alpha + $theme-colorize-active-alpha ); $table-header-bg-color-active : get_colorize_bg( secondary, $theme-colorize-hover-alpha ) !default; $table-header-bg-color-active-hover : get_colorize_bg( secondary, $theme-colorize-hover-alpha + $theme-colorize-active-alpha ) !default; $table-header-border-color : get_colorize_border( secondary ); $table-header-border-color-hover : get_colorize_border( secondary, $theme-colorize-hover-alpha + $theme-colorize-active-alpha ); $table-header-border-color-active : get_colorize_border( secondary, $theme-colorize-hover-alpha ) !default; $table-header-border-color-active-hover : get_colorize_border( secondary, $theme-colorize-hover-alpha + $theme-colorize-active-alpha ) !default; $table-cell-border-width : 0; $table-row-bg-color : get_color_tone( content, -200 ); $table-row-bg-color-even : get_color_tone( content, -300 ); $table-row-bg-color-hover : get_color_tone( content, -200, primary ); $table-row-bg-color-hover-even : get_color_tone( content, -300, primary ); $table-row-bg-color-active-hover : get_color_tone( content, -200, secondary ); $table-row-bg-color-active-hover-even : get_color_tone( content, -300, secondary ); $table-row-bg-color-success-even : get_color_tone( content, -300, success ); $table-row-bg-color-success-hover-even : get_color_tone( content, -300, success, 20% ); $table-row-bg-color-success-active-hover-even : get_color_tone( content, -300, success, 30% ); $table-row-bg-color-danger-even : get_color_tone( content, -300, danger ); $table-row-bg-color-danger-hover-even : get_color_tone( content, -300, danger, 20% ); $table-row-bg-color-danger-active-hover-even : get_color_tone( content, -300, danger, 30% ); //--color-background: #{get_color( $color, $alpha )}; //--color-border: #{get_color( $color, #{($alpha - 0.1) * 1.1 } )}; //--color-text: #{contrast( get_color( $color, $alpha ), $light, $dark )}; /** Datei: themes/lcars/assets.OLD/scss/_functions.scss **/ @function map-set( $map, $key, $value ) { @return map-merge( $map, ( $key: $value ) ); } /** Datei: themes/lcars/assets.OLD/scss/frame/_styles.scss **/ :root { --gap: #{$frame-gap}; --gap-negate: #{$frame-gap * -1}; } .frame { &__{ &wrapper { $frame-wrapper: & !global; display: flex; gap: var( --gap ); input { max-height: var(--navbar); min-height: 0; background: transparent; box-shadow: none !important; border-style: solid; border-width: #{$frame-border-width}; border-color: var( --color-border ); color: var( --color-text ); &:focus { border-color: var( --color-border-active ); } &:hover { border-color: var( --color-border-hover ); } } } &element { $frame-element: & !global; border-radius: 0; border-width: #{$frame-border-width}; border-style: solid; background-color: var( --color-background ); border-color: var( --color-border ); color: var( --color-text ); &-- { &fill { $frame-fill: & !global; flex: 1 1 auto; } &label, &button { $frame-label: & !global; font-family: "Antonio", sans-serif; font-weight: 600; text-transform: uppercase; display: flex; gap: #{$frame-padding * 2 + $frame-border-width}; align-items: end; justify-content: space-between; font-size: 1rem; text-decoration: none; padding: #{$frame-padding}; text-align: right; position: relative; background: #000; z-index: 1; > * { z-index: 1; } &::after { content: ''; position: absolute; top: #{$frame-border-width *-1}; left: #{$frame-border-width *-1}; right: #{$frame-border-width *-1}; bottom: #{$frame-border-width *-1}; z-index: -1; background-color: var( --color-background ); } --size: calc( min( 100cqi, var( --height, #{$frame-inner-button} ) ) - #{($frame-padding + $frame-border-width) * 2} ); min-height: 30px; .icon { order: 1; height: var( --size ); font-size: var( --size ); aspect-ratio: 1; pointer-events: none; display: inline-flex; align-items: center; justify-content: center; &::before { vertical-align: -0.01em; } } .label { order: 2; height: var( --size ); font-size: min( var(--size), 20px ); white-space: nowrap; display: block; overflow: hidden; text-overflow: ellipsis; line-height: 1em; flex: 1; min-inline-size: 0; } &:hover, &:focus-within{ max-inline-size: 100vw !important; } } &label { overflow: hidden; text-overflow: ellipsis; display: block; padding-top: #{$frame-spacing}; } &button { $frame-button: & !global; cursor: pointer; &.active, &:active { --color-background: var( --color-background-active ); --color-border: var( --color-borderactive ); --color-text: var( --color-text-active ); } &:hover { --color-background: var( --color-background-hover ); --color-border: var( --color-border-hover ); --color-text: var( --color-text-hover ); } } &corner { $frame-corner: & !global; width: calc( var( --sidebar ) - #{$frame-border-width} ) !important; height: var( --navbar ); position: relative; &::after { content: ''; display: block; position: absolute; background-color: var( --color-background ); border-color: var( --color-border ); border-width: #{$frame-border-width}; border-style: solid; height: var( --navbar ); width: #{$frame-spacing + $frame-border-width}; } } } } &sidebar { $frame-sidebar: & !global; position: relative; display: flex; flex-direction: column; gap: var( --gap ); grid-column: var( --side ); grid-row: 2 / -2; --width: var( --sidebar ); container-type: inline-size; > * { width: var( --sidebar ); } #{$frame-wrapper} { flex-direction: column; z-index: 10; } &:has( > #{$frame-wrapper}:first-child ) { &::before { content: ''; display: block; background-color: var( --color-background ); border-color: var( --color-border ); border-width: #{$frame-border-width}; border-style: solid; margin-top: #{$frame-gap * -1}; width: var( --sidebar ); height: #{$frame-spacing + $frame-border-width}; border-top-width: 0; } } > #{$frame-wrapper} { // overflow-y: auto; } #{$frame-label} { flex: 0 0 auto; inline-size: max-content; min-inline-size: var(--sidebar); max-inline-size: var(--sidebar); transition: max-inline-size 200ms ease; } #{$frame-fill} { &:last-child, &:has( + #{$frame-fill} ) { margin-bottom: var( --gap-negate ); border-bottom-width: 0; } + #{$frame-fill} { border-top-width: 0; } &:first-child { margin-top: var( --gap-negate ); border-top-width: 0; } } } &navbar { $frame-navbar: & !global; position: relative; display: flex; container-type: size; flex-direction: row; gap: var( --gap ); --navbar: var( --height ); grid-column: 1 / -1; // #{$frame-button} { // max-width: var( --navbar ); // width: var( --navbar ); // } #{$frame-label} { flex: 0 0 auto; // inline-size: max-content; min-inline-size: var(--navbar); max-inline-size: var(--navbar); transition: max-inline-size 200ms ease; } #{$frame-wrapper} { flex-direction: row; } &-- { &header { $frame-header: & !global; --height: var( --header ); grid-row: 1; #{$frame-corner} { border-bottom-width: 0; &::after { top: #{$frame-border-width * -1}; } } } &footer { $frame-footer: & !global; --height: var( --footer ); grid-row: 5; #{$frame-corner} { border-top-width: 0; &::after { bottom: #{$frame-border-width * -1}; } } } &left, &right { width: var(--height); } &after, &before, ¢er { &:empty { display: contents; } } } } §ion { $frame-section: & !global; --columWidth: calc( var( --sidebar ) + #{$frame-spacing} ); grid-template-rows: var( --header ) #{$frame-spacing} 1fr #{$frame-spacing} var( --footer ); grid-template-columns: var( --columWidth ) 1fr var( --columWidth ); position: relative; flex: 1 1 auto; display: grid; margin: 0; overflow: hidden; grid-area: content; gap: var( --gap ); container: section / size; height: 100%; width: 100%; } &content { display: flex; overflow: auto; container: content / size; gap: calc( var( --gap ) * 2 + #{$frame-spacing} ); & > * { flex: 1 1 100%; } } &content, §ion { $frame-content: & !global; grid-column: 1 / -1; grid-row: 3; } &corner { aspect-ratio: 1; } &title { margin: 0; height: var( --height ); font-weight: bold; @extend .font--headline; font-size: 100cqmin; line-height: 1; display: flex; align-items: center; text-transform: uppercase; flex: 0 0 auto; padding-inline: calc( var( --height ) / 2 - var( --gap ) ); } } &--{ &sidebar { &-left { > #{$frame-sidebar} { --side: 1; } > #{$frame-navbar} { #{$frame-corner} { border-right-width: 0; margin-right: #{$frame-spacing + $frame-border-width}; &::after { left: 100%; border-left-width: 0; } } } > #{$frame-content} { grid-column: 2 / -1; } } &-right { > #{$frame-sidebar} { --side: -2; align-items: end; #{$frame-label} { flex-direction: row-reverse; text-align: left; } } #{$frame-section}:not( & ) { > #{$frame-navbar} { #{$frame-fill} { &:has( + #{$frame-fill} ) { margin-right: var( --gap-negate ); border-right-width: 0; } + #{$frame-fill} { border-left-width: 0; } } #{$frame-corner} { &:has( + #{$frame-fill} ) { margin-right: #{$frame-spacing + $frame-border-width - $frame-gap}; &::after { border-right-width: 0; } } + #{$frame-fill} { border-left-width: 0; } } } } > #{$frame-navbar} { flex-direction: row-reverse; #{$frame-corner} { border-left-width: 0; margin-left: #{$frame-spacing + $frame-border-width}; &:has( + #{$frame-fill} ) { margin-left: #{$frame-spacing + $frame-border-width - $frame-gap}; &::after { border-left-width: 0; } + #{$frame-fill} { border-right-width: 0; } } &::after { right: 100%; border-right-width: 0; } } #{$frame-fill} { &:has( + #{$frame-fill} ) { margin-left: var( --gap-negate ); border-left-width: 0; } + #{$frame-fill} { border-left-width: #{$frame-border-width}; border-right-width: 0; } } } #{$frame-wrapper} { align-items: end; } > #{$frame-content} { grid-column: 1 / -2; } } @each $size, $value in $frame-sizes { &-#{$size} { --sidebar: var( --maxSidebar, #{$value} ); } } } &header { @each $size, $value in $frame-sizes { &-#{$size} { --header: #{$value}; } } } &footer { @each $size, $value in $frame-sizes { &-#{$size} { --footer: #{$value}; } } } } } .frame__sidebar { .frame__wrapper{ overflow: visible; } } input, select { color: #fff !important; -webkit-text-fill-color: #fff !important; -webkit-background-clip: text !important; background-clip: text !important; } /** Datei: themes/lcars/assets.OLD/scss/frame/_mixins.scss **/ @mixin element--box() { @include theme-element( $height : var( --height ), $border : '0 0, 0 100%, 100% 100%, 100% 0, #{$theme-element-border} 0, #{$theme-element-border} #{$theme-element-border}, calc( 100% - #{$theme-element-border} ) #{$theme-element-border}, calc( 100% - #{$theme-element-border} ) calc( 100% - #{$theme-element-border} ), #{$theme-element-border} calc( 100% - #{$theme-element-border} ), #{$theme-element-border} 0', ); } @mixin element--break-right() { @include theme-element( $height : var( --height ), $width : calc( var( --height ) / 2), $border : '0 100%, 100% 100%, 100% 0, 0 0, 0 #{$theme-element-border}, calc( 100% - #{$theme-element-border} ) #{$theme-element-border}, calc( 100% - #{$theme-element-border} ) calc( 100% - #{$theme-element-border} ), 0 calc( 100% - #{$theme-element-border})', ); margin-right: $theme-element-gap; } @mixin element--break-left() { @include theme-element( $height : var( --height ), $width : calc( var( --height ) / 2), $border : '100% 100%, 0 100%, 0 0, 100% 0, 100% #{$theme-element-border}, #{$theme-element-border} #{$theme-element-border}, #{$theme-element-border} calc( 100% - #{$theme-element-border} ), 100% calc( 100% - #{$theme-element-border})', ); } @mixin element--corner-left() { @include theme-element( $height : var( --height ), $width : calc( var( --height ) / 2 + #{floor($theme-line-offset)} ), $polygon: '100% 0, 100% 100%, calc( 100% - #{$theme-line-offset}) 100%, 0 50%, calc( 100% - #{$theme-line-offset}) 0', $border : '100% 100%, calc( 100% - #{$theme-line-offset} ) 100%, 0 50%, calc( 100% - #{$theme-line-offset} ) 0, 100% 0, 100% #{$theme-element-border}, #{$theme-element-border + $theme-line-offset} 50%, 100% calc( 100% - #{$theme-element-border})', ); } @mixin element--corner-right() { @include theme-element( $height : var( --height ), $width : calc( var( --height ) / 2 + #{floor($theme-line-offset)} ), $polygon: '0 0, 0 100%, #{$theme-line-offset} 100%, 100% 50%, #{$theme-line-offset} 0', $border :'0 100%, #{$theme-line-offset} 100%, 100% 50%, #{$theme-line-offset} 0, 0 0, 0 #{$theme-element-border}, calc( 100% - #{$theme-element-border + $theme-line-offset}) 50%, 0 calc( 100% - #{$theme-element-border})', ); } @mixin element--corner-top-left() { @include theme-element( $width : calc( var( --width ) + var( --height ) / 3 ), $height : calc( var( --height ) + var( --height ) / 3 ), $polygon: 'var( --height ) 0px, 0px var( --height ), 0px 100%, calc( 100% - var( --height, var( --height ) ) / 3 ) 100%, 100% var( --height ), 100% 0', $border : '0px 100%, 0px var( --height ), var( --height ) 0px, 100% 0px, 100% #{$theme-element-border}, calc( var( --height ) + #{$theme-line-offset} ) #{$theme-element-border}, #{$theme-element-border} calc( var( --height ) + #{$theme-line-offset} ), #{$theme-element-border} 100%, calc( 100% - var( --height ) / 3 ) 100%, 100% var( --height ), 100% calc( var( --height ) - #{$theme-element-border} ), calc( 100% - #{$theme-line-offset} ) calc( var( --height ) - #{$theme-element-border} ), calc( 100% - var( --height ) / 3 - #{$theme-element-border} ) calc( 100% - #{$theme-line-offset} ), calc( 100% - var( --height ) / 3 - #{$theme-element-border} ) 100%' ); } @mixin element--corner-top-right() { @include theme-element( $width : calc( var( --width ) + var( --height ) / 3 ), $height : calc( var( --height ) + var( --height ) / 3 ), $polygon: 'var( --height ) 0px, 0px var( --height ), 0px 100%, calc( 100% - var( --height, var( --height ) ) / 3 ) 100%, 100% var( --height ), 100% 0', $border : '0px 100%, 0px var( --height ), var( --height ) 0px, 100% 0px, 100% #{$theme-element-border}, calc( var( --height ) + #{$theme-line-offset} ) #{$theme-element-border}, #{$theme-element-border} calc( var( --height ) + #{$theme-line-offset} ), #{$theme-element-border} 100%, calc( 100% - var( --height, var( --height ) ) / 3 ) 100%, 100% var( --height ), 100% calc( var( --height ) - #{$theme-element-border} ), calc( 100% - #{$theme-line-offset} ) calc( var( --height ) - #{$theme-element-border} ), calc( 100% - var( --height ) / 3 - #{$theme-element-border} ) calc( 100% - #{$theme-line-offset} ), calc( 100% - var( --height ) / 3 - #{$theme-element-border} ) 100%' ); scale: -1 1; } @mixin element--corner-bottom-left() { @include theme-element( $width : calc( var( --width ) + var( --height ) / 3 ), $height : calc( var( --height ) + var( --height ) / 3 ), $polygon: 'var( --height ) 0px, 0px var( --height ), 0px 100%, calc( 100% - var( --height, var( --height ) ) / 3 ) 100%, 100% var( --height ), 100% 0', $border : '0px 100%, 0px var( --height ), var( --height ) 0px, 100% 0px, 100% #{$theme-element-border}, calc( var( --height ) + #{$theme-line-offset} ) #{$theme-element-border}, #{$theme-element-border} calc( var( --height ) + #{$theme-line-offset} ), #{$theme-element-border} 100%, calc( 100% - var( --height, var( --height ) ) / 3 ) 100%, 100% var( --height ), 100% calc( var( --height ) - #{$theme-element-border} ), calc( 100% - #{$theme-line-offset} ) calc( var( --height ) - #{$theme-element-border} ), calc( 100% - var( --height ) / 3 - #{$theme-element-border} ) calc( 100% - #{$theme-line-offset} ), calc( 100% - var( --height ) / 3 - #{$theme-element-border} ) 100%' ); scale: 1 -1; } @mixin element--corner-bottom-right() { @include theme-element( $width : calc( var( --width ) + var( --height ) / 3 ), $height : calc( var( --height ) + var( --height ) / 3 ), $polygon: 'var( --height ) 0px, 0px var( --height ), 0px 100%, calc( 100% - var( --height, var( --height ) ) / 3 ) 100%, 100% var( --height ), 100% 0', $border : '0px 100%, 0px var( --height ), var( --height ) 0px, 100% 0px, 100% #{$theme-element-border}, calc( var( --height ) + #{$theme-line-offset} ) #{$theme-element-border}, #{$theme-element-border} calc( var( --height ) + #{$theme-line-offset} ), #{$theme-element-border} 100%, calc( 100% - var( --height, var( --height ) ) / 3 ) 100%, 100% var( --height ), 100% calc( var( --height ) - #{$theme-element-border} ), calc( 100% - #{$theme-line-offset} ) calc( var( --height ) - #{$theme-element-border} ), calc( 100% - var( --height ) / 3 - #{$theme-element-border} ) calc( 100% - #{$theme-line-offset} ), calc( 100% - var( --height ) / 3 - #{$theme-element-border} ) 100%' ); scale: -1 -1; } @mixin theme-background( $polygon: 0 ) { position: relative; &::before { @include transition(); content: ''; display: block; z-index: -1; position: absolute; top: 0; left: 0; width: 100%; height: 100%; @if $polygon != 0 { clip-path: polygon( #{$polygon} ); } } @if $polygon != 0 { clip-path: polygon( #{$polygon} ); } backdrop-filter: blur( $theme-bg-blur ); } @mixin theme-border( $width: 0, $color: var( --brand-primary-alpha2 ) ) { border-color: $color; border-style: solid; border-width: $width; } @mixin theme-border-shape( $polygon ) { &::after { @include transition(); z-index: -1; content: ''; display: block; position: absolute; top: 0; left: 0; width: 100%; height: 100%; @if $polygon != 0 { clip-path: polygon( #{$polygon} ); } } } @mixin theme-element( $flex: 0 0 auto, $width: auto, $height: auto, $polygon: 0, $border: 0 ) { flex: $flex; width: $width; height: $height; position: relative; @include transition(); @include theme-background( $polygon ); @include theme-border-shape( $border ); } /** Datei: themes/lcars/assets.OLD/scss/_fonts.scss **/ @import url('https://fonts.googleapis.com/css2?family=Source+Sans+3:ital,wght@0,200..900;1,200..900&family=Titillium+Web:ital,wght@0,200;0,300;0,400;0,600;0,700;0,900;1,200;1,300;1,400;1,600;1,700&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Source+Code+Pro:ital,wght@0,200..900;1,200..900&family=Source+Sans+3:ital,wght@0,200..900;1,200..900&family=Titillium+Web:ital,wght@0,200;0,300;0,400;0,600;0,700;0,900;1,200;1,300;1,400;1,600;1,700&display=swap'); @font-face { font-family: 'Antonio'; font-style: normal; font-weight: 100 700; font-display: swap; src: url(https://fonts.gstatic.com/s/antonio/v19/gNMEW3NwSYq_9WD3yHQiFQ.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; size-adjust: 110%; ascent-override: 97%; } .font--text { font-family: 'Source Sans 3', sans-serif; font-weight: 350; } .font--monospace { font-family: 'Source Code Pro', monospace; font-weight: 350; } .font--headline { font-family: 'Antonio', sans-serif; font-weight: 600; text-transform: uppercase; } .font--button { font-family: 'Antonio', sans-serif; font-weight: 500; text-transform: uppercase; } .font-size--dynamic { --font-size: max( 1rem, calc( var( --font-size--max, 100cqmin ) * var( --font-size--factor, 1 ) ) ); container-type: size; font-size: var( --font-size ); } @for $i from 1 through 100 { .font-size--dynamic-#{$i} { --font-size--max: #{$i}cqmin; @extend .font-size--dynamic; } } /** Datei: themes/lcars/assets.OLD/scss/_mixins.scss **/ @mixin glass( $color: #000, $alpha : 0.3, $radius : 1rem ) { background: rgba( #{red( $color )}, #{green( $color )}, #{blue( $color )}, $alpha ); border-radius: $radius; box-shadow: 0 4px #{$radius * 2} rgba(0, 0, 0, 0.1); backdrop-filter: blur( 5px ); @include glass-border( $color, $alpha - 0.1 ); } @mixin glass-border( $color: #000, $alpha : 0.2 ) { border: 1px solid rgba( #{red( $color )}, #{green( $color )}, #{blue( $color )}, #{$alpha * 1.1 } ); } @mixin transition( $transition: $transition ) { transition: #{$transition}; } /** Datei: themes/lcars/assets.OLD/scss/styles.scss **/ @import '#{$restdir}/colors/mixins.scss'; @import '#{$restdir}/colors/functions.scss'; @import '#{$restdir}/colors/variables.scss'; @import 'fonts.scss'; @import 'mixins.scss'; @import "functions.scss"; @import "variables.scss"; @import '#{$restdir}/colors/styles.scss'; //@import '#{$restdir}/colors/styles.scss'; //@import 'framework.scss'; *, ::before, ::after { box-sizing: border-box !important; } html { font-family: sans-serif; font-size: 18px !important; line-height: 1.2222222222; height: 100%; // width: 100%; max-height: var( --app-h, 100dvh ); // max-width: var( --app-w, 100vw ); margin: 0; padding: 0; background: #000; color: #FFF; container: root / size; --app-k-top: env(keyboard-inset-top); --app-k-left: env(keyboard-inset-left); --app-k-right: env(keyboard-inset-right); --app-k-bottom: env(keyboard-inset-bottom); --app-k-height: env(keyboard-inset-height); --app-k-width: env(keyboard-inset-width); // position: absolute; // // top: env( safe-area-inset-top, 0px ); // left: env( safe-area-inset-left, 0px ); // right: env( safe-area-inset-right, 0px ); // bottom: env( safe-area-inset-bottom, 0px ); } body { padding: 0; margin: 0; display: flex; flex-direction: column; width: 100%; height: 100%; } .theme { background: #000000; color: #ffffff; @media ( max-width: 600px ) { --maxSidebar: #{map-get( $frame-sizes, sm )}; } > * { padding: 10px; } } .tooltip { position: absolute; z-index: 100; background: #000; color: #fff; border: 1px solid #fff; padding: 5px 10px; border-radius: 5px; &__ { &anchor { cursor: pointer; * { pointer-events: none; } } &top { translate: -50% 5px; } &right { translate: 5px -50%; } &left { translate: calc(-100% - 5px) -50%; } } } @import 'frame/styles.scss'; @import '#{$restdir}/functions'; @import '#{$restdir}/layout/form'; @import '#{$restdir}/layout/table'; @import '#{$restdir}/wrapper/dialog'; .menu__item, .menu__category, .menu__sub { display: contents; } .form { } .notification { $notify: & !global; border-radius: 0; border-width: #{$frame-border-width}; border-style: solid; background-color: var( --color-background ); border-color: var( --color-border ); color: var( --color-text ); font-family: sans-serif; padding: #{$frame-padding}; display: flex; justify-content: flex-start; align-items: flex-start; gap: #{$frame-padding * 2 + $frame-border-width}; --size: calc( min( 100cqi, var( --height, #{$frame-inner-button} ) ) - #{($frame-padding + $frame-border-width) * 2} ); &__ { &wrapper { $notify-wrapper: & !global; position: relative; height: var( --navbar ); overflow: hidden; display: flex; flex-direction: column; justify-content: end; } &close { $notify-close: & !global; display: none; } &inner { $notify-inner: & !global; font-size: calc( ( var( --size ) - #{$frame-padding} ) / 2 ); white-space: nowrap; overflow: hidden; height: var( --size ); display: flex; flex-direction: column; justify-content: space-between; } &title { $notify-title: & !global; text-transform: uppercase; font-weight: 600; } } .icon { height: var( --size ); font-size: var( --size ); aspect-ratio: 1; display: inline-flex; align-items: center; justify-content: center; &::before { vertical-align: -0.01em; } } &-- { &stacked { flex-direction: column !important; #{$notify} { z-index: 1; position: relative; margin-top: 0; } } &show-on-hover { #{$notify} { gap: 0rem; cursor: help; transition: all 200ms ease-in-out; } #{$notify-inner} { max-width: 0; transition: all 200ms ease-in-out; } &.hover, &:hover { #{$notify-inner} { margin-left: #{$frame-padding * 2 + $frame-border-width}; max-width: 400px; } } } } } .keyboard { --count: calc( var( --tiles ) - var( --columns ) * ( var( --rows ) - 1 ) ); --height: calc( ( 100cqh - ( ( var( --rows ) - 1 ) * var( --gap ) ) ) / var( --rows ) ); display: grid; grid-template-columns: repeat( var( --columns ), 1fr ); // grid-template-rows: repeat( sqrt( var( --count ) ), 1fr ); gap: var(--gap); overflow: hidden; .button { // aspect-ratio: 1; align-self: stretch; justify-self: stretch; .label { height: 100%; font-size: calc( var( --height ) / 2 ); display: flex; align-items: end; } &:last-child { grid-column-end: -1; grid-column-start: var( --count ); } } } .template { &-- { &login { @container root ( width > 800px ) and ( height > 800px ) { #main_section_content { width: min( 800px, 100% ); height: min( 400px, 100% ); align-self: center; justify-self: center; @container root (orientation: landscape) and (aspect-ratio > 1.5) { flex-direction: row; } } } #content_section_content { gap: #{$frame-spacing}; > * { flex: 1 1 50%; justify-content: center; } @container content (orientation: landscape) and (aspect-ratio > 1.5) { flex-direction: row; > * { flex-basis: 50%; } } } } } } #main_section:not(.frame--aside-left):not(.frame--aside-right) { #content_section { &.frame--aside-left { #content_section_content { margin-right: calc( var( --header, var( --footet, 0px ) ) + #{$frame-gap} ); } } } } .error { display: flex; justify-content: center; align-items: center; width: 100%; gap: #{$frame-spacing}; @container error (aspect-ratio < 1.5) { flex-direction: column; --error-w: 6cqw; } @container error (aspect-ratio >= 1.5) { flex-direction: row; } @container error (orientation: landscape) { } &__ { &wrapper { @include colorize( get_color( 'danger' ) ); color: var( --color-border-hover ); display: flex; flex-direction: column; justify-content: center; align-items: center; width: 100%; gap: #{$frame-spacing}; container: error / size; --error-h: 20cqh; --error-w: 4cqw; --error-i: 5; --error-c: 2; --error-m: 1; } &icon { svg { display: block; height: auto; width: auto; height: calc( min( var(--error-h), var(--error-w ) ) * var( --error-i ) ); @container root ( width <= 800px ) or ( height <= 800px ) { @container content (orientation: portrait) { // height: min( #{$error-iconsvg-min * $error-faktor-portrait}, #{$error-iconsvg-max * $error-faktor-portrait} ); } @container content (orientation: landscape) { // height: min( #{$error-iconsvg-min}, #{$error-iconsvg-max} ); } } } } &text { display: flex; flex-direction: column; align-items: center; @container root ( width <= 800px ) or ( height <= 800px ) { @container content (orientation: landscape) { align-items: start; } } } &caption { font-size: calc( min( var(--error-h), var(--error-w ) ) * var( --error-c ) ); text-align: center; gap: #{$frame-gap}; margin: 0; @container root ( width <= 800px ) or ( height <= 800px ) { @container content (orientation: portrait) { // font-size: min( #{$error-caption-min * $error-faktor-portrait}, #{$error-caption-max * $error-faktor-portrait} ); } @container content (orientation: landscape) { // font-size: min( #{$error-caption-min}, #{$error-caption-max} ); } } } &message { font-size: calc( min( var(--error-h), var(--error-w ) ) * var( --error-m ) ); text-align: center; margin: 0; @container root ( width <= 800px ) or ( height <= 800px ) { @container content (orientation: portrait) { // font-size: min( #{$error-message-min * $error-faktor-portrait}, #{$error-message-max * $error-faktor-portrait} ); } @container content (orientation: landscape) { // font-size: min( #{$error-message-min}, #{$error-message-max} ); } } } } } .tabs__item--active { @include colorize( get_color( 'secondary' ) ); max-inline-size: 100vw !important; } .dialog { backdrop-filter: blur( 3px ); background: get_color( 'black', 0.8 ); color: inherit; outline: 0; position: relative; display: contents; &__{ &wrapper { flex-basis: 50%; min-height: #{$frame-gap * 4 + map-get( $frame-sizes, 'sm' ) * 5 }; background: transparent; border-radius: #{$frame-border-radius}; display: grid; box-shadow: none; padding: 0; height: calc( var(--height) + #{$frame-gap * 4 + map-get( $frame-sizes, 'sm' ) * 4 } ); > .frame__section { grid-column: auto; grid-row: auto; } max-width: 100%; height: 100%; } } } /** Datei: themes/lcars/assets.OLD/js/arunox/tools.beep.js **/ window.ARUNOX ??= {}; ARUNOX.Tools ??= {}; var audioCtx = new ( window.AudioContext || window.webkitAudioContext || window.audioContext ); ARUNOX.Tools.Beep = (duration, frequency, volume, type, callback) => { var oscillator = audioCtx.createOscillator(); var gainNode = audioCtx.createGain(); oscillator.connect(gainNode); gainNode.connect(audioCtx.destination); if (volume) { gainNode.gain.value = volume; } if (frequency) { oscillator.frequency.value = frequency; } if (type) { oscillator.type = type; } if (callback) { oscillator.onended = callback; } oscillator.start(audioCtx.currentTime); oscillator.stop(audioCtx.currentTime + ((duration || 500) / 1000)); }; ARUNOX.Tools.Beep.short = () => { ARUNOX.Tools.Beep(100, 600, 1, 'square') }; ARUNOX.Tools.Beep.long = () => { ARUNOX.Tools.Beep(300, 600, 1, 'square') }; ARUNOX.Tools.Beep.alert = () => { ARUNOX.Tools.Beep(100, 900, 1, 'square') window.setTimeout( () => { ARUNOX.Tools.Beep(100, 900, 1, 'square') }, 100 ); }; /** Datei: themes/lcars/assets.OLD/js/arunox/components/section/navbar.js **/ /** * /lcars/components/section/navbar.js * * Some Javascript codes without further description * * @author Sparky * @copyright 2025 ARUNOX * @version 2.0.0 * @since 2.0.0 Adaptation to new ctx method * @since 1.0.0 File is created */ ARUNOX.Templates.register( 'layout/section/navbar', { htmlTag : 'nav', hooks : { config : function( config ) { config.datasets.arx.node = this.instance.htmlTag; config.classes.push( 'frame__navbar', `frame__navbar--${this.instance.htmlTag}` ); return config; }, corner : function( config, position ) { return Object.assign( { id : `${this.instance.parent.config.name}_${position}`, classes : [ 'frame__wrapper', 'frame__element', `frame__navbar--${position}` ], keepOnReplace : { classes : [ 'frame__*' ], }, content : [ ARUNOX.Templates.config( 'div', { classes : [ 'frame__wrapper__inner' ], }), ], }, config || {} ); }, toolbar : function( config, position ) { return Object.assign( { id : `${this.instance.parent.config.name}_${position}`, classes : [ 'frame__wrapper', `frame__navbar--${position}` ], keepOnReplace : { classes : [ 'frame__*' ], }, content : [ ARUNOX.Templates.config( 'div', { classes : [ 'frame__wrapper__inner' ], content : typeof config.textNode === 'string' ? [ ARUNOX.Templates.config( this.instance.config.html || 'div', { classes : [ 'frame__title' ], content : config.textNode, }) ] : config.content, }), ], }, config || {} ); }, nodeRight : function( config ) { return this.instance.filter( 'corner', config || {}, 'right' ); }, nodeBefore : function( config ) { return this.instance.filter( 'toolbar', config || {}, 'before' ); }, nodeCenter : function( config ) { return this.instance.filter( 'toolbar', config || {}, 'center' ); }, nodeAfter : function( config ) { return this.instance.filter( 'toolbar', config || {}, 'after' ); }, nodeLeft : function( config ) { if( this.instance.parent.config.aside.visibility ) { config = Object.assignRecursive( {}, config || {}, { classes : [ 'frame__element', 'frame__element--corner' ], datasets : { arx : { node : 'corner', }, }, }); } return this.instance.filter( 'corner', config || {}, 'left' ); }, }, builder : function( config, data ) { const fillBefore= this.render( 'div', { classes : [ 'frame__element', 'frame__element--fill' ], datasets : { arx : { node : 'fillBefore', }, } }); const fillAfter = this.render( 'div', { classes : [ 'frame__element', 'frame__element--fill' ], datasets : { arx : { node : 'fillAfter', }, } }); this.parent.root.classList.add( `frame--${this.htmlTag}-${config.size}` ); this.node( 'left', {}, 'prepend' ).render(); this.node( 'before', config.before, 'before', fillBefore ); this.node( 'center', config.center, 'before', fillAfter ); this.node( 'after', config.after, 'after', fillAfter ); this.node( 'right', {}, 'append' ).render(); if( config.before ) this.nodes.before.render(); if( config.center ) this.nodes.center.render(); if( config.after ) this.nodes.after.render(); }, }); ARUNOX.Templates.register( 'layout/section/header', { htmlTag : 'header', extends : 'layout/section/navbar', }); ARUNOX.Templates.register( 'layout/section/footer', { htmlTag : 'footer', extends : 'layout/section/navbar', }); /** Datei: themes/lcars/assets.OLD/js/arunox/components/section/sidebar.js **/ /** * /lcars/components/section/sidebar.js * * Some Javascript codes without further description * * @author Sparky * @copyright 2025 ARUNOX * @version 1.0.0 * @since 1.0.0 File is created */ ARUNOX.Templates.register( 'layout/section/sidebar', { htmlTag : 'aside', hooks : { config : function( config ) { config.datasets.arx.node = this.instance.htmlTag; config.classes.push( 'frame__sidebar' ); return config; }, toolbar : function( config, position ) { return Object.assign( { id : `${this.instance.parent.config.name}_${position}`, classes : [ 'frame__wrapper', `frame__sidebar--${position}` ], keepOnReplace : { classes : [ 'frame__*' ], }, content : [ ARUNOX.Templates.config( 'div', { classes : [ 'frame__wrapper__inner' ], content : config.content, }), ], }, config || {} ); }, nodeBefore : function( config ) { return this.instance.filter( 'toolbar', config || {}, 'before' ); }, nodeCenter : function( config ) { return this.instance.filter( 'toolbar', config || {}, 'center' ); }, nodeAfter : function( config ) { return this.instance.filter( 'toolbar', config || {}, 'after' ); }, shouldRender : function( render, config, data ) { return this.instance.parent.config.aside.visibility; }, }, builder : function( config, data ) { const fillBefore= this.render( 'div', { classes : [ 'frame__element', 'frame__element--fill' ], datasets : { arx : { node : 'fillBefore', }, } }); const fillAfter = this.render( 'div', { classes : [ 'frame__element', 'frame__element--fill' ], datasets : { arx : { node : 'fillAfter', }, } }); this.parent.root.classList.add( `frame--sidebar-${config.size}`, `frame--sidebar-${config.side}` ); this.node( 'before', config.before, 'before', fillBefore ); this.node( 'center', config.center, 'before', fillAfter ); this.node( 'after', config.after, 'after', fillAfter ); if( config.before ) this.nodes.before.render(); if( config.center ) this.nodes.center.render(); if( config.after ) this.nodes.after.render(); }, }); /** Datei: themes/lcars/assets.OLD/js/arunox/components/dynamic.js **/ /** * /lcars/components/dynamic.js * * Some Javascript codes without further description * * @author Sparky * @copyright 2025 ARUNOX * @version 1.0.0 * @since 1.0.0 File is created */ ARUNOX.Templates.register( 'dynamic', { extends : 'layout/section', hooks : { config : { priority : 5, callback : function( config, data ) { return { name : 'main_section_content', color : 'primary', header : { html : 'h2', after : config.title, }, aside : 'right', content : ARUNOX.Templates.config( 'div', { classes : [ 'frame__content' ], content : config?.content, }), footer : { after : config.copyright, }, }; }, }, }, }); /** Datei: themes/lcars/assets.OLD/js/arunox/components/section.js **/ /** * /lcars/components/section.js * * Some Javascript codes without further description * * @author Sparky * @copyright 2025 ARUNOX * @version 2.0.0 * @since 2.0.0 Adaptation to new ctx method * @since 1.0.0 File is created */ ARUNOX.Templates.register( 'layout/section', { htmlTag : 'section', hooks : { config : function( config, data ) { // console.log( 'SECTION', config ); config.size ??= 'sm'; config.aside ??= false; config.header ??= {}; config.footer ??= {}; config.content ??= true; config.color ??= 'default'; if( typeof config.aside !== 'undefined' ) { if( typeof config.aside === 'string' ) config.aside = { side : config.aside }; if( typeof config.aside === 'boolean' ) config.aside = { visibility : config.aside }; config.aside.visibility ??= true; config.aside.side ??= config.side || 'left'; config.aside.size ??= config?.size; } if( config.header ) { if( typeof config.header === 'string' ) config.header = { after : config.header }; if( typeof config.header === 'boolean' ) config.header = { visibility : config.header }; config.header.visibility ??= true; config.header.size ??= config?.size; } if( config.footer ) { if( typeof config.footer === 'string' ) config.footer = { after : config.footer }; if( typeof config.footer === 'boolean' ) config.footer = { visibility : config.footer }; config.footer.visibility ??= true; config.footer.size ??= config?.size; } // if( config.content ) { // if( typeof config.content === 'string' ) config.content = { textNode : config.content }; // // config.content.visibility = true; // } return config; }, content : function( content ) { if( content.length > 1 ) { return ARUNOX.Templates.config( 'div', { classes : [ 'frame__content' ], content : content, }); } if( content.length == 1 ) { content[0].config.classes ??= []; content[0].config.classes.push( 'frame__content' ); } return content; }, }, builder : function( config, data ) { config.name = config.name || 'section'; this.root.id = config.name; this.root.classList.add( 'frame__section' ); this.render( 'layout/section/header', config.header, data ) this.render( 'layout/section/sidebar', config.aside, data ) this.render( 'layout/section/footer', config.footer, data ) } }); /** Datei: themes/lcars/assets.OLD/js/arunox/hooks/button.js **/ /** * /lcars/hooks/button.js * * Some Javascript codes without further description * * @author Sparky * @copyright 2025 ARUNOX * @version 1.0.0 * @since 1.0.0 File is created */ ARUNOX.Hooks.register( 'button->config', function( config ) { return Object.assignRecursive( config, { block : 'frame', color : Object.assign( { color : 'primary', prefix : 'theme', }, config.color ), classes : [ config.classes, [ 'frame__element', 'frame__element--button', ]].flat().filter(Boolean), }); }, 5 ); if( 'vibrate' in navigator ) { ARUNOX.Hooks.register( 'button->afterRender', function() { this.instance.element.addEventListener( 'touchstart', event => { navigator.vibrate(50); }); }); } /** Datei: themes/lcars/assets.OLD/js/arunox/hooks/menus.js **/ /** * /lcars/hooks/_general.js * * Some Javascript codes without further description * * @author Sparky * @copyright 2025 ARUNOX * @version 1.0.0 * @since 1.0.0 File is created */ ARUNOX.Hooks.register( 'addMenus', async function( anchor ) { const wrapper = this.instance.replace( 'div' ); const routes = ( await ARUNOX.Router.routes() ).map( item => { if( !Array.isArray( item.menu ) ) { item.menu = [ item.menu ]; } return item; }); const filtered = routes.filter( item => item.menu.includes( anchor ) ); for( const route of filtered ) { if( route.path ) { wrapper.apply( 'addMenus->item', route ); continue; } wrapper.apply( 'addMenus->category', route, routes ); } }); ARUNOX.Hooks.register( 'addMenus->category', async function( route, routes ) { const filtered = routes.filter( item => item.menu.includes( route.name ) ); const wrapper = this.instance.render( 'div', { classes : [ 'frame__wrapper' ], content : ARUNOX.Templates.config( 'div', { classes : [ 'frame__element', 'frame__element--label' ], content : ARUNOX.Templates.config( 'span', { classes : [ 'label' ], content : route.label, }), }), }); for( const route of filtered ) { wrapper.apply( 'addMenus->item', route ); } }); ARUNOX.Hooks.register( 'addMenus->item', async function( route ) { this.instance.render( 'button', { label : route.label, icon : route.icon, action : route.path, }); }); /** Datei: themes/lcars/assets.OLD/js/arunox/hooks/form.js **/ /** * rest/arunox/hooks/form.js * * Some Javascript codes without further description * * @author Sparky * @copyright 2025 ARUNOX * @version 1.0.0 * @since 1.0.0 File is created */ ARUNOX.Hooks.register( 'form->afterRender', function() { const section = this.instance.closest( 'layout/section' ); const buttons = this.instance.nodes.buttons; if( section ) { section.nodes.footer.nodes.after.replace( buttons ); } }); /** Datei: themes/lcars/assets.OLD/js/arunox/hooks/notifications.js **/ /** * /lcars/hooks/notifications.js * * Some Javascript codes without further description * * @author Sparky * @copyright 2025 ARUNOX * @version 1.0.0 * @since 1.0.0 File is created */ ARUNOX.Hooks.register( 'notifications->afterRender', function() { const section = this.instance.closest( 'layout/section' ); if( section ) { section.nodes.header.nodes.before.render(); section.nodes.header.nodes.before.replace( this.instance ); this.instance.addNotification({ duration : 0, icon : 'bi-bell', title : 'Benachrichtigungen', message : 'Keine Benachrichtigungen', style : { order : -1, }, }); } }); ARUNOX.Hooks.register( 'notification->afterRender', function() { const config = this.instance.config; if( config.duration === 0 ) return; config.delay ??= 2000; config.animate ??= config.delay <= 500 ? 100 : 500; if( typeof ARUNOX.Tools.Beep === 'function' ) { if( config.type == 'danger' ) ARUNOX.Tools.Beep.alert(); else if( config.type == 'success' ) ARUNOX.Tools.Beep.short(); else if( config.type == 'warning' ) ARUNOX.Tools.Beep.long(); } window.setTimeout( () => { this.instance.parent.root.classList.add( 'hover' ); window.setTimeout( () => { this.instance.parent.root.classList.remove('hover'); // if( config.redirect !== false && config.redirect.url !== false ) { // if( config.redirect === true ) location.reload(); // else location.href = config.redirect.url; // } window.setTimeout( () => { this.instance.root.classList.add( 'fade-out' ); window.setTimeout( () => { this.instance.root.remove(); }, 250 ); }, config.message ? 2000 : 0 ); }, config.delay || 2000 ); }, config.animate || 500 ); }); /** Datei: themes/lcars/assets.OLD/js/arunox/templates/login.js **/ /** * rest/arunox/templates/login.js * * Some Javascript codes without further description * * @author Sparky * @copyright 2025 ARUNOX * @version 2.0.0 * @since 2.0.0 Adaptation to new ctx method * @since 1.0.0 File is created */ ARUNOX.Templates.register( 'login', { extends : 'layout/section', hooks : { config : { priority : 5, callback : function( config, data ) { return { name : 'main_section', size : isMobile ? 'sm' : 'md', header : { html : 'h1', after : config.title, }, content : config?.content, footer : { left : { arx : { ref : 'reload', }, }, after : config.copyright, }, }; }, }, dynamicConfig : { once : true, priority : 6, hook : 'config', template : 'dynamic', callback : function( config, data ) { const loginConfig = { title : 'Login required', message : [ 'Enter login details' ], }; return Object.assignRecursive( config, { color : 'danger', header : { after : false, before : 'Locked', }, aside : { side : 'left', }, content : [ ARUNOX.Templates.config( 'div', { classes : [ 'error__wrapper' ], content : [ ARUNOX.Templates.config( 'div', { classes : 'error', content : [ ARUNOX.Templates.config( 'div', { classes : 'error__icon', innerHTML : ``, }), ARUNOX.Templates.config( 'div', { classes : 'error__text', content : [ ARUNOX.Templates.config( 'h1', { classes : 'error__caption', content : loginConfig.title, }), ARUNOX.Templates.config( 'div', { classes : 'error__message', content : loginConfig.message.join(' or '), }), ], }), ], }), ], }), ] }); }, }, afterRender : function( config, data ) { this.instance.container.classList.removeRexEx( /template--.*/ ); this.instance.container.classList.add( 'theme', 'template--login' ); this.instance.nodes.footer.nodes.left.replace( 'button', { icon : 'bi bi-arrow-clockwise', title : 'Reload', color : { color: 'danger', target: 'button' }, href : 'javascript:location.reload( true );void(0);', target : '_top', }); this.instance.render( 'notifications' ); }, }, }); /** Datei: themes/lcars/assets.OLD/js/arunox/templates/default.js **/ ARUNOX.Templates.register( 'default', { extends : 'layout/section', hooks : { config : { priority : 5, callback : function( config, data ) { return { name : 'main_section', header : { html : 'h1', size : ARUNOX.Utils.device.isMobile ? 'sm' : 'md', after : config.title, }, aside : { size : 'xl', }, content : config?.content, footer : { after : config.copyright, }, }; }, }, afterRender : function( config, data ) { this.instance.container.classList.removeRexEx( /template--.*/ ); this.instance.container.classList.add( 'theme' ); this.instance.nodes.footer.nodes.before.apply( 'addMenus', 'tools' ); this.instance.nodes.aside.nodes.before.apply( 'addMenus', 'sidebar' ); this.instance.render( 'notifications' ); }, }, }); /** Datei: themes/lcars/assets.OLD/js/arunox/app.js **/ ARUNOX.Utils.dom.ready(async () => { try { // await ARUNOX.Loader.loadAll([ // '/assets/js/hooks/_general.js', // '/themes/lcars/js/hooks/button.js', // '/themes/lcars/js/hooks/notifications.js', // // '/themes/lcars/js/components/section.js', // '/themes/lcars/js/components/dynamic.js', // '/themes/lcars/js/templates/default.js', // ]); ARUNOX.currentTheme = 'lcars'; ARUNOX.themeHookPath = `/themes/${ARUNOX.currentTheme}/js/hooks`; ARUNOX.themeComponentPath = `/assets/js/components`; await ARUNOX.Router.handle( window.location.pathname + window.location.hash, {}, {}, 'rest' ); } catch( error ) { console.error( 'Failed to initialize app:', error ); } }); /** Datei: themes/lcars/assets.OLD/js/arunox/tools.keyboard.js **/ window.ARUNOX ??= {}; ARUNOX.Tools ??= {}; ARUNOX.Tools.Keyboard = { _value : '', onHide : null, onShow : null, onAdd : null, onRefresh : null, onClear : null, onClearShow : null, onClearHide : null, onBack : null, onBackShow : null, onBackHide : null, Types : { numbers : [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ], letters : [ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'X', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' ], base16 : [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' ], base36 : [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'X', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' ], }, prefix : '#', type : 'numbers', keys : [], keyConfig : {}, visible : true, content : null, number : null, openBtn : null, closeBtn : null, backBtn : null, clearBtn : null, add : function( key ) { this._value += key; this.refresh(); this._call( this.onAdd ); }, clear : function() { this._value = ''; this.refresh(); this._call( this.onClear ); }, backspace : function() { this._value = this._value.substring( 0, this._value.length - 1 ); this.refresh(); this._call( this.onBack ); }, refresh : function() { this._call( this.onBackHide ); this._call( this.onClearHide ); if( this.number ) { this.number.element.innerText = this.prefix + this._value; this._call( this.onRefresh, this._value ); } if( this._value ) { this._call( this.onBackShow ); this._call( this.onClearShow ); } }, hide : function( onHide ) { this._call( onHide || this.onHide ); }, show : function( onShow ) { this._call( onShow || this.onShow ); }, init : function( options ) { Object.assign( this, {}, options || {} ); if( this.closeBtn ) { this.closeBtn.element.href = 'javascript:ARUNOX.Tools.Keyboard.hide();void(0);'; this.closeBtn.element.target = '_top'; } if( this.openBtn ) { this.openBtn.element.href = 'javascript:ARUNOX.Tools.Keyboard.show();void(0);'; this.openBtn.element.target = '_top'; } if( this.backBtn ) { this.backBtn.element.href = 'javascript:ARUNOX.Tools.Keyboard.backspace();void(0);'; this.backBtn.element.target = '_top'; } if( this.clearBtn ) { this.clearBtn.element.href = 'javascript:ARUNOX.Tools.Keyboard.clear();void(0);'; this.clearBtn.element.target = '_top'; } if( this.content ) { if( !this.keys.length ) this.keys = this.Types[ this.type ]; else this.type = 'custom'; this.content.element.classList.add( 'keyboard', `keybaord--${this.type}` ); this.content.element.style.setProperty( '--tiles', this.keys.length ) this.content.element.style.setProperty( '--columns', Math.ceil( Math.sqrt( this.keys.length ) ) ) this.content.element.style.setProperty( '--rows', Math.floor( Math.sqrt( this.keys.length ) ) ) for( const key of this.keys ) { this.content.render( 'button', Object.assign( { color : 'default', label : key, onClick : () => this.add( key ), }, this.keyConfig ) ); } } this.refresh(); if( this.visible ) this.show(); else this.hide(); }, _call : function( callback, ...args ) { if( typeof callback === 'function' ) { return callback.apply( this, args ); } return false; }, }; /** Datei: themes/lcars/assets.OLD/js/lcars.js **/ /** * lcars.js * * Main Theme Functions * * @author Sparky * @copyright 2025 ARUNOX * @version 1.1.3 * * @since 1.0.0 File is created */ (function(){ const root = document.documentElement; let sizes = []; let kbOpen = false; let version = 2.0; root.classList.add( isMobile ? 'is--mobile' : 'is--desktop'); root.classList.add( isRotatable ? 'is--rotatable' : 'is--not-rotatable'); if( !isRotatable ) return; root.style.setProperty('--app-v', version.toString()); function readHeight( stored ) { return Math.min( stored || screen.availHeight, Math.round(window.visualViewport?.height ?? window.innerHeight ) ); } function readWidth( stored ) { return Math.min( stored || screen.availWidth, Math.round(window.visualViewport?.width ?? window.innerWidth ) ); } function readOrientation() { return [ 0, 180 ].includes( window.screen.orientation.angle ) ? 'portrait' : 'landscape'; } function storeSize() { sizes = fetchSize(); } function fetchSize() { const h = readHeight( sizes?.h ); const w = readWidth( sizes?.w ); const o = readOrientation(); root.style.setProperty('--app-o', o ); root.style.setProperty('--app-h', h + 'px'); root.style.setProperty('--app-w', w + 'px'); return { o, h, w }; } window.addEventListener('DOMContentLoaded', storeSize ); window.addEventListener('resize', fetchSize ); window.addEventListener('orientationchange', ( event) => { const o = readOrientation(); if( o !== sizes.o ) { sizes = { o : o, h : sizes.w, w : sizes.h, }; } }); })(); /** Datei: themes/lcars/config.php **/ '1.0.0', 'dependencies' => ['user'], // Abhängigkeit zum User-Plugin ]; /** Datei: themes/default/library/ARUNOX/Themes/Default/Theme.php **/ * @copyright 2025 ARUNOX * @version 1.0.0 * @since 1.0.0 File is created */ namespace ARUNOX\Themes\Default; use ARUNOX\Core; class Theme extends Core\Theme { /* ### PUBLIC FUNCTIONS ######################################### # */ public function getLable() : string { return 'Default Theme'; } } /** Datei: themes/default/hooks/init.php **/ * @copyright 2025 ARUNOX * @version 1.0.0 * @since 1.0.0 File is created */ use ARUNOX\Core\Hooks; use ARUNOX\Themes\LCARS\Theme; Hooks::add("theme::scripts->before", function() { ?> 0 ) { $color : lighten( $color, $brightness ); } @if( $alpha != 1 ) { $color : rgba( red( $color ), green( $color ), blue( $color ), $alpha ); } @return $color } @function getCoreColor( $color, $alpha : 1, $brightness : 0 ) { @return getColor( $core-colors, $color, $alpha, $brightness ); } @function getThemeColor( $color, $alpha : 1, $brightness : 0 ) { @return getColor( $theme-colors, $color, $alpha, $brightness ); } @function getColorTone( $color, $level : 100, $tint: null, $tint-strength: 15% ) { $base: getThemeColor( $color, 1, getBrightness( $level ) ); @if $tint == null { @return $base; } $accent: getThemeColor( $tint ); @return mix( $accent, $base, $tint-strength ); } @function getBrightness( $level : 100 ) { @return map-get( $brightness-levels, $level ); } $brightness-levels: ( 50 : 5%, 100 : 0%, 200 : -2.5%, 300 : -5%, 400 : -7.5%, 500 : -10%, ); // Farbvariablen $core-colors: ( blue : #33abc9, purple : #800080, green : #28a745, red : #dc3545, yellow : #ffc107, cyan : #17a2b8, gray-darkest : #212529, gray-darker : #495057, gray-dark : #adb5bd, gray : #dee2e6, gray-light : #f1f3f5, gray-lighter : #f8f9fa, gray-lightest : #fcfcfc, white : #ffffff, black : #000000, ); $theme-colors: ( primary : getCoreColor( blue ), secondary : getCoreColor( purple ), success : getCoreColor( green ), danger : getCoreColor( red ), warning : getCoreColor( yellow ), info : getCoreColor( cyan ), text : getCoreColor( gray-darkest ), label : getCoreColor( gray-darker ), border : getCoreColor( gray ), header : getCoreColor( gray-light ), content : getCoreColor( white ), background : getCoreColor( gray-lighter ), ); :root { @each $name, $color in $theme-colors { --theme-color-#{$name} : #{$color}; } } $icon-font-family: bootstrap-icons; // Layoutvariablen $sidebar-width : 250px; $header-height : 60px; $gap-tiny : 5px; $gap-small : 10px; $gap-default : 15px; $gap-wide : 20px; $border-radius : 0; /** Datei: themes/default/assets/scss/components/_breadcrumbs.scss **/ .breadcrumbs { display: flex; gap: 0.5rem; &__{ &item { color: getThemeColor( secondary ); cursor: pointer; &:hover { color: getThemeColor( primary ); } &--active { font-weight: bold; cursor: default; color: getThemeColor( primary ); } &--inactive { cursor: default; color: getThemeColor( primary ); } } &separator { &:before { content: '/'; display: block; } } } } /** Datei: themes/default/assets/scss/components/_button.scss **/ /** * _button.scss * * Stile für die Button-Komponente unter Berücksichtigung von BEM. * * @author Sparky * @copyright 2025 ARUNOX * @version 1.0.2 * @since 1.0.0 File is created * @since 1.0.1 Farben mit Bootstrap-Variablen korrigiert * @since 1.0.2 Dynamische Farben aus _buttons.scss übernommen */ @import "../variables"; // Stellt sicher, dass Theme-Variablen geladen werden @mixin buttonColors() { background-color: var( --color-background ); color: var( --color-text ); &:hover { background-color: var( --color-background-hover ); color: var( --color-text-hover ); } &:active { background-color: var( --color-background-acive ); color: var( --color-text-acive ); } } button { border: 0; background: transparent; outline: 0; } .button { display: inline-flex; align-items: center; justify-content: center; padding: 0.2em 0.6em; font-size: 1rem; border-radius: $border-radius; border: none; cursor: pointer; transition: background 0.3s ease, transform 0.2s ease, box-shadow 0.2s ease; font-weight: bold; gap: $gap-small; min-height: 2rem; outline: 0; @include buttonColors(); & { &-- { &wrapper { position: relative; display: inline-block; } } &__ { &dropdown { position: absolute; top: 100%; right: 0; display: none; z-index: 10; gap: $gap-small; padding: 5px; border: 1px solid #{getCoreColor( gray )}; background: #fff; border-radius: $border-radius; &.open { display: flex; flex-direction: column; } &__item { display: block; width: 100%; .button { width: 100%; background: none; color: #{getThemeColor( text )} !important; min-height: auto; padding: 0.4em 0.8em; font-size: 0.9rem; justify-content: start; white-space: nowrap; &:hover { background: rgba(0, 0, 0, 0.05); } } } } icon { // margin-right: 0.5rem; // font-size: 1.2rem; } } } } /** Datei: themes/default/assets/scss/_tooltip.scss **/ [title], [data-tooltip] { cursor: help; } .tooltip { position: absolute; padding: 0.5rem 1rem; border-radius: $border-radius; background-color: #000; color: #fff; font-size: 0.9rem; text-align: center; z-index: 10000; white-space: nowrap; &::after { content: ''; position: absolute; border-style: solid; border-width: 6px; /* Größe des Pfeils */ display: block; } &.tooltip-bottom::after { top: -12px; /* Pfeil über dem Tooltip */ border-color: transparent transparent #000 transparent; } &.tooltip-top::after { bottom: -12px; /* Pfeil unter dem Tooltip */ border-color: #000 transparent transparent transparent; } &.tooltip-top, &.tooltip-bottom { &.tooltip-align-left::after { left: 10%; transform: translateX(0); } &.tooltip-align-center::after { left: 50%; transform: translateX(-50%); } &.tooltip-align-right::after { right: 10%; transform: translateX(0); } } &.tooltip-left::after { right: -12px; /* Pfeil neben dem Tooltip */ border-color: transparent transparent transparent #000; } &.tooltip-right::after { left: -12px; /* Pfeil neben dem Tooltip */ border-color: transparent #000 transparent transparent; } &.tooltip-left, &.tooltip-right { &.tooltip-align-top::after { top: 10%; transform: translateX(0); } &.tooltip-align-middle::after { top: 50%; transform: translateY(-50%); } &.tooltip-align-bottom::after { bottom: 10%; transform: translateX(0); } } } /** Datei: themes/default/assets/scss/_sidebar.scss **/ .template__sidebar { &.menu { display: flex; flex-direction: column; gap: 0.5rem; overflow-y: auto; color: getThemeColor( primary ); } .menu { &__sub { // display: flex; flex-direction: column; gap: 0.5rem; } &__link, &__label { padding: 0.8rem 1rem; border-radius: $border-radius; font-weight: bold; cursor: pointer; flex: 1 1 auto; } &__link { &--active { background-color: getThemeColor( primary ); color: getCoreColor( white ); } &.behavior-default { &:hover { background-color: getHoverColor( primary ); color: getCoreColor( white ); } } } &__label { border-bottom: 1px solid getThemeColor( border ); background-color: getColorTone( content, 400 ); color: getThemeColor( text ); } &__item { > #{$menu-sub} { padding-left: 0; #{$menu-link} { color: getThemeColor( text ); &:hover { background-color: getHoverColor( border ); } &--active { background-color: getThemeColor( primary ); color: getCoreColor( white ); #{$menu-icon} { color: getCoreColor( white ) !important; } &:hover { background-color: getHoverColor( primary ); } } } } &.has-children { &::after { right: 1rem; top: 0.8rem; translate: 0 0.25em; color: inherit; pointer-events: none; } } &.has-active > #{$menu-link} { background-color: getHoverColor( border ); color: getHoverColor( primary ); &:hover { background-color: getHoverColor( primary ); color: getCoreColor( white ); } } } &__category { margin-block: $gap-wide; // background-color: getColorTone( content, 400 ); } &__icon { font-size: 1.2rem; &:not( :only-child ) { margin-right: 0.5rem; } } } } /** Datei: themes/default/assets/scss/_utilities.scss **/ // Statusfarben @function getContrastColor( $color, $dark, $light, $threshold : 55% ) { @return if( lightness( $color ) < $threshold, $light, $dark ) } $colors: map-merge( $theme-colors, $core-colors ); @each $name, $color in $colors { .bg--colored-#{$name} { --background-color: #{$color}; --color: #{getContrastColor( $color, getCoreColor( black ), getCoreColor( white ) )}; background-color: var( --background-color ) !important; color: var( --color ) !important; } .text--colored-#{$name} { --color: #{$color}; color: var( --color ) !important; } .icon--colored-#{$name} { --icon: #{$color}; i, &:is( i ) { color: var( --icon ) !important; } } .border--colored-#{$name} { --border-color: #{$color}; border-color: var( --border-color ) !important; } } .cursor--pointer { cursor : pointer; }; @keyframes animate-rotate { from { transform: rotate( 0deg ); } to { transform: rotate( 360deg ); } } .opacity-50 { opacity: 0.5 !important; } .opacity-75 { opacity: 0.75 !important; } .opacity-100 { opacity: 1 !important; } .p-1 { padding: 0.25rem !important; } .p-2 { padding: 0.5rem !important; } .p-3 { padding: 1rem !important; } .m-1 { margin: 0.25rem !important; } .m-2 { margin: 0.5rem !important; } .m-3 { margin: 1rem !important; } /** Datei: themes/default/assets/scss/_base.scss **/ html { font-size: 14px; } body { font-family: Arial, sans-serif; margin: 0; background-color: getThemeColor( background ); color: getThemeColor( text ); container-name: body; container-type: size; height: 100vh; width: 100vw; } a { text-decoration: none; color: getThemeColor( primary ); &:hover { color: getHoverColor( primary ); } &.link { cursor: pointer; } } h1, h2, h3, h4, h5, h6 { margin: 0; font-weight: bold; } .highlight { background-color: #f0f8ff; /* Hellblau */ transition: background-color 0.3s ease; } .headline, .paragraph { .icon { margin-right: $gap-small; } em { text-decoration: underline; font-style: normal; } } .paragraph { line-height: 1.48em; } /** Datei: themes/default/assets/scss/templates/_default.scss **/ .template { $parent: &; &__ { &wrapper { display: grid; grid-template-rows: $header-height 1fr; // Navbar oben grid-template-columns: $sidebar-width 1fr; // Sidebar links grid-template-areas: "sidebar header" "sidebar main"; height: 100vh; width: 100vw; } &header { grid-area: header; height: $header-height; background-color: getThemeColor( content ); border-bottom: 1px solid getThemeColor( border ); display: flex; align-items: center; padding: 0 1rem; } &sidebar { grid-area: sidebar; width: $sidebar-width; background-color: getThemeColor( content ); border-right: 1px solid getThemeColor( border ); padding: $gap-default; } &logo { margin: $gap-wide; max-height: #{$gap-wide * 1.5}; object-fit: contain; object-position: left; } &aside { grid-area: aside; padding: 1rem; } &content { grid-area: main; padding: $gap-wide; overflow-y: auto; } &headline { } &inner { display: flex; padding: 1.5rem; flex-direction: column; gap: $gap-default; .paragraph { margin: 0; } } } &-- { @import 'login'; } } /** Datei: themes/default/assets/scss/templates/_login.scss **/ &login { gap: 0; grid-template-rows: 1fr; grid-template-columns: 1fr 1fr; grid-template-areas: 'main aside'; @container ( orientation: portrait ) { grid-template-rows: 1fr 1fr; grid-template-columns: 1fr; grid-template-areas: 'main' 'aside'; } #{$parent} { &__ { &content { justify-content: center; align-items: center; display: flex; } &inner { min-width: 50%; background-color: getThemeColor( content ); border: 1px solid getThemeColor( border ); padding: $gap-wide; } &aside { background-color: getThemeColor( secondary ); border-left: 1px solid getThemeColor( secondary, 1, -15 ); display: grid; img { max-width : 50%; max-height: 100%; margin: auto } } } } } /** Datei: themes/default/assets/scss/_header.scss **/ #header { display: flex; justify-content: space-between; align-items: center; height: $header-height; padding: 0 1rem; .user-menu { display: flex; align-items: center; gap: 1rem; .user-name { font-weight: bold; } .dropdown { display: none; a { display: block; padding: 0.5rem; color: getThemeColor( secondary ); &:hover { color: getThemeColor( primary ); } } } } } /** Datei: themes/default/assets/scss/layouts/_menu.scss **/ .menu { list-style: none; padding: 0; margin: 0; &__ { &sub { $menu-sub: & !global; display: none; list-style: none; margin: 0; } &item, &category { position: relative; display: flex; cursor: pointer; &.has-children { display: flex; flex-direction: column; } } &link { $menu-link: & !global; display: flex; } &item { $menu-item: & !global; > #{$menu-sub} { padding-left: 16px; } &.has-children { > #{$menu-link}::after { content: "▼"; font-size: 12px; margin-left: auto; transition: transform 0.2s ease; position: absolute; right: 1rem; top: 1rem; } } &.is-expanded { #{$menu-link}::after { transform: rotate(180deg); } } &--active { font-weight: bold; } } &badge { margin-left: auto; aspect-ratio: 1; border-radius: 50%; background: #fff; color: #33abc9; display: flex; align-items: center; justify-content: center; height: 1.4rem; } &category { $menu-category: & !global; > #{$menu-sub} { display: block; } } &link, &label { text-decoration: none; color: inherit; display: flex; align-items: center; gap: 8px; flex-grow: 1; } &icon { $menu-icon: & !global; font-size: 16px; } } // Submenu öffnen, wenn Parent aktiv ist .is-expanded { > #{$menu-sub} { display: flex; } } } /** Datei: themes/default/assets/scss/layouts/_tabs.scss **/ /** * _tabs.scss * * Stile für das dynamische Tab-System im BEM-Format. * * @author Sparky * @copyright 2025 ARUNOX * @version 1.1.0 * @since 1.0.0 File is created * @since 1.1.0 Anpassung an BEM-Konventionen */ .tabs { display: flex; flex-direction: column; gap: $gap-wide; width: 100%; .headline, .paragraph { grid-column: 1/-1; } &__ { &list { display: flex; list-style: none; gap: $gap-tiny; padding: 0; margin: 0; border-bottom: 2px solid #{getCoreColor( gray )}; } &item { padding: 0.2em 0.6em; font-size: 1rem; gap: $gap-small; min-height: 2rem; border-radius: $border-radius; border: none; background: transparent; cursor: pointer; transition: background 0.2s ease; display: flex; align-items: center; user-select: none; &:hover { background: rgba(0, 0, 0, 0.05); } &--active { font-weight: bold; @include highlightBorder(); } &--action { margin-left: auto; // Action-Tabs immer rechts background: rgba(0, 0, 0, 0.05); border-radius: $border-radius; & + & { margin-left: 0; } } @include buttonColors(); } &content { padding: 15px; border: 1px solid #{getThemeColor( border )}; background: #fff; &__item { display: flex; flex-direction: column; gap: $gap-default; display: grid; grid-template-columns: repeat( 2, 1fr ); > * { margin-block: 0; } > .form__group { grid-column: 1/-1; } } } &icon { font-size: 16px; } } } /** Datei: themes/default/assets/scss/wrapper/_dialog.scss **/ // ===================================== // Dialog-Styles // ===================================== .dialog { width: 90%; max-width: 600px; background-color: var(--color-background, #fff); border: none; border-radius: 8px; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2); z-index: 1000; transition: opacity 300ms ease, transform 0.3s ease; opacity: 0; overflow: hidden; padding: 0; max-height: calc( 100vh - 6rem ); &::backdrop { } &.is- { &open { transform: scale(1); opacity: 1; } &closing { transform: scale(0.95); opacity: 0; } } &-- { &sm { max-width: 400px; } &md { max-width: 600px; // Standard } &lg { max-width: 800px; } &xl { max-width: 1200px; } &full { width: 100%; height: 100%; max-width: none; max-height: none; border-radius: 0; } &max { margin-top: 3rem; height: 100%; .scroll__viewport { height : 100vh; } } &equal { .scroll__viewport { height : var( --height ); } } &top { margin-top: 3rem; } } &__{ &wrapper { // max-height: 50vh; } &close { position: absolute; top: 0rem; right: 0rem; background: transparent; border: none; font-size: 1.25rem; cursor: pointer; color: var(--color-text, #666); transition: color 0.2s ease; outline: 0; padding: 0; line-height: 1em; &:hover { color: var(--color-danger, #d00); } } &header { flex-shrink: 0; display: flex; justify-content: space-between; align-items: center; padding: 0 0 1rem 0; border-bottom: 1px solid #eee; background: var(--color-background, #fff); position: sticky; top: 0; z-index: 2; } &content { flex-grow: 1; overflow-y: auto; padding: 0 1.5rem; margin: 0 -1.5rem; &:has(.tabs__content) { overflow: visible; padding: 0; margin: 0; .tabs__content { max-height: calc( 100vh - 6rem - var( --maxHeight ) - 1.5rem + 10px ); overflow-y: auto; border: 0; margin-inline: -1.5rem; padding-inline: 1.5rem; padding-bottom: 1.5rem; padding-block: 5px; margin-blok: -5px; } } } &backdrop { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.6); backdrop-filter: blur(3px); opacity: 0; transition: opacity 300ms ease-in-out; z-index: 999; } } } /** Datei: themes/default/assets/scss/wrapper/notification.scss **/ .notification { display: flex; align-items: center; gap: $gap-default; padding: $gap-default; border-radius: $border-radius; background-color: getCoreColor( gray, 0.95); color: getThemeColor( text ); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); position: relative; min-width: 280px; max-width: 350px; opacity: 1; transform: translateY(0); transition: opacity 0.4s ease, transform 0.4s ease; pointer-events: auto; background-color: var( --color-background ); border-color: var( --color-border ); color: var( --color-text ); &.is-closing { opacity: 0; transform: translateY(-20px); } &__ { &wrapper { position: fixed; top: $gap-default; right: $gap-default; display: flex; flex-direction: column; gap: $gap-small; z-index: 1050; pointer-events: none; } &icon { display: flex; align-items: center; font-family: $icon-font-family; font-size: 1.4rem; opacity: 0.8; } &message { flex: 1; font-size: 0.95rem; line-height: 1.4; } &close { background: transparent; border: none; font-size: 1.2rem; cursor: pointer; padding: 0; color: inherit; opacity: 0.7; transition: all 0.3s ease-in-out; &:hover { opacity: 1; } } } @each $name, $color in $theme-colors { &--#{$name} { background-color: getThemeColor($name, 0.9); color: #{getContrastColor( #{$color}, getCoreColor(black), getCoreColor(white) )}; border-left: 4px solid getThemeColor($name); .notification__close { color: inherit; &:hover { color: getThemeColor( $name, 1, -10 ); } } } } } /** Datei: themes/default/assets/scss/_badge.scss **/ /** * _badge.scss * * Stile für das Badge-Element im BEM-Style, angepasst an bestehende Variablen und Utilities. * * @author Sparky * @copyright 2025 ARUNOX * @version 1.1.0 * @since 1.0.0 File is created * @since 1.1.0 Anpassung an Theme-Variablen und Utility-Klassen */ .badge { display: inline-flex; align-items: center; padding: $gap-small $gap-default; border-radius: $border-radius; font-size: 12px; font-weight: bold; color: getThemeColor(white); &--primary { background-color: getThemeColor(primary); } &--success { background-color: getThemeColor(success); } &--danger { background-color: getThemeColor(danger); } &--rounded { border-radius: $border-radius * 2; } &__text { padding: 0 4px; } } /** Datei: themes/default/assets/scss/_navbar.scss **/ .template__navbar { &.menu { display: flex; flex-direction: row-reverse; gap: $gap-tiny; } .menu { &__sub { $menu-sub: & !global; display: none; flex-direction: column; gap: $gap-tiny; &:hover { display: flex; } } &__link, &__label { padding: 0.8rem 1rem; color: getThemeColor( secondary ); border-radius: $border-radius; font-weight: bold; cursor: pointer; } &__link { &--active { background-color: getThemeColor( secondary ); color: getCoreColor( white ); } &.behavior-default { &:hover { background-color: getHoverColor( secondary ); color: getCoreColor( white ); } } } &__label { border-bottom: 1px solid getThemeColor( border ); background-color: getColorTone( content, 400 ); color: getThemeColor( text ); } &__item { &:hover, &--active { color: getCoreColor( white ); } &.has-children { &::after { right: 1rem; top: 0.8rem; translate: 0 0.25em; color: inherit; pointer-events: none; } } } &__category { // margin-block: $gap-wide; // background-color: getCoreColor( header ); &:hover { .menu__sub { display: flex; } } } &__icon { font-size: 1.2rem; &:not( :only-child ) { margin-right: $gap-tiny; } } } } /** Datei: themes/default/assets/scss/styles.scss **/ /** * styles.scss * * Hauptstylesheet für das Projekt, lädt alle SCSS-Module. * * @author Sparky * @copyright 2025 ARUNOX * @version 1.0.1 * @since 1.0.0 File is created * @since 1.0.1 Aktualisiert: BEM-Button-Stile importiert */ * { &, &::before, &::after { box-sizing: border-box; } } @mixin transition( $property: all, $duration: 200ms, $timing-function: ease-in-out, $behavior: normal, $delay: 0 ) { transition-property: $property; transition-duration: $duration; transition-timing-function: $timing-function; transition-behavior: $behavior; transition-delay: $delay; } @mixin highlightBorder( $position: bottom ) { position : relative; &:before { content: ''; display: block; position : absolute; bottom: 0; right: 0; left: 0; top: 0; pointer-events: none; @if( $position == all or $position == bottom or $position == horizontal ) { border-bottom: 3px solid #{getThemeColor( primary )}; } @if( $position == all or $position == top or $position == horizontal ) { border-top: 3px solid #{getThemeColor( primary )}; } @if( $position == all or $position == left or $position == vertical ) { border-left: 3px solid #{getThemeColor( primary )}; } @if( $position == all or $position == right or $position == vertical ) { border-right: 3px solid #{getThemeColor( primary )}; } } } #main { grid-area: main; } #header { grid-area: header; } #sidebar { grid-area: sidebar; } @import 'variables'; @import 'utilities'; @import 'base'; @import 'templates/default'; @import 'tooltip'; @import '#{$restdir}/colors/styles.scss'; @import 'components/button'; @import 'components/breadcrumbs'; @import 'layouts/menu'; @import 'layouts/tabs'; @import '#{$restdir}/layout/form'; @import '#{$restdir}/layout/table'; @import 'wrapper/notification'; @import '#{$restdir}/wrapper/dialog'; @import 'sidebar'; @import 'header'; @import 'navbar'; @import 'badge'; /** Datei: themes/default/assets/js/default.js **/ /** Datei: themes/default/templates/index.php **/ ARUNOX Framework
/** Datei: themes/default/config.php **/ '1.0.0', 'dependencies' => ['user'], // Abhängigkeit zum User-Plugin ];