mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2025-12-12 01:00:29 +08:00
kvm pug
This commit is contained in:
parent
3e7315c448
commit
6fa59bd7a1
1
Makefile
1
Makefile
@ -146,6 +146,7 @@ pug: testenv
|
||||
-it $(TESTENV_IMAGE) bash -c "cd src \
|
||||
&& pug --pretty web/index.pug -o web \
|
||||
&& pug --pretty web/login/index.pug -o web/login \
|
||||
&& pug --pretty web/kvm/index.pug -o web/kvm \
|
||||
&& pug --pretty web/ipmi/index.pug -o web/ipmi \
|
||||
&& pug --pretty web/vnc/index.pug -o web/vnc \
|
||||
"
|
||||
|
||||
@ -25,6 +25,7 @@ doctype html
|
||||
- var css_dir = "/share/css"
|
||||
- var js_dir = "/share/js"
|
||||
- var svg_dir = "/share/svg"
|
||||
- var png_dir = "/share/png"
|
||||
|
||||
- var title = ""
|
||||
- var main_js = ""
|
||||
|
||||
4
web/kvm/footer.pug
Normal file
4
web/kvm/footer.pug
Normal file
@ -0,0 +1,4 @@
|
||||
ul(class="footer")
|
||||
li(id="kvmd-meta-server-host" class="footer-left")
|
||||
li(class="footer-right")
|
||||
a(target="_blank" href="https://pikvm.org") Pi-KVM Project
|
||||
1377
web/kvm/index.html
1377
web/kvm/index.html
File diff suppressed because it is too large
Load Diff
13
web/kvm/index.pug
Normal file
13
web/kvm/index.pug
Normal file
@ -0,0 +1,13 @@
|
||||
extends ../base.pug
|
||||
|
||||
append vars
|
||||
- title = "Pi-KVM Session"
|
||||
- main_js = "kvm/main"
|
||||
- body_class = "body-no-select"
|
||||
- css_list = css_list.concat(["navbar", "window", "modal", "led", "slider", "switch", "progress", "keypad", "tabs"])
|
||||
- css_list = css_list.concat(["kvm/stream", "kvm/hid", "kvm/msd", "kvm/keyboard", "kvm/about"])
|
||||
|
||||
block body
|
||||
include navbar.pug
|
||||
include windows.pug
|
||||
include footer.pug
|
||||
263
web/kvm/navbar.pug
Normal file
263
web/kvm/navbar.pug
Normal file
@ -0,0 +1,263 @@
|
||||
mixin navbar_led(id, icon)
|
||||
img(data-dont-hide-menu id=id, class="led-gray" src=`${svg_dir}/${icon}.svg`)
|
||||
|
||||
mixin navbar_message(icon, short)
|
||||
div(class="text")
|
||||
table
|
||||
tr
|
||||
td #[img(class="sign" src=`${svg_dir}/${icon}.svg`)]
|
||||
td
|
||||
| #[b #{short}]
|
||||
if block
|
||||
br
|
||||
sup
|
||||
block
|
||||
|
||||
mixin navbar_health_message(icon, short, gray)
|
||||
div(class="text")
|
||||
table
|
||||
tr
|
||||
td #[img(class=`sign ${gray ? " led-gray" : ""}` src=`${svg_dir}/${icon}.svg`)]
|
||||
td
|
||||
| #[b #{short}] #[br] #[br]
|
||||
sup
|
||||
block
|
||||
|
||||
mixin switch(id)
|
||||
div(class="switch-box")
|
||||
input(checked type="checkbox" id=id class="switch-checkbox")
|
||||
label(class="switch-label" for=id)
|
||||
span(class="switch-inner")
|
||||
span(class="switch")
|
||||
|
||||
ul(id="navbar")
|
||||
li(class="left")
|
||||
a(id="logo" href="/") ←
|
||||
img(class="svg-gray" src=`${svg_dir}/logo.svg` alt="π-kvm")
|
||||
|
||||
div(id="hw-health-dropdown" class="hidden")
|
||||
li(class="left")
|
||||
a(class="menu-button" href="#")
|
||||
img(data-dont-hide-menu id="hw-health-undervoltage-led" class="hidden" src=`${svg_dir}/led-undervoltage.svg`)
|
||||
img(data-dont-hide-menu id="hw-health-overheating-led" class="hidden" src=`${svg_dir}/led-overheating.svg`)
|
||||
| ↴
|
||||
div(data-dont-hide-menu class="menu")
|
||||
+navbar_health_message("warning", "Raspberry Pi's health is at risk", false)
|
||||
| This is not a drill! A red icon indicates a current issue,#[br]
|
||||
| a yellow one that was observed since the device booted up.
|
||||
div(id="hw-health-message-undervoltage" class="hidden")
|
||||
hr
|
||||
+navbar_health_message("led-undervoltage", "Undervoltage detected", true)
|
||||
| Make sure your power supply and cabling are providing#[br]
|
||||
| enough power to the Raspberry Pi (3A minimum).
|
||||
div(id="hw-health-message-overheating" class="hidden")
|
||||
hr
|
||||
+navbar_health_message("led-overheating", "Overheating detected", true)
|
||||
| Frequency capping due to overheating.#[br]
|
||||
| Improve cooling of the Raspberry Pi.
|
||||
|
||||
li(class="right")
|
||||
a(class="menu-button" href="#")
|
||||
+navbar_led("link-led", "led-link")
|
||||
+navbar_led("stream-led", "led-stream")
|
||||
+navbar_led("hid-keyboard-led", "led-hid-keyboard")
|
||||
+navbar_led("hid-mouse-led", "led-hid-mouse")
|
||||
| System ↴
|
||||
div(data-dont-hide-menu class="menu")
|
||||
div(class="buttons")
|
||||
button(disabled data-force-hide-menu id="stream-screenshot-button") • Take a screenshot
|
||||
hr
|
||||
button(data-force-hide-menu id="show-stream-button") • Show stream
|
||||
button(data-force-hide-menu id="show-keyboard-button") • Show keyboard
|
||||
button(data-force-hide-menu id="show-about-button") • Show about
|
||||
div(id="stream-resolution" class="feature-disabled")
|
||||
hr
|
||||
div(class="text")
|
||||
| Stream resolution:
|
||||
div(class="stream-param-box")
|
||||
select(disabled data-dont-hide-menu id="stream-resolution-selector")
|
||||
div(id="stream-quality" class="feature-disabled")
|
||||
hr
|
||||
div(class="text")
|
||||
| Stream quality: #[span(id="stream-quality-value") 80%]
|
||||
div(class="stream-param-box")
|
||||
input(disabled type="range" id="stream-quality-slider" class="slider")
|
||||
hr
|
||||
div(class="text")
|
||||
| Stream FPS: #[span(id="stream-desired-fps-value") 0]
|
||||
div(class="stream-param-box")
|
||||
input(disabled type="range" id="stream-desired-fps-slider" class="slider")
|
||||
hr
|
||||
div(class="text")
|
||||
| Stream size: #[span(id="stream-size-value") 100%]
|
||||
div(class="stream-param-box")
|
||||
input(type="range" id="stream-size-slider" class="slider")
|
||||
hr
|
||||
div(class="text")
|
||||
table(class="one-line-switch")
|
||||
td Auto-resize stream:
|
||||
td(align="right")
|
||||
+switch("stream-auto-resize-checkbox")
|
||||
hr
|
||||
div(class="buttons")
|
||||
button(disabled data-force-hide-menu id="stream-reset-button") • Reset stream
|
||||
button(disabled data-force-hide-menu id="hid-reset-button") • Reset keyboard & mouse
|
||||
button(disabled data-force-hide-menu id="msd-reset-button" class="feature-disabled") • Reset mass storage
|
||||
hr
|
||||
div(class="buttons")
|
||||
button(data-force-hide-menu id="open-log-button") • Open log
|
||||
div(id="wol" class="buttons feature-disabled")
|
||||
hr
|
||||
button(disabled id="wol-wakeup-button") • Wake on LAN server
|
||||
|
||||
li(id="atx-dropdown" class="right feature-disabled")
|
||||
a(class="menu-button" href="#")
|
||||
+navbar_led("atx-power-led", "led-atx-power")
|
||||
+navbar_led("atx-hdd-led", "led-atx-hdd")
|
||||
| ATX ↴
|
||||
div(class="menu")
|
||||
div(class="buttons")
|
||||
button(disabled id="atx-power-button") • Click Power #[sup #[i short]]
|
||||
button(disabled id="atx-power-button-long") • Click Power #[sup #[i long]]
|
||||
hr
|
||||
button(disabled id="atx-reset-button") • Click Reset
|
||||
|
||||
li(id="msd-dropdown" class="right feature-disabled")
|
||||
a(class="menu-button" href="#")
|
||||
+navbar_led("msd-led", "led-msd")
|
||||
| Mass Storage ↴
|
||||
div(data-dont-hide-menu id="msd-menu" class="menu")
|
||||
div(id="msd-message-offline" class="hidden")
|
||||
+navbar_message("warning", "Mass Storage Device is offline")
|
||||
hr
|
||||
div(id="msd-message-image-broken" class="hidden")
|
||||
+navbar_message("warning", "Current image is broken!")
|
||||
| Perhaps uploading was interrupted
|
||||
hr
|
||||
div(id="msd-message-too-big-for-cdrom" class="hidden")
|
||||
+navbar_message("warning", "Current image is too big for CD-ROM!")
|
||||
| The device filesystem will be truncated to 2.2GiB
|
||||
hr
|
||||
div(id="msd-message-out-of-storage" class="hidden")
|
||||
+navbar_message("warning", "Current image is out of storag")
|
||||
| This image was connected manually using #[b kvmd-otgmsd]
|
||||
hr
|
||||
div(id="msd-message-another-user-uploads" class="hidden")
|
||||
+navbar_message("info", "Another user uploads an image")
|
||||
hr
|
||||
table(class="kv")
|
||||
tr
|
||||
td Status:
|
||||
td(id="msd-status" class="value")
|
||||
hr
|
||||
table(class="kv msd-single-storage feature-disabled")
|
||||
tr
|
||||
td Current image:
|
||||
td(id="msd-image-name" class="value")
|
||||
tr
|
||||
td Image size:
|
||||
td(id="msd-image-size" class="value")
|
||||
tr
|
||||
td Storage size:
|
||||
td(id="msd-storage-size" class="value")
|
||||
table(class="kv msd-multi-storage feature-disabled")
|
||||
tr
|
||||
td Image:
|
||||
td(width="100%") #[select(disabled id="msd-image-selector")]
|
||||
td #[button(disabled id="msd-remove-image") Remove]
|
||||
table(class="kv msd-multi-storage feature-disabled")
|
||||
tr(class="msd-cdrom-emulation feature-disabled")
|
||||
td Emulate CD-ROM drive:
|
||||
td
|
||||
+switch("msd-emulate-cdrom-checkbox")
|
||||
div(class="msd-multi-storage feature-disabled")
|
||||
hr
|
||||
div(class="text")
|
||||
div(id="msd-storage-progress" class="progress")
|
||||
span(id="msd-storage-progress-value" class="progress-value")
|
||||
hr
|
||||
input(type="file" id="msd-select-new-image-file" class="hidden")
|
||||
div(class="buttons buttons-row")
|
||||
button(disabled id="msd-select-new-image-button" class="row50") Upload new image
|
||||
button(disabled id="msd-upload-new-image-button" class="row25") Start
|
||||
button(disabled id="msd-abort-uploading-button" class="row25") Abort
|
||||
hr
|
||||
div(id="msd-submenu-new-image" class="hidden")
|
||||
table(class="kv")
|
||||
tr
|
||||
td New image:
|
||||
td(id="msd-new-image-name" class="value")
|
||||
tr
|
||||
td Upload size:
|
||||
td(id="msd-new-image-size" class="value")
|
||||
hr
|
||||
div(class="text")
|
||||
div(id="msd-uploading-progress" class="progress")
|
||||
span(id="msd-uploading-progress-value" class="progress-value")
|
||||
hr
|
||||
div(class="buttons buttons-row")
|
||||
button(disabled data-force-hide-menu id="msd-connect-button" class="row50") • Connect drive to Server
|
||||
button(disabled data-force-hide-menu id="msd-disconnect-button" class="row50") • Disconnect drive
|
||||
|
||||
li(class="right")
|
||||
a(class="menu-button" href="#")
|
||||
+navbar_led("hid-recorder-led", "led-gear")
|
||||
| Macro ↴
|
||||
div(data-dont-hide-menu class="menu")
|
||||
div(class="text")
|
||||
b Record and play keyboard & mouse actions#[br]
|
||||
sub For security reasons, the record will not saved on Pi-KVM
|
||||
div(class="buttons buttons-row")
|
||||
button(disabled data-force-hide-menu id="hid-recorder-record" class="row25") • Rec
|
||||
button(disabled id="hid-recorder-stop" class="row25") Stop
|
||||
button(disabled id="hid-recorder-play" class="row25") Play
|
||||
button(disabled id="hid-recorder-clear" class="row25") Clear
|
||||
hr
|
||||
table(class="kv")
|
||||
tr
|
||||
td Script time:
|
||||
td(colspan="2" id="hid-recorder-time" class="value") 00:00:00.0
|
||||
tr
|
||||
td Scripted events:
|
||||
td(id="hid-recorder-events-count" class="value") 0
|
||||
td #[sup #[i include delays]]
|
||||
hr
|
||||
input(type="file" id="hid-recorder-new-script-file")
|
||||
div(class="buttons buttons-row")
|
||||
button(disabled id="hid-recorder-upload" class="row50") Upload script
|
||||
button(disabled id="hid-recorder-download" class="row50") Download script
|
||||
|
||||
li(class="right")
|
||||
a(class="menu-button" href="#") Shortcuts ↴
|
||||
div(data-dont-hide-menu class="menu")
|
||||
div(class="buttons")
|
||||
textarea(id="hid-pak-text" placeholder="Paste your text here")
|
||||
hr
|
||||
button(disabled data-force-hide-menu id="hid-pak-button") • ↳ Paste-as-Keys #[sup #[i ascii-only]]
|
||||
hr
|
||||
div(class="buttons-row")
|
||||
button(data-force-hide-menu data-shortcut="CapsLock" class="row50")
|
||||
| • Caps Lock
|
||||
img(class="inline-lamp hid-keyboard-caps-led led-gray" src=`${svg_dir}/led-square.svg`)
|
||||
button(data-force-hide-menu data-shortcut="MetaLeft" class="row50") • Left Win
|
||||
hr
|
||||
button(data-force-hide-menu data-shortcut="AltLeft ShiftLeft") • Alt+Shift
|
||||
button(data-force-hide-menu data-shortcut="ControlLeft ShiftLeft") • Ctrl+Shift
|
||||
button(data-force-hide-menu data-shortcut="ShiftLeft ShiftRight") • Shift+Shift
|
||||
button(data-force-hide-menu data-shortcut="MetaLeft Space") • Win+Space
|
||||
hr
|
||||
button(data-force-hide-menu data-shortcut="ControlLeft KeyW") • Ctrl+W
|
||||
button(data-force-hide-menu data-shortcut="AltLeft Tab") • Alt+Tab
|
||||
button(data-force-hide-menu data-shortcut="AltLeft Enter") • Alt+Enter
|
||||
button(data-force-hide-menu data-shortcut="AltLeft F4") • Alt+F4
|
||||
hr
|
||||
button(data-force-hide-menu data-shortcut="ControlLeft AltLeft Delete") • Ctrl+Alt+Del
|
||||
hr
|
||||
div(class="text")
|
||||
| ↓ Alt+SysRq+... <sup><i>linux magic
|
||||
| #[a(target="_blank" href="https://www.kernel.org/doc/html/latest/admin-guide/sysrq.html") help]</i></sup>
|
||||
hr
|
||||
div(class="buttons")
|
||||
div(class="buttons-row")
|
||||
each key in ["R", "E", "I", "S", "U", "B"]
|
||||
button(data-shortcut=`AltLeft PrintScreen Key${key}` class="row16") #{key}
|
||||
58
web/kvm/window-about.pug
Normal file
58
web/kvm/window-about.pug
Normal file
@ -0,0 +1,58 @@
|
||||
+window("about-window", "About", true, false)
|
||||
div(id="about")
|
||||
table
|
||||
tr
|
||||
td(valign="top" class="logo")
|
||||
img(class="svg-gray" src="../share/svg/logo.svg" alt="Open Source Hardware" height="40")
|
||||
td(valign="top")
|
||||
table
|
||||
tr #[td(colspan="2" class="title") Open Source & Open Hardware IP-KVM]
|
||||
tr #[td(colspan="2" class="copyright") Copyright © 2018 Pi-KVM Developers Team]
|
||||
br
|
||||
div(class="tabs")
|
||||
each tab, index in ["Meta", "Hardware", "Version", "Thanks"]
|
||||
- tab_id = `about-tab-${tab != "Hardware" ? tab.toLowerCase() : "hw"}-button`
|
||||
if index == 0
|
||||
input(checked type="radio" name="about-tab-button" id=tab_id)
|
||||
else
|
||||
input(type="radio" name="about-tab-button" id=tab_id)
|
||||
label(for=tab_id) #{tab}
|
||||
each tab in ["meta", "hw", "version"]
|
||||
div(id=`about-tab-${tab}-content`)
|
||||
div(id=`about-${tab}` class="code") #[span(class="code-comment") No data]
|
||||
div(id="about-tab-thanks-content")
|
||||
div(id="about-thanks" class="code")
|
||||
span(class="code-comment")
|
||||
| // These kind people donated money to the Pi-KVM project#[br]
|
||||
| // and supported the work on it. We are very grateful#[br]
|
||||
| // for their help, and memorializing their names#[br]
|
||||
| // is the least we can do in gratitude.#[br]
|
||||
| // If you also want to support this project,#[br]
|
||||
| // you can use one of these services:
|
||||
| #[a(target="_blank" href="https://www.patreon.com/pikvm") Patreon]
|
||||
| or #[a(target="_blank" href="https://www.paypal.me/mdevaev") PayPal].
|
||||
ul
|
||||
li Aleksei Brusianskii
|
||||
li Arthur Woimbée
|
||||
li Ben Gordon
|
||||
li Branden Shaulis
|
||||
li Christof Maluck
|
||||
li Corey Lista
|
||||
li David Howell
|
||||
li Denis Yatsenko
|
||||
li Ge Men
|
||||
li Grey Cynic
|
||||
li Jason Toland
|
||||
li Jeff Bowman
|
||||
li John McGovern
|
||||
li Mark Gilbert
|
||||
li Mark Robinson
|
||||
li Mauricio Allende
|
||||
li Michael Lynch
|
||||
li Samed Ozoglu
|
||||
li Truman Kilen
|
||||
li Walter_Ego
|
||||
br
|
||||
p(class="text")
|
||||
| Full documentation, source code, hardware schematics and legal information
|
||||
| can be found in our #[a(target="_blank" href="https://pikvm.org") official website].
|
||||
157
web/kvm/window-keyboard.pug
Normal file
157
web/kvm/window-keyboard.pug
Normal file
@ -0,0 +1,157 @@
|
||||
mixin key(code, classes="", width=0)
|
||||
div(data-code=code, class=`key ${classes}`, style=(width ? `width:${width}px` : ""))
|
||||
div(class="label")
|
||||
block
|
||||
|
||||
mixin modifier(code, classes="", width=0)
|
||||
div(data-code=code class=`modifier ${classes}` style=(width ? `width:${width}px` : ""))
|
||||
div(class="label")
|
||||
| #[b •]#[br]
|
||||
block
|
||||
|
||||
mixin empty_key(width=0)
|
||||
div(class="empty-key" style=(width ? `width:${width}px` : ""))
|
||||
|
||||
mixin lamp(cls)
|
||||
img(class=`inline-lamp ${cls} led-gray` src=`${svg_dir}/led-square.svg`)
|
||||
|
||||
+window("keyboard-window", "Virtual Keyboard", true, true)
|
||||
div(id="keyboard-desktop" class="keypad" align="center")
|
||||
div(class="keypad-block")
|
||||
div(class="keypad-row")
|
||||
+key("Escape", "small") Esc
|
||||
+empty_key(24)
|
||||
each key in ["F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12"]
|
||||
+key(key, "small") #{key}
|
||||
if key == "F4" || key == "F8"
|
||||
+empty_key(10)
|
||||
hr
|
||||
div(class="keypad-row")
|
||||
+key("Backquote") ~#[br]`
|
||||
each key, index in ["!", "@", "#", "$", "%", "^", "&", "*", "("]
|
||||
+key(`Digit${index + 1}`) #{key}#[br]#{index + 1}
|
||||
+key("Digit0") )#[br]0
|
||||
+key("Minus") _#[br]-
|
||||
+key("Equal") +#[br]=
|
||||
+key("Backspace", "wide-2 right") ↤
|
||||
div(class="keypad-row")
|
||||
+key("Tab", "wide-2 left") ⇤#[br]⇥
|
||||
each key in ["Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P"]
|
||||
+key(`Key${key}`, "single") #{key}
|
||||
+key("BracketLeft") {#[br][
|
||||
+key("BracketRight") }#[br]]
|
||||
+key("Backslash") |#[br]\
|
||||
div(class="keypad-row")
|
||||
+key("CapsLock", "wide-3 left small")
|
||||
+lamp("hid-keyboard-caps-led")
|
||||
| #[br] Caps Lock
|
||||
each key in ["A", "S", "D", "F", "G", "H", "J", "K", "L"]
|
||||
+key(`Key${key}`, "single") #{key}
|
||||
+key("Semicolon") :#[br];
|
||||
+key("Quote") "#[br]'
|
||||
+key("Enter", "wide-3 right small") Enter#[br]↵
|
||||
div(class="keypad-row")
|
||||
+modifier("ShiftLeft", "wide-4 left small") Shift
|
||||
each key in ["Z", "X", "C", "V", "B", "N", "M"]
|
||||
+key(`Key${key}`, "single") #{key}
|
||||
+key("Comma") <#[br],
|
||||
+key("Period") >#[br].
|
||||
+key("Slash") ?#[br]/
|
||||
+modifier("ShiftRight", "wide-4 right small") Shift
|
||||
div(class="keypad-row")
|
||||
+modifier("ControlLeft", "wide-1 left small") Ctrl
|
||||
+modifier("MetaLeft", "wide-1 left small") Win
|
||||
+modifier("AltLeft", "wide-1 left small") Alt
|
||||
+key("Space", "wide-5")
|
||||
+modifier("AltRight", "wide-1 right small") Alt
|
||||
+modifier("MetaRight", "wide-1 right small") Win
|
||||
+modifier("ControlRight", "wide-1 right small") Ctrl
|
||||
div(class="keypad-block")
|
||||
div(class="keypad-row")
|
||||
+modifier("PrintScreen", "small") Pt/Sq
|
||||
+key("ScrollLock", "small")
|
||||
+lamp("hid-keyboard-scroll-led")
|
||||
| #[br] ScrLk
|
||||
+key("Pause", "small") P/Brk
|
||||
hr
|
||||
div(class="keypad-row")
|
||||
+key("Insert", "small") Ins
|
||||
+key("Home", "small") Home
|
||||
+key("PageUp", "small") PgUp
|
||||
div(class="keypad-row")
|
||||
+key("Delete", "small") Del
|
||||
+key("End", "small") End
|
||||
+key("PageDown", "small") PgDn
|
||||
div(class="keypad-row")
|
||||
div(class="keypad-row")
|
||||
+empty_key()
|
||||
+key("ArrowUp") ↑
|
||||
+empty_key()
|
||||
div(class="keypad-row")
|
||||
+key("ArrowLeft") ←
|
||||
+key("ArrowDown") ↓
|
||||
+key("ArrowRight") →
|
||||
|
||||
div(id="keyboard-mobile" class="keypad" align="center")
|
||||
div(class="keypad-block")
|
||||
div(class="keypad-row")
|
||||
+key("Escape", "margin-0 small") Esc
|
||||
+empty_key(1)
|
||||
each key in ["F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12"]
|
||||
+key(key, "wide-0 margin-0 small") #{key}
|
||||
+empty_key(2)
|
||||
+modifier("PrintScreen", "margin-0 small") Pt/Sq
|
||||
+key("ScrollLock", "margin-0 small")
|
||||
+lamp("hid-keyboard-scroll-led")
|
||||
| #[br] ScrLk
|
||||
+key("Pause", "margin-0 small") P/Brk
|
||||
+key("Insert", "margin-0 small") Ins
|
||||
+key("Home", "margin-0 small") Home
|
||||
+key("End", "margin-0 small") End
|
||||
+key("Delete", "margin-0 small") Del
|
||||
div(class="keypad-row")
|
||||
+key("Backquote") ~#[br]`
|
||||
each key, index in ["!", "@", "#", "$", "%", "^", "&", "*", "("]
|
||||
+key(`Digit${index + 1}`) #{key}#[br]#{index + 1}
|
||||
+key("Digit0") )#[br]0
|
||||
+key("Minus") _#[br]-
|
||||
+key("Equal") +#[br]=
|
||||
+key("Backspace", "wide-3 right", 101) ↤
|
||||
div(class="keypad-row")
|
||||
+key("Tab", "wide-2 left") ⇤<br>⇥
|
||||
each key in ["Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P"]
|
||||
+key(`Key${key}`, "single") #{key}
|
||||
+key("BracketLeft") {#[br][
|
||||
+key("BracketRight") }#[br]]
|
||||
+key("Backslash", "wide-2 left", 78) |#[br]\
|
||||
div(class="keypad-row")
|
||||
+key("CapsLock", "wide-3 left small")
|
||||
+lamp("hid-keyboard-caps-led")
|
||||
| #[br] Caps Lock
|
||||
each key in ["A", "S", "D", "F", "G", "H", "J", "K", "L"]
|
||||
+key(`Key${key}`, "single") #{key}
|
||||
+key("Semicolon") :#[br];
|
||||
+key("Quote") `#[br]'
|
||||
+key("Enter", "wide-4 right small", 116) Enter#[br]↵
|
||||
div(class="keypad-row")
|
||||
+modifier("ShiftLeft", "wide-4 left small") Shift
|
||||
each key in ["Z", "X", "C", "V", "B", "N", "M"]
|
||||
+key(`Key${key}`, "single") #{key}
|
||||
+key("Comma") lt;#[br],
|
||||
+key("Period") >#[br].
|
||||
+key("Slash") ?#[br]/
|
||||
+key("PageUp", "small") PgUp
|
||||
+key("ArrowUp") ↑
|
||||
+key("PageDown", "small") PgDn
|
||||
div(class="keypad-row")
|
||||
+modifier("ControlLeft", "wide-1 left small") Ctrl
|
||||
+modifier("MetaLeft", "wide-1 left small") Win
|
||||
+modifier("AltLeft", "wide-1 left small") Alt
|
||||
+key("Space", "", 190)
|
||||
+modifier("AltRight", "right small") Alt
|
||||
+modifier("MetaRight", "right small") Win
|
||||
+modifier("ShiftRight", "right small") Shift
|
||||
+modifier("ControlRight", "right small") Ctrl
|
||||
+key("ArrowLeft") ←
|
||||
+key("ArrowDown") ↓
|
||||
+key("ArrowRight") →
|
||||
15
web/kvm/window-stream.pug
Normal file
15
web/kvm/window-stream.pug
Normal file
@ -0,0 +1,15 @@
|
||||
+window("stream-window", "Stream", false, true)
|
||||
div(id="stream-info")
|
||||
div(id="stream-box" class="stream-box-inactive")
|
||||
img(id="stream-image" class="stream-image-inactive" src=`${png_dir}/blank-stream.png`)
|
||||
div(id="stream-mouse-buttons" class="keypad" align="center")
|
||||
div(class="keypad-block")
|
||||
div(class="keypad-row")
|
||||
div(data-code="left" class="key wide-4 left small") #[span Mouse#[br]Left]
|
||||
div(data-code="left" class="modifier wide-2 left small") #[span #[b •]#[br]← Hold]
|
||||
div(class="empty-key" style="width:10px")
|
||||
div(data-code="middle" class="key wide-2 left small") #[span Mouse#[br]Middle]
|
||||
div(data-code="middle" class="modifier wide-2 left small") #[span #[b •]#[br]← Hold]
|
||||
div(class="empty-key" style="width:10px")
|
||||
div(data-code="right" class="modifier wide-2 right small") #[span #[b •]#[br]Hold →]
|
||||
div(data-code="right" class="key wide-4 right small") #[span Mouse#[br]Right]
|
||||
11
web/kvm/windows.pug
Normal file
11
web/kvm/windows.pug
Normal file
@ -0,0 +1,11 @@
|
||||
mixin window(id, title, closeable=true, with_header_id=false)
|
||||
div(id=id class="window")
|
||||
div(id=(with_header_id ? `${id}-header` : "") class="window-header" style=(closeable ? "" : "z-index:1"))
|
||||
div(class="window-grab") #{title}
|
||||
if closeable
|
||||
button(class="window-button-close") ×
|
||||
block
|
||||
|
||||
include window-stream.pug
|
||||
include window-keyboard.pug
|
||||
include window-about.pug
|
||||
@ -20,12 +20,12 @@
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
ul#menu {
|
||||
ul#navbar {
|
||||
box-shadow: var(--shadow-small);
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: var(--cs-menu-default-bg);
|
||||
background-color: var(--cs-navbar-default-bg);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
@ -33,107 +33,107 @@ ul#menu {
|
||||
z-index: 2147483646;
|
||||
}
|
||||
|
||||
ul#menu li.menu-right-items {
|
||||
border-left: var(--border-menu-thin);
|
||||
ul#navbar li.right {
|
||||
border-left: var(--border-navbar-item-thin);
|
||||
float: right;
|
||||
}
|
||||
|
||||
ul#menu li.menu-left-items {
|
||||
border-right: var(--border-menu-thin);
|
||||
ul#navbar li.left {
|
||||
border-right: var(--border-navbar-item-thin);
|
||||
float: left;
|
||||
}
|
||||
|
||||
ul#menu li a#menu-logo {
|
||||
ul#navbar li a#logo {
|
||||
line-height: 50px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
color: var(--cs-menu-default-fg);
|
||||
color: var(--cs-navbar-default-fg);
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
ul#menu li a.menu-item img {
|
||||
ul#navbar li a.menu-button {
|
||||
line-height: 50px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
color: var(--cs-navbar-default-fg);
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
ul#navbar li a#logo:hover:not(.active),
|
||||
ul#navbar li a.menu-button:hover:not(.active) {
|
||||
background-color: var(--cs-navbar-item-hovered-bg);
|
||||
}
|
||||
@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) {
|
||||
/* iPad 8 */
|
||||
ul#navbar li a#menu-button:hover:not(.active),
|
||||
ul#navbar li a.menu-button:hover:not(.active) {
|
||||
background-color: var(--cs-navbar-default-bg) !important;
|
||||
}
|
||||
}
|
||||
|
||||
ul#navbar li a#logo img {
|
||||
margin-top: -2px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
ul#navbar li a.menu-button img {
|
||||
vertical-align: middle;
|
||||
margin-right: 10px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
ul#menu li a#menu-logo img {
|
||||
margin-top: -2px;
|
||||
height: 24px;
|
||||
ul#navbar li a.menu-button-pressed {
|
||||
box-shadow: var(--shadow-navbar-item-pressed);
|
||||
background-color: var(--cs-navbar-item-pressed-bg) !important;
|
||||
}
|
||||
|
||||
ul#menu li a.menu-item {
|
||||
line-height: 50px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
color: var(--cs-menu-default-fg);
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
ul#menu li a#menu-logo:hover:not(.active),
|
||||
ul#menu li a.menu-item:hover:not(.active) {
|
||||
background-color: var(--cs-menu-hovered-bg);
|
||||
}
|
||||
@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) {
|
||||
/* iPad 8 */
|
||||
ul#menu li a#menu-item:hover:not(.active),
|
||||
ul#menu li a.menu-item:hover:not(.active) {
|
||||
background-color: var(--cs-menu-default-bg) !important;
|
||||
}
|
||||
}
|
||||
|
||||
ul#menu li a.menu-item-selected {
|
||||
box-shadow: var(--shadow-menu-pressed);
|
||||
background-color: var(--cs-menu-pressed-bg) !important;
|
||||
}
|
||||
|
||||
ul#menu li div.menu-item-content {
|
||||
ul#navbar li div.menu {
|
||||
visibility: hidden;
|
||||
outline: none;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
border: var(--border-menu-item-content-default-2px);
|
||||
border-top: var(--border-menu-item-content-top-thin);
|
||||
border: var(--border-navbar-menu-default-2px);
|
||||
border-top: var(--border-navbar-menu-top-thin);
|
||||
border-radius: 0 0 8px 8px;
|
||||
position: absolute;
|
||||
background-color: var(--cs-menu-default-bg);
|
||||
background-color: var(--cs-navbar-default-bg);
|
||||
min-width: 180px;
|
||||
box-shadow: var(--shadow-big);
|
||||
z-index: 2147483645;
|
||||
}
|
||||
ul#menu li div.menu-item-content-active {
|
||||
border: var(--border-menu-item-content-active-2px) !important;
|
||||
border-top: var(--border-menu-item-content-top-thin) !important;
|
||||
ul#navbar li div.menu-active {
|
||||
border: var(--border-navbar-menu-active-2px) !important;
|
||||
border-top: var(--border-navbar-menu-top-thin) !important;
|
||||
}
|
||||
|
||||
ul#menu li div.menu-item-content-buttons {
|
||||
ul#navbar li div.menu div.buttons {
|
||||
background-color: var(--cs-control-default-bg);
|
||||
}
|
||||
|
||||
ul#menu li div.menu-item-content-text {
|
||||
ul#navbar li div.menu div.text {
|
||||
margin: 10px 15px 10px 15px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
ul#menu li div.menu-item-content-text table.one-line-switch {
|
||||
ul#navbar li div.menu div.text table.one-line-switch {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
@media only screen and (min-width: 768px) and (max-width: 1024px) and (orientation: portrait) {
|
||||
@supports (-webkit-appearance: none) {
|
||||
ul#menu li div.menu-item-content-text table.one-line-switch {
|
||||
ul#navbar li div.menu div.text table.one-line-switch {
|
||||
margin: 20px 0 20px 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ul#menu li div.menu-item-content table.menu-item-content-kv {
|
||||
ul#navbar li div.menu table.kv {
|
||||
-webkit-user-select: text;
|
||||
-moz-user-select: text;
|
||||
user-select: text;
|
||||
@ -141,14 +141,14 @@ ul#menu li div.menu-item-content table.menu-item-content-kv {
|
||||
margin: 0 10px 0 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
ul#menu li div.menu-item-content table.menu-item-content-kv td.value {
|
||||
ul#navbar li div.menu table.kv td.value {
|
||||
font-weight: bold;
|
||||
max-width: 310px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
ul#menu li div.menu-item-content-buttons button,
|
||||
ul#menu li div.menu-item-content-buttons select {
|
||||
ul#navbar li div.menu div.buttons button,
|
||||
ul#navbar li div.menu div.buttons select {
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
@ -156,7 +156,7 @@ ul#menu li div.menu-item-content-buttons select {
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
ul#menu li div.menu-item-content hr {
|
||||
ul#navbar li div.menu hr {
|
||||
margin: 0;
|
||||
display: block;
|
||||
height: 0px;
|
||||
@ -165,7 +165,7 @@ ul#menu li div.menu-item-content hr {
|
||||
border-top: var(--border-control-thin);
|
||||
}
|
||||
|
||||
ul#menu li div.menu-item-content img.sign {
|
||||
ul#navbar li div.menu img.sign {
|
||||
vertical-align: middle;
|
||||
margin-right: 10px;
|
||||
height: 20px;
|
||||
@ -34,10 +34,10 @@
|
||||
--cs-control-pressed-fg: #6c7481;
|
||||
--cs-control-disabled-fg: #6c7481;
|
||||
|
||||
--cs-menu-default-bg: #202225;
|
||||
--cs-menu-default-fg: #c3c3c3;
|
||||
--cs-menu-hovered-bg: #1a1c1f;
|
||||
--cs-menu-pressed-bg: #171717;
|
||||
--cs-navbar-default-bg: #202225;
|
||||
--cs-navbar-default-fg: #c3c3c3;
|
||||
--cs-navbar-item-hovered-bg: #1a1c1f;
|
||||
--cs-navbar-item-pressed-bg: #171717;
|
||||
|
||||
--cs-window-default-bg: #484b51;
|
||||
--cs-window-default-fg: #c3c3c3;
|
||||
@ -69,18 +69,18 @@
|
||||
--shadow-micro: 1px 2px 4px 0 rgba(0, 0, 0, 0.4);
|
||||
--shadow-small: 0 2px 4px 0 rgba(0, 0, 0, 0.2);
|
||||
--shadow-big: 0 8px 16px 0 rgba(0, 0, 0, 0.4);
|
||||
--shadow-menu-pressed: 0 5px 0 #5b90bb inset;
|
||||
--shadow-navbar-item-pressed: 0 5px 0 #5b90bb inset;
|
||||
|
||||
--border-default-thin: thin solid #36393f;
|
||||
--border-default-2px: 2px solid #36393f;
|
||||
--border-menu-thin: thin solid black;
|
||||
--border-navbar-item-thin: thin solid black;
|
||||
--border-control-thin: thin solid #17191d;
|
||||
--border-window-thin: thin solid #17191d;
|
||||
--border-key-thin: thin solid #202225;
|
||||
--border-intensive-2px: 2px solid #5b90bb;
|
||||
--border-intensive-thin: thin solid #5b90bb;
|
||||
|
||||
--border-menu-item-content-default-2px: 2px solid black;
|
||||
--border-menu-item-content-active-2px: 2px solid #5b90bb;
|
||||
--border-navbar-menu-default-2px: 2px solid black;
|
||||
--border-navbar-menu-active-2px: 2px solid #5b90bb;
|
||||
--border-menu-item-content-top-thin: thin solid #17191d;
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@ function __WindowManager() {
|
||||
|
||||
var __top_z_index = 0;
|
||||
var __windows = [];
|
||||
var __menu_items = [];
|
||||
var __menu_buttons = [];
|
||||
|
||||
var __init__ = function() {
|
||||
for (let el_button of $$$("button")) {
|
||||
@ -48,10 +48,10 @@ function __WindowManager() {
|
||||
el_button.ontouchstart = function() {};
|
||||
}
|
||||
|
||||
for (let el_item of $$("menu-item")) {
|
||||
el_item.parentElement.querySelector(".menu-item-content").setAttribute("tabindex", "-1");
|
||||
tools.setOnDown(el_item, () => __toggleMenu(el_item));
|
||||
__menu_items.push(el_item);
|
||||
for (let el_button of $$("menu-button")) {
|
||||
el_button.parentElement.querySelector(".menu").setAttribute("tabindex", "-1");
|
||||
tools.setOnDown(el_button, () => __toggleMenu(el_button));
|
||||
__menu_buttons.push(el_button);
|
||||
}
|
||||
|
||||
for (let el_window of $$("window")) {
|
||||
@ -161,7 +161,7 @@ function __WindowManager() {
|
||||
let el_to_focus = (
|
||||
el.closest(".modal-window")
|
||||
|| el.closest(".window")
|
||||
|| el.closest(".menu-item-content")
|
||||
|| el.closest(".menu")
|
||||
);
|
||||
if (el_to_focus) {
|
||||
el_to_focus.focus();
|
||||
@ -182,9 +182,9 @@ function __WindowManager() {
|
||||
};
|
||||
|
||||
self.getViewGeometry = function() {
|
||||
let el_menu = $("menu");
|
||||
let el_navbar = $("navbar");
|
||||
return {
|
||||
top: (el_menu ? el_menu.clientHeight : 0), // Menu height
|
||||
top: (el_navbar ? el_navbar.clientHeight : 0), // Navbar height
|
||||
bottom: Math.max(document.documentElement.clientHeight, window.innerHeight || 0),
|
||||
left: 0,
|
||||
right: Math.max(document.documentElement.clientWidth, window.innerWidth || 0),
|
||||
@ -194,15 +194,15 @@ function __WindowManager() {
|
||||
var __toggleMenu = function(el_a) {
|
||||
let all_hidden = true;
|
||||
|
||||
for (let el_item of __menu_items) {
|
||||
let el_menu = el_item.parentElement.querySelector(".menu-item-content");
|
||||
if (el_item === el_a && window.getComputedStyle(el_menu, null).visibility === "hidden") {
|
||||
el_item.classList.add("menu-item-selected");
|
||||
for (let el_button of __menu_buttons) {
|
||||
let el_menu = el_button.parentElement.querySelector(".menu");
|
||||
if (el_button === el_a && window.getComputedStyle(el_menu, null).visibility === "hidden") {
|
||||
el_button.classList.add("menu-button-pressed");
|
||||
el_menu.style.visibility = "visible";
|
||||
el_menu.focus();
|
||||
all_hidden &= false;
|
||||
} else {
|
||||
el_item.classList.remove("menu-item-selected");
|
||||
el_button.classList.remove("menu-button-pressed");
|
||||
el_menu.style.visibility = "hidden";
|
||||
}
|
||||
}
|
||||
@ -223,9 +223,9 @@ function __WindowManager() {
|
||||
|
||||
var __closeAllMenues = function() {
|
||||
document.onkeyup = null;
|
||||
for (let el_item of __menu_items) {
|
||||
let el_menu = el_item.parentElement.querySelector(".menu-item-content");
|
||||
el_item.classList.remove("menu-item-selected");
|
||||
for (let el_button of __menu_buttons) {
|
||||
let el_menu = el_button.parentElement.querySelector(".menu");
|
||||
el_button.classList.remove("menu-button-pressed");
|
||||
el_menu.style.visibility = "hidden";
|
||||
}
|
||||
};
|
||||
@ -236,8 +236,8 @@ function __WindowManager() {
|
||||
el_parent.classList.add("window-active");
|
||||
} else if ((el_parent = event.target.closest(".window")) !== null) {
|
||||
el_parent.classList.add("window-active");
|
||||
} else if ((el_parent = event.target.closest(".menu-item-content")) !== null) {
|
||||
el_parent.classList.add("menu-item-content-active");
|
||||
} else if ((el_parent = event.target.closest(".menu")) !== null) {
|
||||
el_parent.classList.add("menu-active");
|
||||
}
|
||||
tools.debug("Focus in:", el_parent);
|
||||
};
|
||||
@ -248,14 +248,14 @@ function __WindowManager() {
|
||||
el_parent.classList.remove("window-active");
|
||||
} else if ((el_parent = event.target.closest(".window")) !== null) {
|
||||
el_parent.classList.remove("window-active");
|
||||
} else if ((el_parent = event.target.closest(".menu-item-content")) !== null) {
|
||||
el_parent.classList.remove("menu-item-content-active");
|
||||
} else if ((el_parent = event.target.closest(".menu")) !== null) {
|
||||
el_parent.classList.remove("menu-active");
|
||||
}
|
||||
tools.debug("Focus out:", el_parent);
|
||||
};
|
||||
|
||||
var __globalMouseButtonHandler = function(event) {
|
||||
if (!event.target.matches(".menu-item")) {
|
||||
if (!event.target.matches(".menu-button")) {
|
||||
for (let el_item = event.target; el_item && el_item !== document; el_item = el_item.parentNode) {
|
||||
if (el_item.hasAttribute("data-force-hide-menu")) {
|
||||
break;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user