Compare commits

..

No commits in common. "3193127809bff116f53810f7f186be85e0dc7559" and "721c0d004228ac194f7872aaea0b1b5aa3253cd1" have entirely different histories.

115 changed files with 2960 additions and 402 deletions

View file

@ -1,48 +0,0 @@
name: Release Build (Windows)
on:
push:
branches:
- "release/**"
jobs:
build-and-merge:
runs-on: windows-latest
steps:
- name: Checkout the release branch
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Extract version from branch name
id: extract
shell: bash
run: |
version="${GITHUB_REF##*/}"
echo "version=$version" >> $GITHUB_OUTPUT
- name: Set up Git
shell: bash
run: |
git config user.name "github-actions"
git config user.email "github-actions@github.com"
- name: Run build script
shell: cmd
run: .\build-scripts\windows-build.bat
- name: Commit and push build artifacts
shell: bash
run: |
git add -A
git commit -m "Automated release build for version: ${{ steps.extract.outputs.version }}" || echo "No changes to commit"
git push origin ${{ github.ref }}
- name: Fetch and force merge into main
shell: bash
run: |
git fetch origin main
git checkout main
git merge -X theirs ${{ github.ref }} -m "Merging release version ${{ steps.extract.outputs.version }} into main"
git push origin main

10
.gitignore vendored
View file

@ -2,19 +2,13 @@
config.js
devices/*
tmp
tmp/
log.txt
Macrame.exe
public/*
public
macros/*
!macros/TEST-*
panels/*
!panels/test_panel
builds
node_modules
ToDo.md

View file

@ -1,13 +0,0 @@
# <img src="favicon.ico" width="24" alt="Macrame icon" /> Macrame
*The current release isn't yet public.*
Turn Any Device into a button panel. Open-source, easy, and built to supercharge your workflow or gaming.
Macrame is released under the GPL V3 licence. More information can be found at: [Macrame License](https://macrame-app.github.io/license.html)
Macrame is small application that can be used to record keyboard macros.
The macros can be linked to button panels and the panels can be used by devices on the same network.
## Getting Started
Read the [official documentation](https://macrame-app.github.io/) about the Macrame app to get started.

View file

@ -36,7 +36,7 @@ func EnvGet(key string) string {
if !configFileExists() {
CreateConfigFile(configPath)
CheckUIDevDir()
CheckFeDevDir()
}
data, err := os.ReadFile(configPath)
@ -63,12 +63,12 @@ func configFileExists() bool {
return err == nil
}
func CheckUIDevDir() {
func CheckFeDevDir() {
log.Println("Checking FE dev directory...")
_, err := os.Stat("ui")
_, err := os.Stat("fe")
if err != nil {
log.Println("Error checking ui dev directory:", err)
log.Println("Error checking FE dev directory:", err)
return
}
@ -83,7 +83,7 @@ func copyConfigToFe() {
return
}
if err := os.WriteFile("ui/config.js", data, 0644); err != nil {
if err := os.WriteFile("fe/config.js", data, 0644); err != nil {
log.Println("Error writing config.js:", err)
}
}

View file

@ -1,52 +0,0 @@
@echo off
setlocal enabledelayedexpansion
REM Step 1: Build Macrame Go application for Windows
echo Building Macrame Go Application for Windows...
go build -ldflags "-H=windowsgui" -o Macrame.exe main.go
IF %ERRORLEVEL% NEQ 0 (
echo Go build failed!
exit /b %ERRORLEVEL%
) ELSE (
echo Go build was successful!
)
REM Step 2: Build Macrame Vue UI
echo Moving to ui directory and building Vue UI
cd ui
echo Running npm install...
call npm install
IF %ERRORLEVEL% NEQ 0 (
echo npm install failed!
exit /b %ERRORLEVEL%
)
echo Running npm run build...
call npm run build
IF %ERRORLEVEL% NEQ 0 (
echo npm run build failed!
exit /b %ERRORLEVEL%
)
cd ..
REM Step 3: Cleanup root directory of build files.
echo Cleaning up root directory...
echo Removing directories: app, ui, and build-scripts
rmdir /s /q app
rmdir /s /q ui
rmdir /s /q build-scripts
for %%F in (*) do (
set "file=%%~nxF"
if /I not "!file!"=="Macrame.exe" if /I not "!file!"=="favicon.ico" if /I not "!file!"=="README.md" (
echo Deleting !file!
del /f /q "%%F"
)
)
echo Build and cleanup complete.

35
build.sh Normal file
View file

@ -0,0 +1,35 @@
#!/bin/bash
# Set the name of the build directory
BUILD_DIR="Macrame_$(date +'%m%d%H%M%S')"
# Build the Go application
go build -ldflags "-H=windowsgui" -o Macrame.exe main.go
# Build the frontend
cd fe
npm run build
cd ../builds
# Create the new build directory
mkdir $BUILD_DIR
mkdir $BUILD_DIR/macros
mkdir $BUILD_DIR/panels
mkdir $BUILD_DIR/panels/test_panel
mkdir $BUILD_DIR/public
mkdir $BUILD_DIR/public/assets
# Move the generated files to the new build directory
cp ../Macrame.exe $BUILD_DIR/Macrame.exe
cp ../favicon.ico $BUILD_DIR/favicon.ico
find ../macros -type f ! -name 'ED-*' -exec cp --parents {} "$BUILD_DIR/macros/" \;
cp -r ../panels/test_panel/* $BUILD_DIR/panels/test_panel/
mv ../public/* $BUILD_DIR/public/
# cp ../install.bat $BUILD_DIR/install.bat
powershell -Command "Compress-Archive -Path $BUILD_DIR/* -DestinationPath $BUILD_DIR.zip -Force"
# Print the path to the new build directory
echo "Build directory: ../$BUILD_DIR"

View file

View file

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Before After
Before After

View file

@ -1,8 +1,7 @@
{
"name": "Macrame - UI",
"description": "Macrame UI - Macrame is a small application that can turn any device into a button panel for your pc.",
"version": "1.0.0",
"private": false,
"name": "fe",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite --host",

View file

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Before After
Before After

View file

@ -1,9 +0,0 @@
[
{ "code": "lalt", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "f4", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "lalt", "direction": "up", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "f4", "direction": "up", "type": "key" }
]

View file

@ -1,13 +0,0 @@
[
{ "code": "lctrl", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "lshift", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "w", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "lctrl", "direction": "up", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "lshift", "direction": "up", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "w", "direction": "up", "type": "key" }
]

View file

@ -1,9 +0,0 @@
[
{ "code": "lctrl", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "w", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "lctrl", "direction": "up", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "w", "direction": "up", "type": "key" }
]

View file

@ -1,9 +0,0 @@
[
{ "code": "lcmd", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "p", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "lcmd", "direction": "up", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "p", "direction": "up", "type": "key" }
]

View file

@ -1,9 +0,0 @@
[
{ "code": "lcmd", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "e", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "lcmd", "direction": "up", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "e", "direction": "up", "type": "key" }
]

View file

@ -1 +0,0 @@
[{"code":"f11","direction":"down","type":"key"},{"type":"delay","value":15},{"code":"f11","direction":"up","type":"key"}]

View file

@ -1,9 +0,0 @@
[
{ "code": "lalt", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "home", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "home", "direction": "up", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "lalt", "direction": "up", "type": "key" }
]

View file

@ -1,13 +0,0 @@
[
{ "code": "lcmd", "direction": "down", "type": "key" },
{ "type": "delay", "value": 50 },
{ "code": "lctrl", "direction": "down", "type": "key" },
{ "type": "delay", "value": 50 },
{ "code": "d", "direction": "down", "type": "key" },
{ "type": "delay", "value": 50 },
{ "code": "lcmd", "direction": "up", "type": "key" },
{ "type": "delay", "value": 50 },
{ "code": "lctrl", "direction": "up", "type": "key" },
{ "type": "delay", "value": 50 },
{ "code": "d", "direction": "up", "type": "key" }
]

View file

@ -1,9 +0,0 @@
[
{ "code": "lctrl", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "t", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "lctrl", "direction": "up", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "t", "direction": "up", "type": "key" }
]

View file

@ -1,9 +0,0 @@
[
{ "code": "lctrl", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "n", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "lctrl", "direction": "up", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "n", "direction": "up", "type": "key" }
]

View file

@ -1,9 +0,0 @@
[
{ "code": "lctrl", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "tab", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "lctrl", "direction": "up", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "tab", "direction": "up", "type": "key" }
]

View file

@ -1 +0,0 @@
[{"code":"audio_play|audio_pause","direction":"down","type":"key"},{"type":"delay","value":15},{"code":"audio_play|audio_pause","direction":"up","type":"key"}]

View file

@ -1,13 +0,0 @@
[
{ "code": "lctrl", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "lshift", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "tab", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "lctrl", "direction": "up", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "lshift", "direction": "up", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "tab", "direction": "up", "type": "key" }
]

View file

@ -1,9 +0,0 @@
[
{ "code": "lcmd", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "r", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "lcmd", "direction": "up", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "r", "direction": "up", "type": "key" }
]

View file

@ -1,9 +0,0 @@
[
{ "code": "lcmd", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "i", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "lcmd", "direction": "up", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "i", "direction": "up", "type": "key" }
]

View file

@ -1,13 +0,0 @@
[
{ "code": "lctrl", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "lshift", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "esc", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "esc", "direction": "up", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "lshift", "direction": "up", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "lctrl", "direction": "up", "type": "key" }
]

View file

@ -1,9 +0,0 @@
[
{ "code": "lcmd", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "tab", "direction": "down", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "lcmd", "direction": "up", "type": "key" },
{ "type": "delay", "value": 15 },
{ "code": "tab", "direction": "up", "type": "key" }
]

View file

@ -1 +0,0 @@
[{"type":"key","key":"Meta","code":"MetaLeft","location":1,"direction":"down","value":0},{"type":"delay","key":"","code":"","location":0,"direction":"","value":240},{"type":"key","key":"d","code":"KeyD","location":0,"direction":"down","value":0},{"type":"delay","key":"","code":"","location":0,"direction":"","value":10},{"type":"key","key":"d","code":"KeyD","location":0,"direction":"up","value":0},{"type":"delay","key":"","code":"","location":0,"direction":"","value":10},{"type":"key","key":"Meta","code":"MetaLeft","location":1,"direction":"up","value":0}]

View file

@ -0,0 +1,913 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<!-- <meta name="viewport" content="width=device-width, initial-scale=1.0" /> -->
<title>Document</title>
<link rel="stylesheet" href="./output.css" />
</head>
<body id="panel-html__body" class="relative m-0">
<div
class="absolute inset-0 bg-slate-950 size-full grid grid-cols-[1fr_2fr_1fr] gap-2 p-2"
>
<div class="group-left">
<div id="menu-spacer" class="size-16"></div>
<div id="maps" class="ed-panel pnl__blue">
<h3>Maps</h3>
<div class="grid-cols-2 ed-button-group__horizontal">
<div
class="ed-button btn__yellow btn__vertical"
id="System__map"
mcrm__button
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<g style="fill: currentColor">
<circle cx="21.6" cy="17.1" r="0.9" />
<circle cx="21.6" cy="14.6" r="0.9" />
<circle cx="21.6" cy="12" r="0.9" />
<circle cx="15.4" cy="12" r="0.9" />
<circle cx="15.4" cy="7.9" r="1.9" />
<circle cx="21.6" cy="7.9" r="1.9" />
<circle cx="5.9" cy="7.6" r="5.4" />
<circle cx="5.9" cy="19.2" r="2.6" />
</g>
</svg>
System
</div>
<div
class="ed-button btn__orange btn__vertical"
id="Galaxy__map"
mcrm__button
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
style="fill: currentColor"
d="M22.1,8.9c-0.3,0-0.6,0.1-0.9,0.3L17,4.9c0.2-0.4,0.3-0.8,0.3-1.3c0-1.6-1.3-2.8-2.8-2.8S11.7,2,11.7,3.6
c0,0.8,0.4,1.6,0.9,2.1l-5.5,7.9c-0.5-0.2-1.1-0.3-1.7-0.3c-2.7,0-5,2.2-5,5s2.2,5,5,5s5-2.2,5-5c0-1.6-0.7-3-1.9-3.9l4.8-8.2
c0.3,0.2,0.7,0.2,1.1,0.2c0.6,0,1.1-0.2,1.5-0.5l4.7,3.8c-0.1,0.2-0.1,0.4-0.1,0.6c0,0.8,0.6,1.4,1.4,1.4s1.4-0.6,1.4-1.4
C23.5,9.6,22.9,8.9,22.1,8.9z"
/>
</svg>
Galaxy
</div>
</div>
</div>
<div id="fsd" class="ed-panel pnl__yellow">
<h3>Frame Shift Drive</h3>
<div
id="FSD__toggle"
class="ed-button btn__blue !rounded-b-none"
mcrm__button
>
Toggle FSD
</div>
<div class="grid-cols-2 ed-button-group__horizontal">
<div
id="Super__Cruise"
class="!rounded-tl-none ed-button btn__yellow"
mcrm__button
>
Super Cruise
</div>
<div
id="Hyper__Space"
class="!rounded-tr-none ed-button btn__orange"
mcrm__button
>
Hyper Space
</div>
</div>
</div>
<div class="grid grid-cols-2 gap-2">
<div
id="mode-switch"
class="grid gap-2 justify-items-center ed-panel pnl__white"
>
<h4>Mode</h4>
<span>Analysis</span>
<div
id="Mode__toggle"
class="ed-toggle toggle__vertical"
inactive-wrapper="border-sky-600 bg-sky-400/30"
inactive-indicator="bg-sky-400"
active-wrapper="border-red-600 bg-red-400/30"
active-indicator="bg-red-400"
mcrm__button
toggle__button
>
<div class="toggle__wrapper">
<div class="toggle__indicator"></div>
</div>
</div>
<span>Combat</span>
</div>
<div
id="mode-switch"
class="grid gap-2 justify-items-center ed-panel pnl__red"
>
<h4>Hardpoints</h4>
<span>Retract</span>
<div
id="Hardpoints__toggle"
class="ed-toggle toggle__vertical"
inactive-wrapper="border-sky-600 bg-sky-400/30"
inactive-indicator="bg-sky-400"
active-wrapper="border-red-600 bg-red-400/30"
active-indicator="bg-red-400"
mcrm__button
toggle__button
>
<div class="toggle__wrapper">
<div class="toggle__indicator"></div>
</div>
</div>
<span>Deploy</span>
</div>
</div>
</div>
<div class="group-middle">
<div id="ship-panels" class="ed-panel pnl__blue">
<h3>Panels</h3>
<div class="grid-cols-4 ed-button-group__horizontal">
<div
class="ed-button btn__orange"
id="External__panel"
mcrm__button
>
External
</div>
<div class="ed-button btn__yellow" id="Comms__panel" mcrm__button>
Comms
</div>
<div class="ed-button btn__yellow" id="Roles__panel" mcrm__button>
Roles
</div>
<div
class="ed-button btn__orange"
id="Internal__panel"
mcrm__button
>
Internal
</div>
</div>
</div>
<div class="grid grid-cols-[3fr_1fr_1fr] gap-2">
<div class="ed-panel pnl__blue">
<h3>Scanner</h3>
<div class="grid-cols-2 ed-button-group__horizontal">
<div
id="Scanner__FSS"
class="ed-button btn__blue btn__filled"
mcrm__button
>
FSS
</div>
<div
id="Scanner__DiscScan"
class="ed-button btn__blue"
mcrm__button
>
Discovery
</div>
</div>
</div>
<div
id="Route__NextSystem"
class="ed-button btn__yellow !px-2"
mcrm__button
>
<div>
<span class="text-base opacity-80">Route:</span>
<strong>Next System</strong>
</div>
</div>
<div
id="Speed_0percent"
class="ed-button btn__white !px-2"
mcrm__button
>
<div>
<span class="text-base opacity-80">Speed:</span>
<strong>0%</strong>
</div>
</div>
</div>
<div class="ed-panel pnl__red">
<h3>Fighters</h3>
<div class="grid grid-cols-[2fr_1fr] gap-2">
<div class="grid gap-2">
<div class="grid-cols-2 ed-button-group__horizontal">
<div
class="!justify-start ed-button btn__red btn__filled btn__vertical"
id="Fighter_attack"
mcrm__button
>
<svg
xmlns="http://www.w3.org/2000/svg"
style="fill: currentColor"
viewBox="0 0 24 24"
>
<path
d="M12,1.5C6.5,1.5,2,8,2,11.5s1.5,4.1,1.6,5.6c0.1,1,0.9,1.7,1.8,1.6c0.1,0-0.1-0.1,0.1-0.1v-2h1.2v1.9v2.1
c0,1,0.8,1.8,1.8,1.8H12h3.5c1,0,1.8-0.8,1.8-1.8v-2.1v-1.9h1.2v2c0.2,0-0.1,0.1,0.1,0.1c0.9,0.1,1.7-0.6,1.8-1.6
c0.2-1.5,1.6-2.1,1.6-5.6S17.5,1.5,12,1.5z M10.4,11.5c-0.6,1.4-2.3,2-3.7,1.4s-2-2.3-1.4-3.7C6,7.9,7.7,9.3,9.1,10
S11,10.2,10.4,11.5z M13,15.6c-0.3,0-0.7-0.3-0.8-0.6c-0.1-0.3-0.3-0.3-0.4,0c-0.1,0.3-0.5,0.6-0.8,0.6s-0.3-0.9,0.1-1.9l0.3-0.8
c0.4-1,0.9-1,1.3,0l0.3,0.8C13.3,14.7,13.3,15.6,13,15.6z M17.3,12.9c-1.4,0.6-3,0-3.7-1.4c-0.6-1.4-0.1-1,1.3-1.6s3.1-2.1,3.7-0.7
C19.3,10.7,18.7,12.3,17.3,12.9z"
/>
</svg>
Attack
</div>
<div
class="!justify-start text-red-400 ed-button btn__red btn__vertical"
id="Fighter__engage"
mcrm__button
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
style="fill: currentColor"
>
<path
d="M14,4.3c2.8,0.7,5,2.9,5.7,5.7h2.1C21,6.1,17.9,3,14,2.2V4.3z"
/>
<path
d="M4.3,10C5,7.2,7.2,5,10,4.3V2.2C6.1,3,3,6.1,2.2,10H4.3z"
/>
<path
d="M10,19.7C7.2,19,5,16.8,4.3,14H2.2c0.8,3.9,3.9,7,7.8,7.8V19.7z"
/>
<path
d="M19.7,14c-0.7,2.8-2.9,5-5.7,5.7v2.1c3.9-0.8,7-3.9,7.8-7.8H19.7z"
/>
<polygon points="13,1 11,1 11,6.5 13,6.5 13,1 " />
<polygon points="6.5,11 1,11 1,13 6.5,13 6.5,11 " />
<polygon points="23,11 17.5,11 17.5,13 23,13 23,11 " />
<polygon points="13,17.5 11,17.5 11,23 13,23 13,17.5 " />
</svg>
Engage
</div>
</div>
<div class="grid-cols-2 ed-button-group__horizontal">
<div
class="!justify-start ed-button btn__orange btn__filled btn__vertical"
id="Fighter_defend"
mcrm__button
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
style="fill: currentColor"
>
<path
style="opacity: 0.8"
d="M12,2.4l0.3,0.1l7.2,2.6l0.6,0.2l0,0.7c0,0.5,0.6,12.6-7.9,15.4L12,21.6l-0.3-0.1C3.2,18.6,3.8,6.6,3.8,6.1l0-0.7l0.6-0.2
l7.2-2.6L12,2.4 M12,0.3l-1,0.4L3.8,3.3L1.9,4l-0.1,2c0,0.6-0.7,14.1,9.2,17.4l0.9,0.3l0.9-0.3c9.9-3.3,9.3-16.8,9.2-17.4l-0.1-2
l-1.9-0.7L13,0.7L12,0.3L12,0.3z"
/>
<path
d="M19.2,6.1L12,3.5L4.8,6.1c0,0-0.7,11.8,7.2,14.4C19.8,17.9,19.2,6.1,19.2,6.1z"
/>
</svg>
Defend
</div>
<div
class="!justify-start text-red-400 ed-button btn__orange btn__vertical"
id="Fighter__hold"
mcrm__button
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
style="fill: currentColor"
>
<polygon
style="opacity: 0.8"
points="13,1 11,1 11,6.5 13,6.5 13,1 "
/>
<polygon
style="opacity: 0.8"
points="6.5,11 1,11 1,13 6.5,13 6.5,11 "
/>
<polygon
style="opacity: 0.8"
points="23,11 17.5,11 17.5,13 23,13 23,11 "
/>
<polygon
style="opacity: 0.8"
points="13,17.5 11,17.5 11,23 13,23 13,17.5 "
/>
<path
style="opacity: 0.8"
d="M6.1,20c1.1,0.8,2.5,1.5,3.9,1.8v-2.1c-0.9-0.2-1.7-0.6-2.5-1.1L6.1,20z"
/>
<path
style="opacity: 0.8"
d="M4.3,14H2.2c0.3,1.4,0.9,2.8,1.8,3.9l1.5-1.5C4.9,15.7,4.5,14.9,4.3,14z"
/>
<path
style="opacity: 0.8"
d="M7.5,5.4C8.3,4.9,9.1,4.5,10,4.3V2.2C8.6,2.5,7.2,3.1,6.1,4L7.5,5.4z"
/>
<path
style="opacity: 0.8"
d="M5.4,7.5L4,6.1C3.1,7.2,2.5,8.6,2.2,10h2.1C4.5,9.1,4.9,8.3,5.4,7.5z"
/>
<path
style="opacity: 0.8"
d="M18.6,7.5c0.5,0.7,0.9,1.6,1.1,2.5h2.1c-0.3-1.4-0.9-2.8-1.8-3.9L18.6,7.5z"
/>
<path
style="opacity: 0.8"
d="M17.9,4c-1.1-0.8-2.5-1.5-3.9-1.8v2.1c0.9,0.2,1.7,0.6,2.5,1.1L17.9,4z"
/>
<path
style="opacity: 0.8"
d="M18.6,16.5l1.5,1.5c0.8-1.1,1.5-2.5,1.8-3.9h-2.1C19.5,14.9,19.1,15.7,18.6,16.5z"
/>
<path
style="opacity: 0.8"
d="M16.5,18.6c-0.7,0.5-1.6,0.9-2.5,1.1v2.1c1.4-0.3,2.8-0.9,3.9-1.8L16.5,18.6z"
/>
<polygon
points="21.2,19.8 13.4,12 21.2,4.2 19.8,2.8 12,10.6 4.2,2.8 2.8,4.2 10.6,12 2.8,19.8 4.2,21.2 12,13.4 19.8,21.2 "
/>
</svg>
Hold
</div>
</div>
<div class="grid-cols-2 ed-button-group__horizontal">
<div
class="!justify-start ed-button btn__blue btn__filled btn__vertical"
id="Fighter_follow"
mcrm__button
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
style="fill: currentColor"
>
<polygon
points="11,13 2.5,13 4.5,15 0.3,19.2 4.8,23.7 9,19.5 11,21.5 "
/>
<polygon
points="11,11 11,2.5 9,4.5 4.8,0.3 0.3,4.8 4.5,9 2.5,11 "
/>
<polygon
points="13,11 21.5,11 19.5,9 23.7,4.8 19.2,0.3 15,4.5 13,2.5 "
/>
<polygon
points="13,13 13,21.5 15,19.5 19.2,23.7 23.7,19.2 19.5,15 21.5,13 "
/>
</svg>
Follow
</div>
<div
class="!justify-start text-red-400 ed-button btn__blue btn__vertical"
id="Fighter__recall"
mcrm__button
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
style="fill: currentColor"
>
<path
d="M12,1C5.9,1,1,5.9,1,12s4.9,11,11,11s11-4.9,11-11S18.1,1,12,1z M12,20c-4.4,0-8-3.6-8-8c0-3,1.6-5.5,4-6.9V10H5l7,7l7-7
h-3V5.1c2.4,1.4,4,4,4,6.9C20,16.4,16.4,20,12,20z"
/>
</svg>
Recall
</div>
</div>
</div>
<div>
<div class="h-full grid-rows-3 ed-button-group__vertical">
<div
id="Fighter__wingman1"
class="ed-button btn__yellow btn__vertical"
mcrm__button
>
<span class="text-base opacity-80">Wingman</span>
<strong>#1</strong>
</div>
<div
id="Fighter__wingman2"
class="ed-button btn__yellow btn__vertical"
mcrm__button
>
<span class="text-base opacity-80">Wingman</span>
<strong>#2</strong>
</div>
<div
id="Fighter__wingman3"
class="ed-button btn__yellow btn__vertical"
mcrm__button
>
<span class="text-base opacity-80">Wingman</span>
<strong>#3</strong>
</div>
</div>
</div>
</div>
</div>
<div class="ed-panel pnl__red">
<h3>Counter Measures</h3>
<div class="grid-cols-4 ed-button-group__horizontal">
<div id="CM__Heatsink" class="ed-button btn__red" mcrm__button>
Heatsink
</div>
<div
id="CM__Chaff"
class="ed-button btn__red btn__filled"
mcrm__button
>
Chaff
</div>
<div
id="CM__ECM"
class="ed-button btn__red btn__filled"
mcrm__button
>
ECM
</div>
<div id="CM__Shieldcell" class="ed-button btn__red" mcrm__button>
Shieldcell
</div>
</div>
</div>
</div>
<div class="group-right">
<div class="ed-panel pnl__white">
<h3>Flight Assist</h3>
<div class="grid grid-cols-2 gap-2">
<div class="grid gap-2 justify-items-center">
<div
id="FlightAssist__toggle"
class="ed-toggle toggle__horizontal"
inactive-wrapper="border-red-600 bg-red-400/30"
inactive-indicator="bg-red-400"
active-wrapper="border-lime-600 bg-lime-400/30"
active-indicator="bg-lime-400"
mcrm__button
toggle__button
active="true"
>
<div class="toggle__wrapper">
<div class="toggle__indicator"></div>
</div>
</div>
<div class="flex justify-between w-full">
<span>Off</span>
<span>On</span>
</div>
</div>
<div
id="Rotational__Correction"
class="!px-2 ed-button btn__blue w-fit"
mcrm__button
>
<span class="text-xs">Rotational Correction</span>
</div>
</div>
</div>
<div
class="grid grid-cols-2 divide-x ed-panel pnl__white divider-white !p-0"
>
<div id="light-switch" class="grid gap-2 p-2 justify-items-center">
<h4>Lights</h4>
<div
id="Lights__toggle"
class="ed-toggle toggle__horizontal"
inactive-wrapper="border-white bg-white/30"
inactive-indicator="bg-white"
active-wrapper="border-sky-600 bg-sky-400/30"
active-indicator="bg-sky-400"
mcrm__button
toggle__button
>
<div class="toggle__wrapper">
<div class="toggle__indicator"></div>
</div>
</div>
<div class="flex justify-between w-full">
<span>Off</span>
<span>On</span>
</div>
</div>
<div id="light-switch" class="grid gap-2 p-2 justify-items-center">
<h4>Night Vis.</h4>
<div
id="NightVis__toggle"
class="ed-toggle toggle__horizontal"
inactive-wrapper="border-white bg-white/30"
inactive-indicator="bg-white"
active-wrapper="border-lime-600 bg-lime-400/30"
active-indicator="bg-lime-400"
mcrm__button
toggle__button
>
<div class="toggle__wrapper">
<div class="toggle__indicator"></div>
</div>
</div>
<div class="flex justify-between w-full">
<span>Off</span>
<span>On</span>
</div>
</div>
</div>
<div class="grid grid-cols-2 gap-2">
<div class="grid gap-2 text-center ed-panel pnl__orange">
<h4>Silent Running</h4>
<div
id="SilentRunning__toggle"
class="ed-toggle toggle__horizontal"
inactive-wrapper="border-white bg-white/30"
inactive-indicator="bg-white"
active-wrapper="border-red-600 bg-red-400/30"
active-indicator="bg-red-400"
mcrm__button
toggle__button
>
<div class="toggle__wrapper">
<div class="toggle__indicator"></div>
</div>
</div>
<div class="flex justify-between w-full">
<span>Off</span>
<span>On</span>
</div>
</div>
<div class="flex items-center justify-between">
<div
id="Jettison__Cargo"
class="flex flex-col items-center justify-center gap-2 text-center text-white border-red-500 rounded-full border-3 bg-red-500/80 aspect-square"
mcrm__button
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path
d="M12 1.67c.955 0 1.845 .467 2.39 1.247l.105 .16l8.114 13.548a2.914 2.914 0 0 1 -2.307 4.363l-.195 .008h-16.225a2.914 2.914 0 0 1 -2.582 -4.2l.099 -.185l8.11 -13.538a2.914 2.914 0 0 1 2.491 -1.403zm.01 13.33l-.127 .007a1 1 0 0 0 0 1.986l.117 .007l.127 -.007a1 1 0 0 0 0 -1.986l-.117 -.007zm-.01 -7a1 1 0 0 0 -.993 .883l-.007 .117v4l.007 .117a1 1 0 0 0 1.986 0l.007 -.117v-4l-.007 -.117a1 1 0 0 0 -.993 -.883z"
/>
</svg>
<span> JETTISON CARGO </span>
</div>
</div>
</div>
<div class="grid grid-cols-2 gap-2">
<div
class="ed-button btn__blue btn__vertical"
dialog-trigger="#camera-dialog"
mcrm__dialog-trigger
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
style="fill: currentColor"
>
<path
d="M22.6,9.1c-0.1-0.5-0.3-1-0.5-1.6c-1.5,0-5.3,0-6.8,0c2.3,2.3,5.1,5.1,7.3,7.3C23.1,13.1,23.1,10.9,22.6,9.1z"
/>
<path
d="M6.6,12.8c0-3.2,0-7.2,0-10.4C4.4,3.7,2.6,5.7,1.7,8C2.3,8.6,6.6,12.8,6.6,12.8z"
/>
<path
d="M12.8,17.4c-3.2,0-7.2,0-10.4,0c1.2,2.2,3.2,3.9,5.6,4.8C8.6,21.7,12.8,17.4,12.8,17.4z"
/>
<path
d="M17.4,11.2c0,3.2,0,7.2,0,10.4c2.2-1.2,3.9-3.2,4.8-5.6C21.7,15.4,17.4,11.2,17.4,11.2z"
/>
<path
d="M11.2,6.6c3.2,0,7.2,0,10.4,0c-1.2-2.2-3.2-3.9-5.6-4.8C15.4,2.3,11.2,6.6,11.2,6.6z"
/>
<path
d="M7.6,16.4h1.2c-2.3-2.3-5.1-5.1-7.3-7.3c-0.7,2.4-0.5,5.1,0.5,7.3C2.7,16.4,6.9,16.4,7.6,16.4z"
/>
<path
d="M14.3,17.4c-1.3,1.3-3.8,3.8-5.2,5.2c2.4,0.7,5.1,0.5,7.3-0.5c0-1.5,0-5.3,0-6.8C15.9,15.8,14.8,16.9,14.3,17.4z"
/>
<path
d="M14.9,1.4c-2.4-0.7-5.1-0.5-7.3,0.5c0,1.5,0,5.3,0,6.8C8.1,8.2,13.5,2.8,14.9,1.4z"
/>
</svg>
<span> CAMERA </span>
</div>
<dialog id="camera-dialog" mcrm__dialog>
<div
class="dialog__content ed-panel pnl__blue !w-fit !bg-sky-900 relative !p-4"
>
<div class="dialog__close">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="size-8"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M18 6l-12 12" />
<path d="M6 6l12 12" />
</svg>
</div>
<h4>Camera</h4>
<div class="grid grid-cols-[1fr_2fr] gap-2 mt-4">
<div
id="Camera__Suite"
class="ed-button btn__orange btn__filled btn__vertical !text-gray-800"
mcrm__button
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="icon icon-tabler icons-tabler-outline icon-tabler-gradienter"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path
d="M3.227 14c.917 4 4.497 7 8.773 7c4.277 0 7.858 -3 8.773 -7"
/>
<path
d="M20.78 10a9 9 0 0 0 -8.78 -7a8.985 8.985 0 0 0 -8.782 7"
/>
<path d="M12 12m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" />
</svg>
<span>Camera Suite</span>
</div>
<div class="grid-cols-2 ed-button-group__horizontal">
<div
id="Previous__Camera"
class="ed-button btn__yellow !text-gray-800 btn__filled !pt-8"
mcrm__button
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path
d="M20.341 4.247l-8 7a1 1 0 0 0 0 1.506l8 7c.647 .565 1.659 .106 1.659 -.753v-14c0 -.86 -1.012 -1.318 -1.659 -.753z"
/>
<path
d="M9.341 4.247l-8 7a1 1 0 0 0 0 1.506l8 7c.647 .565 1.659 .106 1.659 -.753v-14c0 -.86 -1.012 -1.318 -1.659 -.753z"
/>
</svg>
<div class="relative text-right w-28">
<span
class="absolute right-0 text-base opacity-90 bottom-full"
>
Previous
</span>
<strong>Camera</strong>
</div>
</div>
<div
id="Next__Camera"
class="!pt-8 ed-button btn__yellow"
mcrm__button
>
<div class="relative text-left w-28">
<span class="absolute text-base opacity-80 bottom-full">
Next
</span>
<strong>Camera</strong>
</div>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path
d="M2 5v14c0 .86 1.012 1.318 1.659 .753l8 -7a1 1 0 0 0 0 -1.506l-8 -7c-.647 -.565 -1.659 -.106 -1.659 .753z"
/>
<path
d="M13 5v14c0 .86 1.012 1.318 1.659 .753l8 -7a1 1 0 0 0 0 -1.506l-8 -7c-.647 -.565 -1.659 -.106 -1.659 .753z"
/>
</svg>
</div>
</div>
<div
id="Free__Camera"
class="ed-button btn__orange btn__vertical"
mcrm__button
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M18 9l3 3l-3 3" />
<path d="M15 12h6" />
<path d="M6 9l-3 3l3 3" />
<path d="M3 12h6" />
<path d="M9 18l3 3l3 -3" />
<path d="M12 15v6" />
<path d="M15 6l-3 -3l-3 3" />
<path d="M12 3v6" />
</svg>
<span>Free Camera</span>
</div>
<div class="grid-cols-2 ed-button-group__horizontal">
<div
id="Camera__Pos1"
class="ed-button btn__yellow !text-gray-800 btn__filled btn__vertical"
mcrm__button
>
<span class="text-base opacity-80">Position</span>
<strong>#1</strong>
</div>
<div
id="Camera__Pos2"
class="ed-button btn__yellow btn__vertical"
mcrm__button
>
<span class="text-base opacity-80">Position</span>
<strong>#2</strong>
</div>
</div>
</div>
</div>
</dialog>
</div>
<div class="flex items-end justify-end h-28">
<div id="clock">
<div class="hours-minutes"></div>
<sup class="seconds"></sup>
</div>
</div>
</div>
</div>
<script>
function onPanelLoaded() {
document
.querySelectorAll("#panel-html__body [toggle__button]")
.forEach((toggleButton) => {
if (toggleButton.getAttribute("active")) {
toggleClasses(toggleButton, true);
} else {
toggleClasses(toggleButton, false);
}
toggleButton.addEventListener("click", (e) => {
if (!toggleButton.getAttribute("active")) {
toggleButton.setAttribute("active", true);
toggleClasses(toggleButton, true);
} else {
toggleButton.removeAttribute("active");
toggleClasses(toggleButton, false);
}
});
});
function toggleClasses(toggleButton, active) {
const wrapper = toggleButton.querySelector(".toggle__wrapper");
const indicator = toggleButton.querySelector(".toggle__indicator");
const stateClasses = getStateClasses(toggleButton);
if (active) {
wrapper.classList.remove(...stateClasses.wrapper.inactive);
wrapper.classList.add(...stateClasses.wrapper.active);
indicator.classList.remove(...stateClasses.indicator.inactive);
indicator.classList.add(...stateClasses.indicator.active);
} else {
wrapper.classList.remove(...stateClasses.wrapper.active);
wrapper.classList.add(...stateClasses.wrapper.inactive);
indicator.classList.remove(...stateClasses.indicator.active);
indicator.classList.add(...stateClasses.indicator.inactive);
}
}
function getStateClasses(toggleButton) {
return {
wrapper: {
active: mapClasses(toggleButton.getAttribute("active-wrapper")),
inactive: mapClasses(
toggleButton.getAttribute("inactive-wrapper")
),
},
indicator: {
active: mapClasses(toggleButton.getAttribute("active-indicator")),
inactive: mapClasses(
toggleButton.getAttribute("inactive-indicator")
),
},
};
}
function mapClasses(classStr) {
return classStr.split(" ").map((c) => c.trim());
}
// document
// .querySelectorAll("[dialog-trigger]")
// .forEach((dialogTrigger) => {
// dialogTrigger.addEventListener("click", (e) => {
// document
// .querySelector(dialogTrigger.getAttribute("dialog-trigger"))
// .showModal();
// });
// });
// document
// .querySelectorAll("dialog, dialog .dialog__close")
// .forEach((dialogClose) => {
// const dialog = dialogClose.closest("dialog");
// dialogClose.addEventListener("click", (e) => {
// if (
// e.target.classList.contains("dialog__close") ||
// e.target.closest(".dialog__close") ||
// e.target.tagName == "DIALOG"
// ) {
// dialog.close();
// }
// });
// });
setInterval(() => {
const clockEl = document.querySelector("#clock");
const hoursMins = clockEl.querySelector(".hours-minutes");
const seconds = clockEl.querySelector(".seconds");
const now = new Date();
const hours = now.getHours();
const minutes = now.getMinutes();
const secondsStr = now.getSeconds();
hoursMins.innerHTML = formatTimeToHTML(
`${hours.toString().padStart(2, "0")}:${minutes
.toString()
.padStart(2, "0")}`
);
seconds.innerHTML = formatTimeToHTML(
secondsStr.toString().padStart(2, "0")
);
}, 1000);
function formatTimeToHTML(timeStr) {
let htmlStr = "";
timeStr.split("").forEach((char) => {
if (char === ":") htmlStr += "<i>:</i>";
else htmlStr += "<span>" + char + "</span>";
});
return htmlStr;
}
}
</script>
<script no-compile>
onPanelLoaded();
</script>
</body>
</html>

View file

@ -0,0 +1,253 @@
@import url(https://fonts.bunny.net/css?family=orbitron:400,600,800);
@layer theme, utilities;
@import "tailwindcss/theme.css" layer(theme);
@import "tailwindcss/utilities.css" layer(utilities);
@layer theme {
/* :root {
} */
}
html,
body,
#panel-html__body {
@apply relative;
}
#panel-html__body {
--font-sans: "Orbitron", sans-serif;
@apply font-sans text-sm font-light tracking-wide bg-gray-900 text-slate-50 size-full;
* {
box-sizing: border-box;
}
}
.group-left,
.group-middle,
.group-right {
@apply grid gap-2 h-fit;
}
.ed-panel {
@apply w-full p-2 border h-fit rounded-b-xl;
h3,
h4 {
@apply m-0 mb-1 font-extralight;
}
h3 {
@apply text-base;
}
h4 {
@apply text-sm;
}
&.pnl__blue {
@apply border-sky-300 bg-sky-500/30;
h3,
h4 {
@apply text-sky-100;
text-shadow: 0 0 0.2em var(--color-sky-300);
}
}
&.pnl__yellow {
@apply border-amber-300 bg-amber-500/30;
h3,
h4 {
@apply text-amber-100;
text-shadow: 0 0 0.2em var(--color-amber-300);
}
}
&.pnl__orange {
@apply border-orange-300 bg-orange-500/30;
h3,
h4 {
@apply text-orange-100;
text-shadow: 0 0 0.2em var(--color-orange-300);
}
}
&.pnl__red {
@apply border-rose-300 bg-rose-500/30;
h3,
h4 {
@apply text-rose-100;
text-shadow: 0 0 0.2em var(--color-rose-400);
}
}
&.pnl__white {
@apply border-white bg-white/20;
h3,
h4 {
@apply text-white;
text-shadow: 0 0 0.2em var(--color-white);
}
}
}
.ed-button {
@apply flex items-center justify-center px-4 py-2 text-base text-center rounded-lg border-3;
svg {
@apply block !size-5;
}
&.btn__vertical {
@apply flex-col;
}
&.btn__filled {
@apply text-gray-900;
}
&.btn__orange {
@apply text-orange-100 border-orange-400 bg-orange-500/50;
&.btn__filled {
@apply bg-orange-400;
}
}
&.btn__yellow {
@apply text-orange-100 border-amber-400 bg-amber-500/50;
&.btn__filled {
@apply bg-amber-400;
}
}
&.btn__blue {
@apply border-sky-400 bg-sky-500/50 text-sky-100;
&.btn__filled {
@apply bg-sky-500;
}
}
&.btn__red {
@apply border-rose-500 bg-rose-600/50 text-rose-100;
&.btn__filled {
@apply bg-rose-600;
}
}
&.btn__white {
@apply border-white bg-white/30;
&.btn__filled {
@apply bg-white;
}
}
}
.ed-button-group__horizontal {
@apply grid divide-x;
.ed-button {
@apply rounded-none;
&:first-child {
@apply rounded-l-lg;
}
&:last-child {
@apply rounded-r-lg;
}
}
}
.ed-button-group__vertical {
@apply grid divide-y;
.ed-button {
@apply rounded-none;
&:first-child {
@apply rounded-t-lg;
}
&:last-child {
@apply rounded-b-lg;
}
}
}
.ed-toggle {
.toggle__wrapper {
@apply relative p-1.5 border-2 rounded-full size-full;
}
.toggle__indicator {
@apply absolute transition rounded-full aspect-square;
}
&.toggle__horizontal {
@apply w-20 h-12;
.toggle__indicator {
@apply left-1.5 translate-x-0 h-[calc(100%-.75rem)];
}
&[active] .toggle__indicator {
@apply translate-x-full;
}
}
&.toggle__vertical {
@apply w-12 h-20;
.toggle__indicator {
@apply top-1.5 translate-y-0 w-[calc(100%-.75rem)];
}
&[active] .toggle__indicator {
@apply translate-y-full;
}
}
}
dialog[open] {
@apply absolute -translate-x-1/2 -translate-y-1/2 bg-transparent border-0 outline-0 top-1/2 left-1/2;
@apply backdrop:absolute backdrop:bg-black/50;
.dialog__close {
@apply absolute text-white top-3 right-3;
}
}
#clock {
@apply relative flex pr-16 text-3xl w-fit;
i {
@apply pl-1 not-italic;
}
.hours-minutes,
.seconds {
@apply flex gap-1;
}
span {
@apply inline-block w-[.75em] text-center;
}
sup {
@apply absolute right-0 w-16 pl-2 text-lg text-left opacity-80;
}
}

View file

@ -0,0 +1,688 @@
/*! tailwindcss v4.1.4 | MIT License | https://tailwindcss.com */
@import url(https://fonts.bunny.net/css?family=orbitron:400,600,800);
@layer properties;
@layer theme, utilities;
@layer theme {
:root, :host {
--font-sans: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
'Noto Color Emoji';
--color-red-400: oklch(70.4% 0.191 22.216);
--color-red-500: oklch(63.7% 0.237 25.331);
--color-red-600: oklch(57.7% 0.245 27.325);
--color-orange-100: oklch(95.4% 0.038 75.164);
--color-orange-300: oklch(83.7% 0.128 66.29);
--color-orange-400: oklch(75% 0.183 55.934);
--color-orange-500: oklch(70.5% 0.213 47.604);
--color-amber-100: oklch(96.2% 0.059 95.617);
--color-amber-300: oklch(87.9% 0.169 91.605);
--color-amber-400: oklch(82.8% 0.189 84.429);
--color-amber-500: oklch(76.9% 0.188 70.08);
--color-lime-400: oklch(84.1% 0.238 128.85);
--color-lime-600: oklch(64.8% 0.2 131.684);
--color-sky-100: oklch(95.1% 0.026 236.824);
--color-sky-300: oklch(82.8% 0.111 230.318);
--color-sky-400: oklch(74.6% 0.16 232.661);
--color-sky-500: oklch(68.5% 0.169 237.323);
--color-sky-600: oklch(58.8% 0.158 241.966);
--color-sky-900: oklch(39.1% 0.09 240.876);
--color-rose-100: oklch(94.1% 0.03 12.58);
--color-rose-300: oklch(81% 0.117 11.638);
--color-rose-400: oklch(71.2% 0.194 13.428);
--color-rose-500: oklch(64.5% 0.246 16.439);
--color-rose-600: oklch(58.6% 0.253 17.585);
--color-slate-50: oklch(98.4% 0.003 247.858);
--color-slate-950: oklch(12.9% 0.042 264.695);
--color-gray-800: oklch(27.8% 0.033 256.848);
--color-gray-900: oklch(21% 0.034 264.665);
--color-black: #000;
--color-white: #fff;
--spacing: 0.25rem;
--text-xs: 0.75rem;
--text-xs--line-height: calc(1 / 0.75);
--text-sm: 0.875rem;
--text-sm--line-height: calc(1.25 / 0.875);
--text-base: 1rem;
--text-base--line-height: calc(1.5 / 1);
--text-lg: 1.125rem;
--text-lg--line-height: calc(1.75 / 1.125);
--text-3xl: 1.875rem;
--text-3xl--line-height: calc(2.25 / 1.875);
--font-weight-extralight: 200;
--font-weight-light: 300;
--tracking-wide: 0.025em;
--radius-lg: 0.5rem;
--radius-xl: 0.75rem;
--default-transition-duration: 150ms;
--default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
}
@layer utilities {
.absolute {
position: absolute;
}
.relative {
position: relative;
}
.inset-0 {
inset: calc(var(--spacing) * 0);
}
.right-0 {
right: calc(var(--spacing) * 0);
}
.bottom-full {
bottom: 100%;
}
.m-0 {
margin: calc(var(--spacing) * 0);
}
.mt-4 {
margin-top: calc(var(--spacing) * 4);
}
.flex {
display: flex;
}
.grid {
display: grid;
}
.aspect-square {
aspect-ratio: 1 / 1;
}
.size-8 {
width: calc(var(--spacing) * 8);
height: calc(var(--spacing) * 8);
}
.size-16 {
width: calc(var(--spacing) * 16);
height: calc(var(--spacing) * 16);
}
.size-full {
width: 100%;
height: 100%;
}
.h-28 {
height: calc(var(--spacing) * 28);
}
.h-full {
height: 100%;
}
.\!w-fit {
width: fit-content !important;
}
.w-28 {
width: calc(var(--spacing) * 28);
}
.w-fit {
width: fit-content;
}
.w-full {
width: 100%;
}
.grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.grid-cols-4 {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.grid-cols-\[1fr_2fr\] {
grid-template-columns: 1fr 2fr;
}
.grid-cols-\[1fr_2fr_1fr\] {
grid-template-columns: 1fr 2fr 1fr;
}
.grid-cols-\[2fr_1fr\] {
grid-template-columns: 2fr 1fr;
}
.grid-cols-\[3fr_1fr_1fr\] {
grid-template-columns: 3fr 1fr 1fr;
}
.grid-rows-3 {
grid-template-rows: repeat(3, minmax(0, 1fr));
}
.flex-col {
flex-direction: column;
}
.items-center {
align-items: center;
}
.items-end {
align-items: flex-end;
}
.\!justify-start {
justify-content: flex-start !important;
}
.justify-between {
justify-content: space-between;
}
.justify-center {
justify-content: center;
}
.justify-end {
justify-content: flex-end;
}
.justify-items-center {
justify-items: center;
}
.gap-2 {
gap: calc(var(--spacing) * 2);
}
.divide-x {
:where(& > :not(:last-child)) {
--tw-divide-x-reverse: 0;
border-inline-style: var(--tw-border-style);
border-inline-start-width: calc(1px * var(--tw-divide-x-reverse));
border-inline-end-width: calc(1px * calc(1 - var(--tw-divide-x-reverse)));
}
}
.rounded-full {
border-radius: calc(infinity * 1px);
}
.\!rounded-tl-none {
border-top-left-radius: 0 !important;
}
.\!rounded-tr-none {
border-top-right-radius: 0 !important;
}
.\!rounded-b-none {
border-bottom-right-radius: 0 !important;
border-bottom-left-radius: 0 !important;
}
.border-3 {
border-style: var(--tw-border-style);
border-width: 3px;
}
.border-lime-600 {
border-color: var(--color-lime-600);
}
.border-red-500 {
border-color: var(--color-red-500);
}
.border-red-600 {
border-color: var(--color-red-600);
}
.border-sky-600 {
border-color: var(--color-sky-600);
}
.border-white {
border-color: var(--color-white);
}
.\!bg-sky-900 {
background-color: var(--color-sky-900) !important;
}
.bg-lime-400 {
background-color: var(--color-lime-400);
}
.bg-lime-400\/30 {
background-color: color-mix(in srgb, oklch(84.1% 0.238 128.85) 30%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-lime-400) 30%, transparent);
}
}
.bg-red-400 {
background-color: var(--color-red-400);
}
.bg-red-400\/30 {
background-color: color-mix(in srgb, oklch(70.4% 0.191 22.216) 30%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-red-400) 30%, transparent);
}
}
.bg-red-500\/80 {
background-color: color-mix(in srgb, oklch(63.7% 0.237 25.331) 80%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-red-500) 80%, transparent);
}
}
.bg-sky-400 {
background-color: var(--color-sky-400);
}
.bg-sky-400\/30 {
background-color: color-mix(in srgb, oklch(74.6% 0.16 232.661) 30%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-sky-400) 30%, transparent);
}
}
.bg-slate-950 {
background-color: var(--color-slate-950);
}
.bg-white {
background-color: var(--color-white);
}
.bg-white\/30 {
background-color: color-mix(in srgb, #fff 30%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-white) 30%, transparent);
}
}
.\!p-0 {
padding: calc(var(--spacing) * 0) !important;
}
.\!p-4 {
padding: calc(var(--spacing) * 4) !important;
}
.p-2 {
padding: calc(var(--spacing) * 2);
}
.\!px-2 {
padding-inline: calc(var(--spacing) * 2) !important;
}
.\!pt-8 {
padding-top: calc(var(--spacing) * 8) !important;
}
.text-center {
text-align: center;
}
.text-left {
text-align: left;
}
.text-right {
text-align: right;
}
.text-base {
font-size: var(--text-base);
line-height: var(--tw-leading, var(--text-base--line-height));
}
.text-xs {
font-size: var(--text-xs);
line-height: var(--tw-leading, var(--text-xs--line-height));
}
.\!text-gray-800 {
color: var(--color-gray-800) !important;
}
.text-red-400 {
color: var(--color-red-400);
}
.text-white {
color: var(--color-white);
}
.opacity-80 {
opacity: 80%;
}
.opacity-90 {
opacity: 90%;
}
}
@layer theme;
html, body, #panel-html__body {
position: relative;
}
#panel-html__body {
--font-sans: "Orbitron", sans-serif;
width: 100%;
height: 100%;
background-color: var(--color-gray-900);
font-family: var(--font-sans);
font-size: var(--text-sm);
line-height: var(--tw-leading, var(--text-sm--line-height));
--tw-font-weight: var(--font-weight-light);
font-weight: var(--font-weight-light);
--tw-tracking: var(--tracking-wide);
letter-spacing: var(--tracking-wide);
color: var(--color-slate-50);
* {
box-sizing: border-box;
}
}
.group-left, .group-middle, .group-right {
display: grid;
height: fit-content;
gap: calc(var(--spacing) * 2);
}
.ed-panel {
height: fit-content;
width: 100%;
border-bottom-right-radius: var(--radius-xl);
border-bottom-left-radius: var(--radius-xl);
border-style: var(--tw-border-style);
border-width: 1px;
padding: calc(var(--spacing) * 2);
h3, h4 {
margin: calc(var(--spacing) * 0);
margin-bottom: calc(var(--spacing) * 1);
--tw-font-weight: var(--font-weight-extralight);
font-weight: var(--font-weight-extralight);
}
h3 {
font-size: var(--text-base);
line-height: var(--tw-leading, var(--text-base--line-height));
}
h4 {
font-size: var(--text-sm);
line-height: var(--tw-leading, var(--text-sm--line-height));
}
&.pnl__blue {
border-color: var(--color-sky-300);
background-color: color-mix(in srgb, oklch(68.5% 0.169 237.323) 30%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-sky-500) 30%, transparent);
}
h3, h4 {
color: var(--color-sky-100);
text-shadow: 0 0 0.2em var(--color-sky-300);
}
}
&.pnl__yellow {
border-color: var(--color-amber-300);
background-color: color-mix(in srgb, oklch(76.9% 0.188 70.08) 30%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-amber-500) 30%, transparent);
}
h3, h4 {
color: var(--color-amber-100);
text-shadow: 0 0 0.2em var(--color-amber-300);
}
}
&.pnl__orange {
border-color: var(--color-orange-300);
background-color: color-mix(in srgb, oklch(70.5% 0.213 47.604) 30%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-orange-500) 30%, transparent);
}
h3, h4 {
color: var(--color-orange-100);
text-shadow: 0 0 0.2em var(--color-orange-300);
}
}
&.pnl__red {
border-color: var(--color-rose-300);
background-color: color-mix(in srgb, oklch(64.5% 0.246 16.439) 30%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-rose-500) 30%, transparent);
}
h3, h4 {
color: var(--color-rose-100);
text-shadow: 0 0 0.2em var(--color-rose-400);
}
}
&.pnl__white {
border-color: var(--color-white);
background-color: color-mix(in srgb, #fff 20%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-white) 20%, transparent);
}
h3, h4 {
color: var(--color-white);
text-shadow: 0 0 0.2em var(--color-white);
}
}
}
.ed-button {
display: flex;
align-items: center;
justify-content: center;
border-radius: var(--radius-lg);
border-style: var(--tw-border-style);
border-width: 3px;
padding-inline: calc(var(--spacing) * 4);
padding-block: calc(var(--spacing) * 2);
text-align: center;
font-size: var(--text-base);
line-height: var(--tw-leading, var(--text-base--line-height));
svg {
display: block;
width: calc(var(--spacing) * 5) !important;
height: calc(var(--spacing) * 5) !important;
}
&.btn__vertical {
flex-direction: column;
}
&.btn__filled {
color: var(--color-gray-900);
}
&.btn__orange {
border-color: var(--color-orange-400);
background-color: color-mix(in srgb, oklch(70.5% 0.213 47.604) 50%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-orange-500) 50%, transparent);
}
color: var(--color-orange-100);
&.btn__filled {
background-color: var(--color-orange-400);
}
}
&.btn__yellow {
border-color: var(--color-amber-400);
background-color: color-mix(in srgb, oklch(76.9% 0.188 70.08) 50%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-amber-500) 50%, transparent);
}
color: var(--color-orange-100);
&.btn__filled {
background-color: var(--color-amber-400);
}
}
&.btn__blue {
border-color: var(--color-sky-400);
background-color: color-mix(in srgb, oklch(68.5% 0.169 237.323) 50%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-sky-500) 50%, transparent);
}
color: var(--color-sky-100);
&.btn__filled {
background-color: var(--color-sky-500);
}
}
&.btn__red {
border-color: var(--color-rose-500);
background-color: color-mix(in srgb, oklch(58.6% 0.253 17.585) 50%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-rose-600) 50%, transparent);
}
color: var(--color-rose-100);
&.btn__filled {
background-color: var(--color-rose-600);
}
}
&.btn__white {
border-color: var(--color-white);
background-color: color-mix(in srgb, #fff 30%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-white) 30%, transparent);
}
&.btn__filled {
background-color: var(--color-white);
}
}
}
.ed-button-group__horizontal {
display: grid;
:where(& > :not(:last-child)) {
--tw-divide-x-reverse: 0;
border-inline-style: var(--tw-border-style);
border-inline-start-width: calc(1px * var(--tw-divide-x-reverse));
border-inline-end-width: calc(1px * calc(1 - var(--tw-divide-x-reverse)));
}
.ed-button {
border-radius: 0;
&:first-child {
border-top-left-radius: var(--radius-lg);
border-bottom-left-radius: var(--radius-lg);
}
&:last-child {
border-top-right-radius: var(--radius-lg);
border-bottom-right-radius: var(--radius-lg);
}
}
}
.ed-button-group__vertical {
display: grid;
:where(& > :not(:last-child)) {
--tw-divide-y-reverse: 0;
border-bottom-style: var(--tw-border-style);
border-top-style: var(--tw-border-style);
border-top-width: calc(1px * var(--tw-divide-y-reverse));
border-bottom-width: calc(1px * calc(1 - var(--tw-divide-y-reverse)));
}
.ed-button {
border-radius: 0;
&:first-child {
border-top-left-radius: var(--radius-lg);
border-top-right-radius: var(--radius-lg);
}
&:last-child {
border-bottom-right-radius: var(--radius-lg);
border-bottom-left-radius: var(--radius-lg);
}
}
}
.ed-toggle {
.toggle__wrapper {
position: relative;
width: 100%;
height: 100%;
border-radius: calc(infinity * 1px);
border-style: var(--tw-border-style);
border-width: 2px;
padding: calc(var(--spacing) * 1.5);
}
.toggle__indicator {
position: absolute;
aspect-ratio: 1 / 1;
border-radius: calc(infinity * 1px);
transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter;
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
transition-duration: var(--tw-duration, var(--default-transition-duration));
}
&.toggle__horizontal {
height: calc(var(--spacing) * 12);
width: calc(var(--spacing) * 20);
.toggle__indicator {
left: calc(var(--spacing) * 1.5);
height: calc(100% - .75rem);
--tw-translate-x: calc(var(--spacing) * 0);
translate: var(--tw-translate-x) var(--tw-translate-y);
}
&[active] .toggle__indicator {
--tw-translate-x: 100%;
translate: var(--tw-translate-x) var(--tw-translate-y);
}
}
&.toggle__vertical {
height: calc(var(--spacing) * 20);
width: calc(var(--spacing) * 12);
.toggle__indicator {
top: calc(var(--spacing) * 1.5);
width: calc(100% - .75rem);
--tw-translate-y: calc(var(--spacing) * 0);
translate: var(--tw-translate-x) var(--tw-translate-y);
}
&[active] .toggle__indicator {
--tw-translate-y: 100%;
translate: var(--tw-translate-x) var(--tw-translate-y);
}
}
}
dialog[open] {
position: absolute;
top: calc(1/2 * 100%);
left: calc(1/2 * 100%);
--tw-translate-x: calc(calc(1/2 * 100%) * -1);
translate: var(--tw-translate-x) var(--tw-translate-y);
--tw-translate-y: calc(calc(1/2 * 100%) * -1);
translate: var(--tw-translate-x) var(--tw-translate-y);
border-style: var(--tw-border-style);
border-width: 0px;
background-color: transparent;
outline-style: var(--tw-outline-style);
outline-width: 0px;
&::backdrop {
background-color: color-mix(in srgb, #000 50%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-black) 50%, transparent);
}
}
.dialog__close {
position: absolute;
top: calc(var(--spacing) * 3);
right: calc(var(--spacing) * 3);
color: var(--color-white);
}
}
#clock {
position: relative;
display: flex;
width: fit-content;
padding-right: calc(var(--spacing) * 16);
font-size: var(--text-3xl);
line-height: var(--tw-leading, var(--text-3xl--line-height));
i {
padding-left: calc(var(--spacing) * 1);
font-style: normal;
}
.hours-minutes, .seconds {
display: flex;
gap: calc(var(--spacing) * 1);
}
span {
display: inline-block;
width: .75em;
text-align: center;
}
sup {
position: absolute;
right: calc(var(--spacing) * 0);
width: calc(var(--spacing) * 16);
padding-left: calc(var(--spacing) * 2);
text-align: left;
font-size: var(--text-lg);
line-height: var(--tw-leading, var(--text-lg--line-height));
opacity: 80%;
}
}
@property --tw-divide-x-reverse {
syntax: "*";
inherits: false;
initial-value: 0;
}
@property --tw-border-style {
syntax: "*";
inherits: false;
initial-value: solid;
}
@property --tw-font-weight {
syntax: "*";
inherits: false;
}
@property --tw-tracking {
syntax: "*";
inherits: false;
}
@property --tw-divide-y-reverse {
syntax: "*";
inherits: false;
initial-value: 0;
}
@property --tw-translate-x {
syntax: "*";
inherits: false;
initial-value: 0;
}
@property --tw-translate-y {
syntax: "*";
inherits: false;
initial-value: 0;
}
@property --tw-translate-z {
syntax: "*";
inherits: false;
initial-value: 0;
}
@property --tw-outline-style {
syntax: "*";
inherits: false;
initial-value: solid;
}
@layer properties {
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
*, ::before, ::after, ::backdrop {
--tw-divide-x-reverse: 0;
--tw-border-style: solid;
--tw-font-weight: initial;
--tw-tracking: initial;
--tw-divide-y-reverse: 0;
--tw-translate-x: 0;
--tw-translate-y: 0;
--tw-translate-z: 0;
--tw-outline-style: solid;
}
}
}

Some files were not shown because too many files have changed in this diff Show more