/** 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
];