From a775fe1c80cd170f2b14612a92a2924879af9eaa Mon Sep 17 00:00:00 2001 From: MoonDev Date: Thu, 22 May 2025 21:57:13 +0300 Subject: [PATCH] some updates --- __pycache__/web_server.cpython-311.pyc | Bin 4430 -> 6559 bytes callbacks/__pycache__/app.cpython-311.pyc | Bin 0 -> 2911 bytes callbacks/app.py | 44 +++ config/frontend.yaml | 71 +++++ static/frontend/.env | 1 + static/frontend/package-lock.json | 10 + static/frontend/package.json | 1 + static/frontend/src/Api.jsx | 11 +- static/frontend/src/App.css | 13 +- static/frontend/src/App.jsx | 281 ++++++++++++------ static/frontend/src/index.css | 21 +- static/frontend/src/main.jsx | 4 +- .../get_primary_ip.cpython-311.pyc | Bin 0 -> 1005 bytes utils/get_primary_ip.py | 23 ++ web_server.py | 55 +++- 15 files changed, 425 insertions(+), 110 deletions(-) create mode 100644 callbacks/__pycache__/app.cpython-311.pyc create mode 100644 callbacks/app.py create mode 100644 config/frontend.yaml create mode 100644 static/frontend/.env create mode 100644 utils/__pycache__/get_primary_ip.cpython-311.pyc create mode 100644 utils/get_primary_ip.py diff --git a/__pycache__/web_server.cpython-311.pyc b/__pycache__/web_server.cpython-311.pyc index dfc289179b4915a7b050abe84bfcd91f5ac3d681..7fc74e7ac21eea3e93376161b1b18e5ebd6e9c5e 100644 GIT binary patch delta 2821 zcmZ`*TTC3+89sB_>#)OZZ5Fe@0*iqf1HRzOPGZO1wH-S#!J$rPUd0C0nCLN-Oc;w~d-emY@2cSr%CA zo}Kf}|DW@J|GCWnpR@mL{oMiihR^3kP>!X0$3L!Glmq-#ez9}$C4^mxox?jZ!rnw( zGB6zA5Xe%ZKDldn7swUE4Lnl0WuX3n@$E7kRD(;6#-ixot$MNV5{G3QL0YL?c7Q3= zV&M>&HZjvaTm_z-xO$~#nFAB3#R4t0%L24OEf$;9%t*!@*VYo^(J6#?UO~7{70WG$ zTfn_-*^L9(wNk&#gCnTLf_Gg(+os-HBJ9TvFCYZfwlN+zUJ+kF3$qywJ;gO@xsPc#|^2J9SN4(q+XV12 z(m7+n9mv7dxdBoMO=Ld<+cg{0^0Ebtrc-0_OXLtV^g`8SfLXLA)tgd7UTUCXgUy(( z>K!BLl&+@m-gQbhSdMOl2`Eme_W0v46E;5RD9iw%i48-{>0+^s;WX4Gfqgk1^TxQl zkrP1)4`#V6`l%gpq*|9Y?XiHx6-Rj(&2hSKi-og10A~0szvKd^tvRjSl?%I{cjZBP z^`^5dk3E=Q@s>wKKbjHr+D)qoJ9n9$6}Am7Lb}4wp0M#ZF`TR0q-Di&<0!i5y#QM` z z?qK)6; zNv;*TEGJfVC7zh}7ei?yw0hoCl8GnRfH=vLg#Mnc(m&C^gi8MH{t&%OZ!=(hU(nn1 zE(wA$VNq}Kas1?4#&2i*-2fg4BNu|!(ImPbuZ zCRL*7Kxb1tK}ecdo)c4}YDSNzQ(bPta?kROrjwaTUBxjr4@-)?IdJmyso2TWZ=A5i zv3NqYM6BqFCB*TRCB}6%X>mDKa|1WDUW$hgOMd$VU}uBIj{aHnofGW{UK^n8hi*@q z?Z+O4PdyBu`n$^v59Y&zrvF^tf9{e0{6qhF(|Sym~td9N2oipRC>m%T5R<@H`>*}tDmWMg1no8WZujJxNGG}%+7aP|d;Jw4-{-`L!*$;w zFxky9*>kvwDV>$keZu|k`=gTZK=Oh7AmER73lF*-AWzr!Dx)mUdVii$lIoERTz501 z{_{cS7eYIE35I&c^-R}pP3+KEnj{td3Hx6`4kP1$x6{MU0CEJtNP0UeTA20jS}ie?h9hDEL1J41nM`fFtDm`FhWmapp&lhOU=A6IwD)=ALghdD9wTYi z{yjzkTK+sny|n!KTH0ZBS0#*lRqe+0s;-F-0y&EmgbzACbxEW=}`|{kr0^iJ~xP_qtV(+cU$on@e3a@dD9+(SIZ?nmT@?5CE NhmB`dgCaY0{s&=E-}3+f delta 831 zcmZ8e&ubGw6rS1Lq-}n+-Pr7=zp@o;8^i_`i%Kb$D$;}48byd;Su@k@md$RM-P97% zQ~d+N^sXSJg1tyR^yEd)o@KqL;6e1zgQuQ+vq7|d@ZQdQ@7wRq`{wzDk0&!b>2v~t zl^16$FWJuM(l6YeZjU4?ISEnRf!1r$kF26m?S;-)r0f);36iW~l8PdncGI00V8OeF z5n%HIdlQiiaK%ag?m!0v2E1!f8SKbV0q+_{61stix`jxVDo1;jVPG5)jQkls6&rF$sOa>=s3~o@R~yMTgtH=3UHVHb>r_us*zzbvO9Wo7Dl9}jEZCYowS{5CFUBY z??3Vwndcj_!w+KnJRciRG7VUwFv0iZvweazO8GbWD=zX6%3Y03Kru`(YLZpkC3KU` zK;blBitT8vY{{$!w&#`}yJnqUX_$fagbnSbGH>NlQDQ~$Yn;%)w4Fmd)5V9u z!!mu#So2uj41Ng3?KbA$2dC9ZIJZ*&qj*l8N=*yMHpp)O#(YT~kLyrid0tn~JP3Q2 z7s};(w{Bkxm37~9!x(AS8$KHYNZ2C=IrhUa?px;hi?d;zx>b+Ru+O5K#I8|4U@5_s z7U;g~n^oEn`xKLGNR&(bvwCMCOjo^nqZv@LD)`uC0mjr%!q@m`U8T~N=@N&oc7T;;EFg_TJ3P_EG+Qa4l@9^6c<5D|njYr3o;QbPps zB!|6ob&oV1I?qf7fK6rT02e_|3lI3a-m^%hcrTPYmc1C1ypIHavgQk2k^8cWpij$@Pc+S(uG zN2Wl6T7Dv>w?-!)+t|(MdwKfoNthXBu+*lcDKn~(iXCD%;#l3 zDTIWiJ!FTzfCcQp_Lyx;nFUGq)z4yr$lJmRJ!2xo8x=PhQ~>`Ves-u?l5SwqnY%D{)r%KH`QTwQvg`E;gW@seyA?prizTN!19%WzqtJg4%$k}GSk94q@0zmiR> zTM;ESK#fhE@c1~&TX-6nB+4^s=jRN zK|7INyUf#!)aFyR74d8Iy5;fA3va$wE+o$>+ZVP0POo0ZowUl2_1B2tU3Y|rG{}F32Dm_-@g9`ETZD^zLvrL-I!e!y+u%*n5fQp) z$TXQDdGa%vB6HwRiPnQ@k&eUI4825d!!(i?>8J(!1)y{A$&*<+$_Pg32$^oNB3Pyk zwr#8Bv7l@dw~B06CsIm89TKA{MUNzugwiMOGE{k&xLeaz=mo@7Ow{989KgL=LdT+> z5>sicw74yWmRbo#~JETF?O>`8_Qo9z%vTWL;aU2B|ZRxZ)TyMQ1mPE~nMj=%(LzahNu5&SO zDywrNSgCc@3zkEd)}F})@lYFidIl;6JSYe&4_(IFjOaUh9!lyutDePz6A7!Law$Uk zR+S+gZxu`EN#ME(+-HF`2j4vX3gYEUm>jtw!srYgUrCt*^x;*p^N`aikeH)if}lLm zurj_SLb4&@mTE}!+8TlI4Mxc1Fttq74PddB9C&g}LVo#8p$ckDz7OjvJ8Mk`9!zMu zW;z$E&9uv@0j!!XtVkNGU(>A_y=gVY7RBUMLoqjYBxKx`(mPUyB3UJB@~~A*Uoaxe zSUOUgTN>~l!D=$0X|Tsi52_9gMsb?$xd3mismkil2V2AGAw8Z_!l_6i z9gYHPZzS5Ug(K;7OM1w3f`}8~tJ?v=ex@`IejNXS&lyx~YO;563*Nf%!Ha_v4(jz6 zy#DjT-`={f+b;}{4L|gX_q`(Z?kIS76cJa|#y#?FAx-a2*MosZeFqA@1El&u(Sd5~ z$A>QtU&xGQ9(tSadz;B??@;glf_J|Kv{}H@S&1~AF15!9)wS9FvuqKenl{^02db(Y z^GrCizU)!b_bp;EqAUJ_TqzB;>kWXgESn5Mm?PcPbYD8GE|Xg5OB2jp%l&?Y(5x3cLMH? zYW~if{-BS)>+^wsx7pv$^YeTS`17^?_C5Uk9?Re7KeUy Dict[str, Any]: + """ + Запускает приложение или ярлык по указанному пути. + + Args: + args: Dictionary containing 'url' (string) of the website to open. + + Returns: + Dictionary with status message and input arguments. + + Raises: + OSError: If opening the website fails. + """ + try: + path = args.get("path") + # Проверка существования файла + if not Path(path).exists(): + raise OSError(f"Файл не найден: {path}") + + # Проверка расширения файла + if not path.lower().endswith(('.exe', '.lnk', '.bat')): + raise OSError(f"Файл {path} может не быть исполняемым файлом или ярлыком") + + # Попытка запуска приложения + subprocess.run(['start', '', path], shell=True, check=True) + return { + "message": f"App {path} opened successfully", + "args": args + } + + except FileNotFoundError as e: + raise OSError(f"Файл не найден или путь некорректен: {str(e)}") + except subprocess.CalledProcessError as e: + raise OSError(f"Ошибка при запуске приложения: {str(e)}") + except PermissionError as e: + raise OSError(f"Недостаточно прав для запуска: {str(e)}") + except OSError as e: + raise OSError(f"Ошибка операционной системы при запуске: {str(e)}") + except Exception as e: + raise OSError(f"Непредвиденная ошибка: {str(e)}") \ No newline at end of file diff --git a/config/frontend.yaml b/config/frontend.yaml new file mode 100644 index 0000000..76e27ed --- /dev/null +++ b/config/frontend.yaml @@ -0,0 +1,71 @@ +- type: "break" # Разделитель с подписью "система" + label: "Система" + +- type: "clock" # Часы + mini_icon: "/icons/mini/clock-five.png" + +- type: "gauge" # Круговые индикаторы + gauges: + - value: 0 + label: "Загрузка CPU" + - value: 0 + label: "Занято RAM" + tag: "system_load" + mini_icon: "/icons/mini/chart-line-up.png" + +- type: "number" # Вывод числа + value: 0 + label: "Трафик Mbit/s" + tag: "net_traffic" + mini_icon: "/icons/mini/wifi.png" + +- type: "slider" # Слайдеры + label: "Настройки" + sliders: + - value: 0 + label: "Яркость экрана" + action: "screen.chenge_brightness" + - value: 0 + label: "Громкость звука" + action: "media.set_volume" + mini_icon: "/icons/mini/settings.png" + +- type: "break" # Разделитель + label: "Сайты" + +- type: "image" # Кнопка с картинкой + imageUrl: "/icons/telegram-logo-svgrepo-com.svg" + label: "Telegram" + action: "web.open_url" + action_args: + url: "https://ya.ru " + mini_icon: "/icons/mini/arrow-up-right-from-square.png" + +- type: "image" # Кнопка с картинкой + imageUrl: "/icons/cloud.png" + label: "Cloud" + action: "web.open_url" + action_args: + url: "https://cloud.viadev.su " + mini_icon: "/icons/mini/arrow-up-right-from-square.png" + +- type: "break" # Разделитель + label: "Приложения" + +- type: "image" # Кнопка с картинкой + imageUrl: "/icons/steam-svgrepo-com.svg" + label: "Steam" + action: "app.run_app" + action_args: + path: "C:/Users/Slava/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Steam/Steam.lnk" + mini_icon: "/icons/mini/arrow-up-right-from-square.png" + + +- type: "break" # Разделитель + label: "Управление ПК" + +- type: "image" # Кнопка с картинкой + imageUrl: "/icons/vpn.png" + label: "VPN" + action: "v2ray.enable_vpn" + action_args: {} \ No newline at end of file diff --git a/static/frontend/.env b/static/frontend/.env new file mode 100644 index 0000000..425c60f --- /dev/null +++ b/static/frontend/.env @@ -0,0 +1 @@ +VITE_API_PORT = 8000 \ No newline at end of file diff --git a/static/frontend/package-lock.json b/static/frontend/package-lock.json index 71d65bd..89bc707 100644 --- a/static/frontend/package-lock.json +++ b/static/frontend/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@tailwindcss/vite": "^4.1.7", "axios": "^1.9.0", + "qrcode.react": "^4.2.0", "react": "^19.1.0", "react-dom": "^19.1.0", "tailwindcss": "^4.1.7" @@ -3247,6 +3248,15 @@ "node": ">=6" } }, + "node_modules/qrcode.react": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/qrcode.react/-/qrcode.react-4.2.0.tgz", + "integrity": "sha512-QpgqWi8rD9DsS9EP3z7BT+5lY5SFhsqGjpgW5DY/i3mK4M9DTBNz3ErMi8BWYEfI3L0d8GIbGmcdFAS1uIRGjA==", + "license": "ISC", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/react": { "version": "19.1.0", "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", diff --git a/static/frontend/package.json b/static/frontend/package.json index 0b74ea6..0ee59e8 100644 --- a/static/frontend/package.json +++ b/static/frontend/package.json @@ -12,6 +12,7 @@ "dependencies": { "@tailwindcss/vite": "^4.1.7", "axios": "^1.9.0", + "qrcode.react": "^4.2.0", "react": "^19.1.0", "react-dom": "^19.1.0", "tailwindcss": "^4.1.7" diff --git a/static/frontend/src/Api.jsx b/static/frontend/src/Api.jsx index b50174d..a83f2ff 100644 --- a/static/frontend/src/Api.jsx +++ b/static/frontend/src/Api.jsx @@ -1,9 +1,9 @@ import axios from 'axios'; -const API_URL = "http://192.168.2.151:8000" -const createSha256Hash = async (input) => { + +export const createSha256Hash = async (input) => { try { // Convert string to array buffer const msgBuffer = new TextEncoder().encode(input); @@ -23,11 +23,11 @@ const createSha256Hash = async (input) => { } -const sendRequest = async (action,args) => { +export const sendRequest = async (action,args) => { try { const TS = Math.round(Date.now()/1000); - const hash = await createSha256Hash(""+JSON.stringify(args)+TS); - const response = await axios.post(API_URL+"/action/"+action, {args:args,hash:hash+"."+TS}, { + const hash = await createSha256Hash(window.localStorage.auth+JSON.stringify(args)+TS); + const response = await axios.post("http://"+window.location.hostname+":"+import.meta.env.VITE_API_PORT+"/action/"+action, {args:args,hash:hash+"."+TS}, { timeout: 4000, headers: { 'Content-Type': 'application/json' @@ -40,4 +40,3 @@ const sendRequest = async (action,args) => { } }; -export default sendRequest; \ No newline at end of file diff --git a/static/frontend/src/App.css b/static/frontend/src/App.css index f8635fb..938c310 100644 --- a/static/frontend/src/App.css +++ b/static/frontend/src/App.css @@ -7,12 +7,17 @@ transition: all 0.3s ease; } -.glass:hover { - background: rgba(147, 51, 234, 0.2); - border-color: rgba(147, 51, 234, 0.7); - box-shadow: 0 6px 12px rgba(147, 51, 234, 0.3); +.glass { + &:hover, + &:focus, + &:active { + background: rgba(147, 51, 234, 0.2); + border-color: rgba(147, 51, 234, 0.7); + box-shadow: 0 6px 12px rgba(147, 51, 234, 0.3); + } } + @keyframes flipRight { 0% { transform: rotate(0deg); diff --git a/static/frontend/src/App.jsx b/static/frontend/src/App.jsx index 5b8bdfe..657362b 100644 --- a/static/frontend/src/App.jsx +++ b/static/frontend/src/App.jsx @@ -1,6 +1,8 @@ import { useState, useEffect } from 'react' import './App.css' -import sendRequest from "./Api.jsx"; +import { sendRequest, createSha256Hash } from "./Api.jsx"; +import { QRCodeSVG } from 'qrcode.react'; +import axios from 'axios'; window.sendRequest = sendRequest; const TextTile = ({ label }) => ( @@ -94,25 +96,16 @@ const NumberTile = ({ value, label }) => ( ); const App = () => { - const [tiles, setTiles] = useState([ - { id: 0, type: "break", label: "Система" }, - { id: 1, type: "clock", mini_icon:"/icons/mini/clock-five.png" }, + const [phase, setPhase] = useState("loading"); + const [QrLink, setQrLink] = useState(); + const [Password, setPassword] = useState(""); - { id: 2, type: "gauge", gauges: [{ value: 3.60 * 0, label: "Загрузка CPU" }, { value: 3.60 * 0, label: "Занято RAM" }], tag: "system_load", mini_icon:"/icons/mini/chart-line-up.png" }, + const handlePasswordChange = (event) => { + setPassword(event.target.value); + }; - { id: 3, type: "number", value: 0, label: "Трафик Mbit/s", tag: "net_traffic", mini_icon:"/icons/mini/wifi.png" }, - { id: 4, type: "slider", label: "Настройки", sliders: [{ value: 50, label: "Яроксть экрана", action: "screen.chenge_brightness" }, { value: 75, label: "Громкость звука", action: "media.set_volume" }], mini_icon:"/icons/mini/settings.png" }, - - { id: 5, type: "break", label: "Сайты" }, - - { id: 6, type: "image", imageUrl: "/icons/steam-svgrepo-com.svg", label: "Steam", action: "web.open_url", action_args: { url: "https://ya.ru" }, mini_icon:"/icons/mini/arrow-up-right-from-square.png" }, - { id: 7, type: "image", imageUrl: "/icons/telegram-logo-svgrepo-com.svg", label: "Telegram", action: "web.open_url", action_args: { url: "https://ya.ru" }, mini_icon:"/icons/mini/arrow-up-right-from-square.png" }, - { id: 8, type: "image", imageUrl: "/icons/cloud.png", label: "Cloud", action: "web.open_url", action_args: { url: "https://cloud.viadev.su" }, mini_icon:"/icons/mini/arrow-up-right-from-square.png" }, - - { id: 9, type: "break", label: "Управление ПК" }, - { id: 10, type: "image", imageUrl: "/icons/vpn.png", label: "VPN", action: "v2ray.enable_vpn", action_args: {} }, - ]); + const [tiles, setTiles] = useState(); @@ -133,17 +126,6 @@ const App = () => { }; - - const toggleImageEnabled = (tileId) => { - setTiles(prevTiles => - prevTiles.map(tile => { - if (tile.id === tileId && tile.type === "image") { - return { ...tile, enabled: !tile.enabled }; - } - return tile; - }) - ); - }; const setTileProps = (tileId, props) => { setTiles(prevTiles => prevTiles.map(tile => { @@ -164,29 +146,88 @@ const App = () => { }) ); }; + const updateSystemStats = async () => { + try { + const data = await sendRequest("system.get_system_metrics", {}); + setTilePropsByTag("system_load", { + gauges: [ + { value: (3.60 * data.result.metrics.cpu_usage_percent).toFixed(0), label: "Загрузка CPU" }, + { value: (3.60 * (data.result.metrics.ram_used_gb / data.result.metrics.ram_total_gb) * 100).toFixed(0), label: "Занято RAM" } + ] + }) + setTilePropsByTag("net_traffic", { + value: data.result.metrics.network_traffic_mbps + }) + } catch (e) { + console.error(e); + } + }; - useEffect(() => { - const updateSystemStats = async () => { - try { - const data = await sendRequest("system.get_system_metrics", {}); - setTilePropsByTag("system_load", { - gauges: [ - { value: (3.60 * data.result.metrics.cpu_usage_percent).toFixed(0), label: "Загрузка CPU" }, - { value: (3.60 * (data.result.metrics.ram_used_gb / data.result.metrics.ram_total_gb) * 100).toFixed(0), label: "Занято RAM" } - ] - }) - setTilePropsByTag("net_traffic", { - value: data.result.metrics.network_traffic_mbps - }) + const TryAuth = async (passw) => { + try { + setPhase("loading"); + const hash = await createSha256Hash("frontend_config" + passw); + const response = await axios.get("http://" + window.location.hostname + ":" + import.meta.env.VITE_API_PORT + "/frontend-config", { + timeout: 4000, + params: { + hash: hash, + }, + headers: { + 'Content-Type': 'application/json' + } + }); + setTimeout(() => { + window.localStorage.auth = passw; + setTiles(response.data); + setPhase("dash"); + updateSystemStats(); + const interval = setInterval(updateSystemStats, 2000); + }, 500) - } catch (e) { - console.error(e); + } catch (e) { + window.localStorage.clear("auth") + window.location.reload(); + } + } + const RequestAuth = () => { + setPhase("login"); + } + const Init = async () => { + if (window.localStorage.auth) { + return TryAuth(window.localStorage.auth); + } + const response = await axios.get("http://" + window.location.hostname + ":" + import.meta.env.VITE_API_PORT + "/primary-ip", { + timeout: 4000, + headers: { + 'Content-Type': 'application/json' } - }; - updateSystemStats(); - const interval = setInterval(updateSystemStats, 2000); - return () => clearInterval(interval); + }); + console.log(response.data) + const currentUrl = new URL(window.location.href); + + // Меняем хост + currentUrl.hostname = response.data; + + // Устанавливаем hash + currentUrl.hash = '#skip_start'; + + // Получаем новый URL + const newUrl = currentUrl.toString(); + setQrLink(newUrl); + if (window.location.hash != "#skip_start") { + setPhase("start"); + } else { + setPhase("login"); + } + } + useEffect(() => { + + + Init(); + // updateSystemStats(); + // const interval = setInterval(updateSystemStats, 2000); + // return () => { clearInterval(interval) }; }, []); @@ -214,53 +255,111 @@ const App = () => { } } - return ( -
-
- {tiles.map(tile => ( -
- {tile.type === "break" ? ( -
{tile.label}
- ) : ( -
{ onTileClick(tile) }} - className={`glass rounded-lg ${tile.type === "gauge" || tile.type === "slider" || tile.type === "clock" ? "w-full h-45 lg:h-48" : "w-full h-45 lg:h-48"} relative ${tile.type === "image" && tile.enabled ? "glass_enabled" : ""}`} - > - {tile.loading && -
-
-
- } - {!tile.loading && - <> - {tile.type === "text" && } - {tile.type === "image" && ( - toggleImageEnabled(tile.id)} - /> - )} - {tile.type === "clock" && } - {tile.type === "gauge" && } - {tile.type === "slider" && } - {tile.type === "number" && } - {tile.mini_icon && ( -
- - - -
- )} - - } + if (phase === "start") { + return ( +
+
+
+
+
+
- )} +
- ))} +
+
+ + +
+
+
-
+ ) + } + + if (phase === "loading") { + return ( +
+
+
+ ) + } + + return ( + <> + {phase == "login" && ( +
+
+
{ TryAuth(Password) }} className='w-full'> + +
+
+
+ )} + {phase === "dash" && ( + +
+
+ {tiles.map(tile => ( +
+ {tile.type === "break" ? ( +
{tile.label}
+ ) : ( +
{ onTileClick(tile) }} + className={`glass rounded-lg ${tile.type === "gauge" || tile.type === "slider" || tile.type === "clock" ? "w-full h-45 lg:h-48" : "w-full h-45 lg:h-48"} relative ${tile.type === "image" && tile.enabled ? "glass_enabled" : ""}`} + > + {tile.loading && +
+
+
+ } + {!tile.loading && + <> + {tile.type === "text" && } + {tile.type === "image" && ( + + )} + {tile.type === "clock" && } + {tile.type === "gauge" && } + {tile.type === "slider" && } + {tile.type === "number" && } + {tile.mini_icon && ( +
+ + + +
+ )} + + } +
+ )} +
+ ))} +
+
+ + )}; + ); + }; + export default App diff --git a/static/frontend/src/index.css b/static/frontend/src/index.css index bf9f16f..03411dc 100644 --- a/static/frontend/src/index.css +++ b/static/frontend/src/index.css @@ -1,4 +1,23 @@ @import "tailwindcss"; -#root{ +html,body,#root{ width:100%; + height: 100%; + background-color: #101828; +} +@keyframes anim-pop { + 0% { + opacity: 0; + transform: scale(.95); + transform: scale(var(--btn-focus-scale, .98)); + } + 100% { + opacity: 1; + transform: scale(1); + } +} + +.anim-pop { + opacity: 0; /* Element starts hidden */ + animation: anim-pop .3s ease-in forwards; + animation-delay: 0.2s; } \ No newline at end of file diff --git a/static/frontend/src/main.jsx b/static/frontend/src/main.jsx index ffc71ea..820156d 100644 --- a/static/frontend/src/main.jsx +++ b/static/frontend/src/main.jsx @@ -4,7 +4,7 @@ import './index.css' import App from './App.jsx' createRoot(document.getElementById('root')).render( - +
- +
) diff --git a/utils/__pycache__/get_primary_ip.cpython-311.pyc b/utils/__pycache__/get_primary_ip.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a40b4165e5d15703b176a254daaa9e45d1bc262e GIT binary patch literal 1005 zcmZ`%%}X0m5TCan(ZuSSYQ&&ctI?7QsTFKhnu1mfdXPeTsFD&wcCBk;5_UI@DZ8bV z9zyZptBqC?0wXco9#X7fq}!ot^#7?7W%Zyq)*n*VeiK zrFiGk+&T;JlYW$iId=9N(RmIch$Id(ATm#3hKM8te)bnlnTj1JmJE-GOt9ZiXq6K* zv}KvE_-h#2D2KrS9me2p%pf{4-!FAm$ddC^ZFxVSlQrbosBjsKR$&5|r`=1UGY>!+ z)c>>UEvM1W-3F_(B6AWmIGtPNDk*d?6uLx8>^Sn634MJ@zgpp_UhY(!24Qdzt1bVzX{1wAkIJHlfq zGG}?;p68t9@#j6gmZvx8DtOw9aK_nLg53D7(73`qGjc|uzIo5vX?X+d>AZKq@($!C z_k?Ck=vbXJg#c=ywdY;dx-e+94i$lOBLTwlSi#%2GW)7^d33j>?QQTyaJ?zt(r2~w z6@hp<3+?AuoaLv;V&q^~=r)D!gC8}Gn8Eu_pdfUu5>x1+TK%^kpkO`kL#z7m-=2(I z841F-A%