From 46a59d377e9a13d4a0c70f13aef14d9ec2d6d68e Mon Sep 17 00:00:00 2001 From: arc Date: Mon, 13 Jan 2025 10:59:07 -0700 Subject: [PATCH] add stuff --- new/apps/web/src/routes/+page.server.ts | 8 + new/apps/web/static/static/css/backup.css | 1071 +++++++++++++++++ .../web/static/static/css/doom-scroll.css | 377 ++++++ new/apps/web/static/static/css/landing.css | 69 ++ new/apps/web/static/static/css/main.css | 1052 ++++++++++++++++ new/apps/web/static/static/css/tables.css | 95 ++ new/apps/web/static/static/css/themes.css | 80 ++ new/apps/web/static/static/js/common.js | 104 ++ new/apps/web/static/static/js/doom-scroll.js | 324 +++++ new/apps/web/static/static/js/konami.js | 186 +++ new/apps/web/static/static/js/main.js | 238 ++++ new/apps/web/static/static/js/redir.js | 6 + new/apps/web/static/static/js/tables.js | 817 +++++++++++++ new/apps/web/static/static/js/themes.js | 21 + new/apps/web/static/static/js/upload.js | 56 + 15 files changed, 4504 insertions(+) create mode 100644 new/apps/web/src/routes/+page.server.ts create mode 100755 new/apps/web/static/static/css/backup.css create mode 100644 new/apps/web/static/static/css/doom-scroll.css create mode 100755 new/apps/web/static/static/css/landing.css create mode 100755 new/apps/web/static/static/css/main.css create mode 100644 new/apps/web/static/static/css/tables.css create mode 100644 new/apps/web/static/static/css/themes.css create mode 100644 new/apps/web/static/static/js/common.js create mode 100644 new/apps/web/static/static/js/doom-scroll.js create mode 100644 new/apps/web/static/static/js/konami.js create mode 100755 new/apps/web/static/static/js/main.js create mode 100644 new/apps/web/static/static/js/redir.js create mode 100644 new/apps/web/static/static/js/tables.js create mode 100644 new/apps/web/static/static/js/themes.js create mode 100755 new/apps/web/static/static/js/upload.js diff --git a/new/apps/web/src/routes/+page.server.ts b/new/apps/web/src/routes/+page.server.ts new file mode 100644 index 0000000..a2829a5 --- /dev/null +++ b/new/apps/web/src/routes/+page.server.ts @@ -0,0 +1,8 @@ +import { type ServerLoad } from "@sveltejs/kit"; + +export const prerender = false; + +export const load: ServerLoad = async ({ fetch }) => { + const res = await fetch('http://localhost:8080/widgets.php?file=files/test1.json'); + return {widgetResponse: await res.text()}; +}; \ No newline at end of file diff --git a/new/apps/web/static/static/css/backup.css b/new/apps/web/static/static/css/backup.css new file mode 100755 index 0000000..177c7be --- /dev/null +++ b/new/apps/web/static/static/css/backup.css @@ -0,0 +1,1071 @@ +@import url(https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;700&display=swap); + +html { + background-color: #3B4252!important; + color-scheme: dark +} + +body { + background-color: #3B4252!important; + color: #e0e2e4; + font-family: JetBrains Mono, monospace; + font-size: 10pt; + line-height: 150%; + margin: 0 +} + +body, html { + text-size-adjust: none; + -webkit-text-size-adjust: none; + -moz-text-size-adjust: none; + -ms-text-size-adjust: none +} + +main { + flex-grow: 1; + padding: 0 20px 20px +} + +#root, main { + display: flex; + flex-direction: column; + justify-content: space-between +} + +#root { + min-height: 100vh +} + +a:active, a:hover, a:link, a:visited { + color: #f77669; + text-decoration: none +} + +a:active, a:hover { + border-bottom: 1px solid #f77669 +} + +button, input, select { + background-color: #252b2d; + border-radius: 6px; + border-style: none; + color: #ccc; + font-family: JetBrains Mono, monospace; + padding: 5px +} + +button :focus, input :focus, select :focus { + outline: none +} + +select { + -webkit-appearance: none; + appearance: none; + background-image: url(data:image/svg+xml;base64,PHN2ZyBhcmlhLWhpZGRlbj0idHJ1ZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDQ4IDUxMiI+PHBhdGggZmlsbD0iI2I1YjViNSIgZD0iTTIwNy4wMjkgMzgxLjQ3NiAxMi42ODYgMTg3LjEzMmMtOS4zNzMtOS4zNzMtOS4zNzMtMjQuNTY5IDAtMzMuOTQxbDIyLjY2Ny0yMi42NjdjOS4zNTctOS4zNTcgMjQuNTIyLTkuMzc1IDMzLjkwMS0uMDRMMjI0IDI4NC41MDVsMTU0Ljc0NS0xNTQuMDIxYzkuMzc5LTkuMzM1IDI0LjU0NC05LjMxNyAzMy45MDEuMDRsMjIuNjY3IDIyLjY2N2M5LjM3MyA5LjM3MyA5LjM3MyAyNC41NjkgMCAzMy45NDFMMjQwLjk3MSAzODEuNDc2Yy05LjM3MyA5LjM3Mi0yNC41NjkgOS4zNzItMzMuOTQyIDB6Ii8+PC9zdmc+); + background-position: 97%; + background-repeat: no-repeat; + background-size: 10px +} + +button { + cursor: pointer +} + +hr { + border: 2px solid #252b2d +} + +.text-box { + background: #252b2d; + border-radius: 6px; + color: #b5b5b5; + font-size: 130%; + letter-spacing: -1px; + margin: 12px 0; + padding: 8px +} + +header { + background: #181d1f; + box-shadow: 0 0 4px #130b00; + color: #ccc; + font-weight: 400; + gap: 10px; + justify-content: space-between; + line-height: 100%; + margin: 0; + padding: 5px 20px; + z-index: 20 +} + +header, header > .logo { + align-items: center; + display: flex +} + +header > .logo { + background-color: #252b2d; + border: 0; + border-radius: 5px; + margin: 3px 0; + padding: 3px 5px 3px 3px +} + +header > .logo > h1 { + color: #fff; + font-size: 14pt; + font-weight: 400; + margin: 0; + padding: 0 3px +} + +header img { + -webkit-filter: invert(0); + filter: invert(0); + padding-right: 5px +} + +footer { + color: #888; + font-size: 10pt; + font-weight: 400; + margin-top: 30px; + padding: 0 20px 20px; + text-align: right +} + +article { + font-size: 120%; + margin: 20px auto; + max-width: 900px +} + +article h1:before, article h2:before { + color: #ffc93a; + content: "# " +} + +.homepage-header { + background: #181d1f; + display: flex; + justify-content: center +} + +.homepage-header > div { + display: flex; + flex-grow: 1; + justify-content: space-around; + max-width: 900px; + padding: 50px 0 +} + +.homepage-header > div > img { + width: 25% +} + +.homepage-header > div > div { + display: flex; + flex-direction: column; + justify-content: center; + text-align: center; + width: 60% +} + +.homepage-header > div > div > h1 { + font-size: min(15vw, 150px); + line-height: 1em; + margin: 0 0 15px +} + +.homepage-header > div > div > div { + font-size: min(2vw, 20px); + line-height: 1.1 +} + +.homepage .link { + height: 75px +} + +.homepage .link .link-description { + font-weight: 400; + width: 280px +} + +.homepage section { + background-color: #252b2d; + border-radius: 15px; + margin: 25px 0; + padding: .1px 15px +} + +.homepage .feature { + display: flex; + gap: 20px; + margin: 30px 0; + padding-left: 20px +} + +.homepage .feature > svg { + color: #7e7e7e; + font-size: 70px; + margin: auto 0 +} + +.homepage .feature > div { + max-width: 70% +} + +.homepage .feature > div h3 { + color: #ffc93a; + margin: 0 +} + +.downloads .version-number { + color: #f77669; + font-size: larger; + font-weight: 700 +} + +.downloads h3 > span { + color: #888; + font-size: 75% +} + +.downloads .link-description { + width: 250px +} + +.link { + align-items: center; + background-color: #252b2d; + border-radius: 15px; + display: flex; + gap: 15px; + height: 95px; + justify-content: space-between; + margin: 10px 0; + padding: 0 15px +} + +.link:link, .link:visited { + border-bottom: none; + color: #ccc +} + +.link:hover { + background-color: hsla(0, 0%, 61%, .1) +} + +.link .link-title { + align-items: center; + -webkit-column-gap: 15px; + column-gap: 15px; + display: flex; + flex-direction: row; + font-size: 150% +} + +.link .link-title svg { + color: #f77669; + font-size: 40px +} + +.link .link-description { + color: #7e7e7e +} + +.link .link-description code { + color: #ccc +} + +.file-picker { + border: 2px dashed; + cursor: pointer; + text-align: center +} + +.file-picker em { + font-size: 60% +} + +@import"https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;700&display=swap";:host,:root { + --fa-font-solid: normal 900 1em/1 "Font Awesome 6 Solid"; + --fa-font-regular: normal 400 1em/1 "Font Awesome 6 Regular"; + --fa-font-light: normal 300 1em/1 "Font Awesome 6 Light"; + --fa-font-thin: normal 100 1em/1 "Font Awesome 6 Thin"; + --fa-font-duotone: normal 900 1em/1 "Font Awesome 6 Duotone"; + --fa-font-sharp-solid: normal 900 1em/1 "Font Awesome 6 Sharp"; + --fa-font-brands: normal 400 1em/1 "Font Awesome 6 Brands" + } + +html { + background-color: #1e2527; + color-scheme: dark +} + +body { + font-family: JetBrains Mono,monospace; + font-size: 10pt; + line-height: 150%; + margin: 0; + color: #e0e2e4 +} + +body,html { + text-size-adjust: none; + -webkit-text-size-adjust: none; + -moz-text-size-adjust: none; + -ms-text-size-adjust: none +} + +main { + padding: 0 20px 20px; + flex-grow: 1 +} + +#__next,main { + display: flex; + flex-direction: column; + justify-content: space-between +} + +#__next { + min-height: 100vh +} + +a:active,a:hover,a:link,a:visited { + color: #f77669; + text-decoration: none +} + +a:active,a:hover { + border-bottom: 1px solid #f77669 +} + +button,input,select { + font-family: JetBrains Mono,monospace; + background-color: #252b2d; + border-style: none; + color: #ccc; + border-radius: 6px; + padding: 5px +} + +button :focus,input :focus,select :focus { + outline: none +} + +select { + -webkit-appearance: none; + appearance: none; + background-image: url(data:image/svg+xml;base64,PHN2ZyBhcmlhLWhpZGRlbj0idHJ1ZSIgZm9jdXNhYmxlPSJmYWxzZSIgcm9sZT0iaW1nIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0NDggNTEyIj48cGF0aCBmaWxsPSIjYjViNWI1IiBkPSJNMjA3LjAyOSAzODEuNDc2TDEyLjY4NiAxODcuMTMyYy05LjM3My05LjM3My05LjM3My0yNC41NjkgMC0zMy45NDFsMjIuNjY3LTIyLjY2N2M5LjM1Ny05LjM1NyAyNC41MjItOS4zNzUgMzMuOTAxLS4wNEwyMjQgMjg0LjUwNWwxNTQuNzQ1LTE1NC4wMjFjOS4zNzktOS4zMzUgMjQuNTQ0LTkuMzE3IDMzLjkwMS4wNGwyMi42NjcgMjIuNjY3YzkuMzczIDkuMzczIDkuMzczIDI0LjU2OSAwIDMzLjk0MUwyNDAuOTcxIDM4MS40NzZjLTkuMzczIDkuMzcyLTI0LjU2OSA5LjM3Mi0zMy45NDIgMHoiPjwvcGF0aD48L3N2Zz4=); + background-repeat: no-repeat; + background-position: 97%; + background-size: 10px +} + +button { + cursor: pointer +} + +hr { + border: 2px solid #252b2d +} + +article { + max-width: 900px; + margin: 20px auto; + font-size: 120% +} + +article h1:before,article h2:before { + content: "# "; + color: #ffc93a +} + +.textbox { + font-size: 130%; + letter-spacing: -1px; + color: #b5b5b5; + background: #252b2d; + padding: 8px; + margin: 12px 0; + border-radius: 6px +} + +.link { + background-color: #252b2d; + border-radius: 15px; + display: flex; + justify-content: space-between; + align-items: center; + gap: 15px; + height: 95px; + margin: 10px 0; + padding: 0 15px +} + +.link:link,.link:visited { + border-bottom: none; + color: #ccc +} + +.link:hover { + background-color: hsla(0,0%,61%,.1) +} + +.link svg { + color: #f77669; + font-size: 40px +} + +.link .link-title { + display: flex; + flex-direction: row; + align-items: center; + -webkit-column-gap: 15px; + column-gap: 15px; + font-size: 150% +} + +.link .link-description { + color: #7e7e7e +} + +.link .link-description code { + color: #ccc +} + +.footer_footer__kUwim { + color: #888; + margin-top: 30px; + padding: 0 20px 20px; + font-size: 10pt; + font-weight: 400; + text-align: right +} + +#header-header { + display: flex; + justify-content: space-between; + align-items: center; + gap: 10px; + background: #181d1f; + color: #ccc; + padding: 5px 20px; + margin: 0; + font-weight: 400; + box-shadow: 0 0 4px #130b00; + z-index: 20; + line-height: 100% +} + +#header-header>a { + display: flex; + align-items: center; + background-color: #252b2d; + border-radius: 5px; + padding: 3px 5px 3px 3px; + margin: 3px 0; + border: 0 +} + +#header-header>a>h1 { + padding: 0 3px; + font-size: 14pt; + margin: 0; + font-weight: 400; + color: #fff +} + +#header-header svg { + -webkit-filter: invert(0); + filter: invert(0); + padding-right: 5px +} + +.header-homepage { + background: #181d1f; + display: flex; + justify-content: center +} + +.header-homepage>div { + display: flex; + justify-content: space-around; + flex-grow: 1; + max-width: 900px; + padding: 50px 0 +} + +.header-homepage>div>svg { + width: 25% +} + +.header-homepage>div>div { + width: 60%; + display: flex; + flex-direction: column; + justify-content: center; + text-align: center +} + +.header-homepage>div>div>h1 { + font-size: min(15vw,150px); + line-height: 1em; + margin: 0 0 15px +} + +.header-homepage>div>div>div { + font-size: min(2vw,20px); + line-height: 1.1 +} +.sampler_sampler__BhYgT .stack { + margin-top: 20px; + padding-left: 10px +} + +.sampler_sampler__BhYgT .stack ul { + margin: 0; + padding: 0 0 0 20px +} + +.sampler_sampler__BhYgT .stack li { + margin: 0 0 0 -10px; + padding: 0; + list-style: none; + border-left: 1px solid #3c3f41 +} + +.sampler_sampler__BhYgT .stack li.parent { + border: 0 +} + +.sampler_sampler__BhYgT .stack .node-info { + display: flex; + width: 100%; + justify-content: space-between; + cursor: pointer +} + +.sampler_sampler__BhYgT .stack .node-info .time { + display: none; + position: absolute; + color: #888; + font-size: 90%; + padding: 0 4px; + white-space: normal +} + +.sampler_sampler__BhYgT .stack .node-info:hover { + background-color: #2e383e +} + +.sampler_sampler__BhYgT .stack .node-info:hover .time { + display: inline +} + +.sampler_sampler__BhYgT .stack .node-info:hover+ul { + background: #242b2f; + box-shadow: 0 2px 4px rgba(0,0,0,.4); + border-radius: 3px +} + +.sampler_sampler__BhYgT .stack .node-info.bookmarked { + box-shadow: inset 0 0 0 100vmax rgba(134,0,0,.5) +} + +.sampler_sampler__BhYgT .stack .name { + color: #bcbcbc; + background: url(data:image/svg+xml;base64,PHN2ZyBhcmlhLWhpZGRlbj0idHJ1ZSIgZm9jdXNhYmxlPSJmYWxzZSIgcm9sZT0iaW1nIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0NDggNTEyIj48cGF0aCBmaWxsPSIjYjViNWI1IiBkPSJNNDQ4IDgwdjM1MmMwIDI2LjUtMjEuNSA0OC00OCA0OEg0OGMtMjYuNSAwLTQ4LTIxLjUtNDgtNDhWODBjMC0yNi41IDIxLjUtNDggNDgtNDhoMzUyYzI2LjUgMCA0OCAyMS41IDQ4IDQ4ek05Mi41IDIyMC41bDEyMyAxMjNjNC43IDQuNyAxMi4zIDQuNyAxNyAwbDEyMy0xMjNjNy42LTcuNiAyLjItMjAuNS04LjUtMjAuNUgxMDFjLTEwLjcgMC0xNi4xIDEyLjktOC41IDIwLjV6Ij48L3BhdGg+PC9zdmc+) 0 no-repeat; + background-size: 8px; + background-position: 6px 50%; + padding-left: 20px; + white-space: nowrap +} + +.sampler_sampler__BhYgT .stack .collapsed .name { + background-image: url(data:image/svg+xml;base64,PHN2ZyBhcmlhLWhpZGRlbj0idHJ1ZSIgZm9jdXNhYmxlPSJmYWxzZSIgcm9sZT0iaW1nIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0NDggNTEyIj48cGF0aCBmaWxsPSIjYjViNWI1IiBkPSJNNDggMzJoMzUyYzI2LjUxIDAgNDggMjEuNDkgNDggNDh2MzUyYzAgMjYuNTEtMjEuNDkgNDgtNDggNDhINDhjLTI2LjUxIDAtNDgtMjEuNDktNDgtNDhWODBjMC0yNi41MSAyMS40OS00OCA0OC00OHptMTQwLjQ4NSAzNTUuNTE1bDEyMy4wMjktMTIzLjAyOWM0LjY4Ni00LjY4NiA0LjY4Ni0xMi4yODQgMC0xNi45NzFsLTEyMy4wMjktMTIzLjAzYy03LjU2LTcuNTYtMjAuNDg1LTIuMjA2LTIwLjQ4NSA4LjQ4NXYyNDYuMDU5YzAgMTAuNjkxIDEyLjkyNiAxNi4wNDUgMjAuNDg1IDguNDg2eiI+PC9wYXRoPjwvc3ZnPg==) +} + +.sampler_sampler__BhYgT .stack .lambda-part,.sampler_sampler__BhYgT .stack .native-part,.sampler_sampler__BhYgT .stack .package-part { + color: #5a5a5a +} + +.sampler_sampler__BhYgT .stack .lineNumber { + color: #5f5f5f; + padding-left: 2px +} + +.sampler_sampler__BhYgT .stack .remapped { + background: #293134; + border-radius: 3px; + padding: 0 2px +} + +.sampler_sampler__BhYgT .stack .percent { + color: #ffcd22; + font-size: 90%; + border-radius: 3px; + padding: 0 6px +} + +.sampler_sampler__BhYgT .stack .bar { + display: block; + min-width: 100px; + height: 15px; + margin-top: 2px; + margin-left: 20px; + border: 1px solid #484848; + background: #293134 +} + +.sampler_sampler__BhYgT .stack .bar .inner { + display: inline-block; + height: 15px; + background: #e2b671 +} + +@media screen and (max-width: 880px) { + .sampler_sampler__BhYgT .stack .bar { + display:none!important + } +} + +.sampler_sampler__BhYgT .sourceview .stack { + margin-bottom: 40px +} + +.sampler_sampler__BhYgT .sourceview .stack>li { + margin-left: 10px +} + +.sampler_sampler__BhYgT .sourceview .stack>h2>span { + font-size: 100%; + color: #888 +} + +.sampler_sampler__BhYgT .sourceview .other-sources { + padding-left: 10px +} + +.sampler_sampler__BhYgT .sourceview .other-sources li>span { + color: #888 +} + +.sampler_sampler__BhYgT .allview>.header,.sampler_sampler__BhYgT .flatview>.header,.sampler_sampler__BhYgT .graph>.header,.sampler_sampler__BhYgT .sourceview>.header { + margin: 0 10px; + max-width: 1000px; + font-size: 16px +} + +.sampler_sampler__BhYgT .allview>.header .button,.sampler_sampler__BhYgT .flatview>.header .button,.sampler_sampler__BhYgT .graph>.header .button,.sampler_sampler__BhYgT .sourceview>.header .button { + margin-left: 20px; + margin-bottom: 20px +} + +.sampler_sampler__BhYgT .allview>.header .button button,.sampler_sampler__BhYgT .flatview>.header .button button,.sampler_sampler__BhYgT .graph>.header .button button,.sampler_sampler__BhYgT .sourceview>.header .button button { + font-size: 16px; + padding-left: 10px; + padding-right: 10px +} + +.sampler_sampler__BhYgT .allview>.header .button button span,.sampler_sampler__BhYgT .flatview>.header .button button span,.sampler_sampler__BhYgT .graph>.header .button button span,.sampler_sampler__BhYgT .sourceview>.header .button button span { + color: #ffc93a +} + +.sampler_sampler__BhYgT .allview>.header .button p,.sampler_sampler__BhYgT .flatview>.header .button p,.sampler_sampler__BhYgT .graph>.header .button p,.sampler_sampler__BhYgT .sourceview>.header .button p { + margin: 5px 0; + font-weight: 300; + font-size: 14px; + color: #b5b5b5 +} + +.sampler_sampler__BhYgT .flame { + background-color: #252b2d; + padding: 20px; + box-sizing: border-box; + border-radius: .5rem +} + +.sampler_sampler__BhYgT .flame>div>div { + overflow-x: clip!important; + overflow-y: auto!important +} + +.sampler_sampler__BhYgT .flame .LabeledRect_div__3RSFb { + font-family: JetBrains Mono,monospace!important +} + +.sampler_sampler__BhYgT .flame .LabeledRect_rect__11W7H { + stroke: #181d1f!important +} + +.sampler_sampler__BhYgT .graph .VictoryContainer { + max-width: 1500px; + margin: 0 auto +} + +.sampler_sampler__BhYgT .graph .legend { + max-width: 1500px; + margin: 0 auto; + display: flex; + gap: 10px; + justify-content: center +} + +.sampler_sampler__BhYgT .graph .legend .button { + width: 150px; + cursor: pointer; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; + text-align: center +} + +.sampler_sampler__BhYgT .graph .legend .button.toggled { + font-weight: 700; + box-shadow: inset 0 -4px 0 #3c3f41 +} + +.sampler_sampler__BhYgT .no-results { + font-size: 130%; + color: maroon +} + + +.sampler_version-warning__7BkIx { + color: orange; + text-align: center +} + +.sampler_version-warning__7BkIx>svg { + float: right; + padding: 10px; + color: #b5b5b5; + cursor: pointer +} + +.widgets-widgets { + display: flex; + justify-content: space-evenly; + flex-wrap: wrap; + gap: 10px; + margin-bottom: 10px +} + +.widgets-widgets[data-hide=true] :nth-child(n+6) { + display: none +} + +@media screen and (max-width: 1450px) { + .widgets-widgets[data-hide=true] :nth-child(n+5) { + display:none + } +} + +@media screen and (max-width: 1160px) { + .widgets-widgets[data-hide=true] :nth-child(n+4) { + display:none + } +} + +@media screen and (max-width: 880px) { + .widgets-widgets[data-hide=true] :nth-child(n+3) { + display:none + } +} + +.widgets-widgets .widget { + color: #b5b5b5; + background: #252b2d; + padding: 2px 5px; + border-radius: 6px; + width: 260px; + max-width: 340px; + flex-grow: 1 +} + + +.widgets-widgets .widget h1 { + margin: 0; + padding-top: 5px; + padding-bottom: 8px; + font-size: 13pt; + font-weight: 400; + color: #fff; + text-align: center +} + +.widgets-widgets .widget h1 span { + vertical-align: middle; + padding-left: 6px; + font-size: 11pt; + color: #b5b5b5 +} + +.widgets-widgets .widget .widget-values { + display: flex +} + +.widgets-widgets .widget .widget-value { + display: flex; + flex-direction: column; + flex-grow: 1; + text-align: center +} + +.widgets-widgets .widget .widget-value div:first-child { + font-size: 16pt +} + +.widgets-widgets .widget .widget-value div:nth-child(2) { + color: #b5b5b5 +} + +.widgets-widgets .widget .widget-single-value { + display: flex; + justify-content: center +} + +.widgets-widgets .widget .widget-single-value span:nth-child(2) { + color: #b5b5b5; + padding: 0 5px +} + +.widgets-widgets .widget .widget-single-value span:first-child { + text-align: right +} + +.widgets-widgets .widget .widget-single-value span:nth-child(3) { + text-align: left +} + +.widgets-widgets .widget .widget-single-value span:nth-child(2n-1) { + flex-grow: 100; + flex-basis: 0 +} + +.expanded { + max-width: 1900px; + margin: auto +} + +.metadata-detail { + margin-top: 0 +} + +.metadata-detail p { + margin: 0 +} + +.metadata-detail p span { + color: #fff +} + +.metadata-detail .metadata-detail-controls { + padding: 0; + margin: 10px 0 30px +} + +.metadata-detail .metadata-detail-controls li { + list-style-type: none; + display: inline; + cursor: pointer; + margin: 0 3px; + background-color: #293134; + padding: 7px 15px; + border-radius: 5px +} + +.metadata-detail .metadata-detail-controls li.selected { + color: #fff +} + +.metadata-detail .metadata-detail-content>.configurations>p,.metadata-detail .metadata-detail-content>p { + margin: 0 5px +} + +.metadata-detail .configurations ul { + padding-left: 20px +} + +.metadata-detail .configurations ul ul { + border-left: 1px solid #3c3f41 +} + +.metadata-detail .configurations li { + list-style: none +} + +.metadata-detail .configurations .type-string { + color: #f7df97 +} + +.metadata-detail .configurations .type-boolean { + color: #78e6ff +} + +.metadata-detail .configurations .type-number { + color: #9bffa2 +} + +.metadata-detail .entity-counts { + display: flex; + justify-content: space-between; + -webkit-column-gap: 20px; + column-gap: 20px; + margin: 0 5px +} + +.metadata-detail .entity-counts>div { + width: 100% +} + +.metadata-detail .entity-counts .header { + background-color: #293134; + text-align: center; + padding: 5px; + border-radius: 5px; + margin-bottom: 10px +} + +.metadata-detail .entity-counts .header.region-selector { + display: flex; + justify-content: space-between +} + +.metadata-detail .entity-counts .button { + cursor: pointer; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; + padding: 0 5px +} + +.metadata-detail .entity-counts .detail-lists { + display: flex; + justify-content: space-between +} + +.metadata-detail .entity-counts .detail-lists>div { + width: 100%; + margin: 0 10px +} + +.metadata-detail .entity-counts .detail-lists ul { + margin-top: 5px; + list-style-type: none; + padding-left: 15px +} + +.metadata-detail .entity-counts .detail-lists span { + color: #fff +} + +.controls { + display: flex; + justify-content: space-between; + gap: 10px; + margin: 10px 0; + flex-wrap: wrap; + flex-basis: 1 +} + +.controls>div,.controls>input { + flex-grow: 1; + flex-shrink: 1; + height: 40px +} + +.controls .textbox { + padding: 0; + margin: 0 +} + +.controls .button { + max-width: 40px; + width: 40px; + cursor: pointer; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; + display: flex; + align-items: center; + justify-content: center +} + +.controls .button>svg { + padding: 0 5px +} + +.controls .button.toggled { + color: #fff; + box-shadow: inset 0 -3px 0 #3c3f41 +} + +.controls .sources-view-button { + justify-content: space-around; + max-width: 150px; + width: unset; + padding: 0 3px +} + +.controls .title { + text-align: center; + flex-grow: 2; + vertical-align: middle; + display: flex; + justify-content: center; + flex-direction: column; + min-height: 40px; + height: -webkit-fit-content; + height: -moz-fit-content; + height: fit-content +} + +.controls .title>span { + padding: 5px +} + +.controls .title img { + vertical-align: top; + padding-right: 3px +} + +.controls .searchbar { + flex-grow: 2; + padding: 0 0 0 28px; + background-image: url(data:image/svg+xml;base64,PHN2ZyBhcmlhLWhpZGRlbj0idHJ1ZSIgZm9jdXNhYmxlPSJmYWxzZSIgcm9sZT0iaW1nIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIj48cGF0aCBmaWxsPSIjYjViNWI1IiBkPSJNNTA1IDQ0Mi43TDQwNS4zIDM0M2MtNC41LTQuNS0xMC42LTctMTctN0gzNzJjMjcuNi0zNS4zIDQ0LTc5LjcgNDQtMTI4QzQxNiA5My4xIDMyMi45IDAgMjA4IDBTMCA5My4xIDAgMjA4czkzLjEgMjA4IDIwOCAyMDhjNDguMyAwIDkyLjctMTYuNCAxMjgtNDR2MTYuM2MwIDYuNCAyLjUgMTIuNSA3IDE3bDk5LjcgOTkuN2M5LjQgOS40IDI0LjYgOS40IDMzLjkgMGwyOC4zLTI4LjNjOS40LTkuNCA5LjQtMjQuNi4xLTM0ek0yMDggMzM2Yy03MC43IDAtMTI4LTU3LjItMTI4LTEyOCAwLTcwLjcgNTcuMi0xMjggMTI4LTEyOCA3MC43IDAgMTI4IDU3LjIgMTI4IDEyOCAwIDcwLjctNTcuMiAxMjgtMTI4IDEyOHoiPjwvcGF0aD48L3N2Zz4=); + background-repeat: no-repeat; + background-position: 8px; + background-size: 15px +} + +.hover{ + border-size: 5px; + border-style: solid; + border-color: transparent; +} +.hover:hover{ + transition-duration: 0.1s; + border-size: 5px; + border-style: solid; + border-color: #5E81AC; +} + +#pups{ + display:none; +} + +.json-data table{ + background:none; +} + +.accordion-button, .accordion-button:not(.collapsed) { + background: none; +} + +.accordion-button:hover { + background:#5E81AC; +} diff --git a/new/apps/web/static/static/css/doom-scroll.css b/new/apps/web/static/static/css/doom-scroll.css new file mode 100644 index 0000000..cdb7bef --- /dev/null +++ b/new/apps/web/static/static/css/doom-scroll.css @@ -0,0 +1,377 @@ +:root { + --bg-color: white; + --fg-color: black; + --line-color: hsl(0, 0%, 50%); + --link-color: #0969da; + + --progress-bar-filled: hsl(0, 0%, 70%); + --progress-bar-unfilled: hsl(0, 0%, 90%); + --progress-bar-color: var(--fg-color); + --table-alternate-color: hsl(0, 0%, 90%); + --nav-hover-color: hsl(0, 0%, 95%); + + + --green: #22c55e; + --yellow: #facc15; + --red: #ef4444; + --amd: rgb(215,27,27); + --intel: rgb(8,110,224); +} + +@media (prefers-color-scheme: dark) { + :root { + --bg-color: hsl(0, 0%, 13%); + --fg-color: #fefefe; + --line-color: hsl(0, 0%, 50%); + --link-color: #2f81f7; + + --progress-bar-filled: hsl(0, 0%, 30%); + --progress-bar-unfilled: hsl(0, 0%, 20%); + --progress-bar-color: var(--fg-color); + --table-alternate-color: hsl(0, 0%, 20%); + --nav-hover-color: hsl(0, 0%, 17%); + + + --green: #A3BE8C; + --yellow: rgb(235, 203, 139); + --red: rgb(191, 97, 106); + } +} + +:root { + color: var(--fg-color); + background-color: var(--bg-color); + font-family: "JetBrains Mono", monospace; +} + +.green { color: var(--green); } +.yellow { color: var(--yellow); } +.red { color: var(--red); } +.amd { color: var(--amd); } +.intel { color: var(--intel); } + +*, *::before, *::after { + box-sizing: border-box; +} + +body { + margin: 0; + display: flex; +} + +main { + width: 100%; + flex: 10 0 auto; /* allow horizontal scroll */ + margin: 1rem; +} + +nav { + position: sticky; + top: 0; + max-height: 100vh; + overflow-y: auto; + border-right: 1px solid var(--line-color); + padding-right: 1rem; + flex: 0 0 auto; +} + +#nav-collapse { + position: absolute; + right: 0; + display: inline-block; + margin-right: 0.5rem; +} + +#nav-expand { + display: none; +} + +.nav-collapsed #nav-list { + display: none; +} + +.nav-collapsed #nav-expand { + display: block; + position: relative; + left: 50%; + cursor: pointer; +} + +.nav-collapsed #nav-collapse { + display: none; +} + +.nav-space-below { + margin-bottom: 0.5rem; +} + +#nav-list { + margin-top: 0; /* We make it margin instead of padding so that it doesn't slide down when scrolling */ + padding-top: 1rem; + font-size: 16px; + list-style: none; + padding-left: 1rem; +} + +#nav-list li:hover { + background-color: var(--nav-hover-color); +} + +a { + color: var(--link-color); +} + +nav a { + text-decoration: none; + display: block; + width: 100%; +} + +/* this is just an empty element that ensures when you click on a heading, it scrolls to the left */ +.linker { + position: absolute; + left: 0; +} + +table { + border: 1px #595959 solid; + border-radius: 5px; + border-collapse: collapse; + table-layout: auto; +} + +tr:nth-child(even) { + background-color: var(--table-alternate-color); +} + +td, th { + font-size: 10pt; + font-weight: normal; + padding: 0.125rem 0.25rem; + border: 1px #595959 solid; +} + +th { + font-weight: bold; +} + +.nic tr > td:nth-child(2) { + min-width: 17ch; /* just to make it look nice, this is the width of a mac address with colons */ +} + +.td-center { + text-align: center; +} + + +.smart-table-wrapper { + display: flex; + gap: 1rem; +} + +#notes span { + font-weight: bold; +} + +/* + * MDB5 (modified) + * Version: FREE 7.1.0 + * + * + * Copyright: Material Design for Bootstrap + * https://mdbootstrap.com/ + * + * Read the license: https://mdbootstrap.com/general/license/ + */ +.progress, +.progress-stacked { + --mdb-progress-height: 4px; + --mdb-progress-font-size: 0.75rem; + --mdb-progress-bg: hsl(0, 0%, 80%); + --mdb-progress-border-radius: none; + --mdb-progress-box-shadow: none; + --mdb-progress-bar-color: #fff; + --mdb-progress-bar-bg: #3b71ca; + --mdb-progress-bar-transition: width 0.6s ease; + display: flex; + height: var(--mdb-progress-height); + overflow: hidden; + font-size: var(--mdb-progress-font-size); + background-color: var(--mdb-progress-bg); + border-radius: var(--mdb-progress-border-radius); + box-shadow: var(--mdb-progress-box-shadow); +} + +.progress-bar { + display: flex; + flex-direction: column; + justify-content: center; + overflow: hidden; + color: var(--mdb-progress-bar-color); + text-align: center; + white-space: nowrap; + background-color: var(--mdb-progress-bar-bg); + transition: var(--mdb-progress-bar-transition); +} +@media (prefers-reduced-motion: reduce) { + .progress-bar { + transition: none; + } +} + +.progress-bar-striped { + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-size: var(--mdb-progress-height) var(--mdb-progress-height); +} + +.progress-stacked > .progress { + overflow: visible; +} + +.progress-stacked > .progress > .progress-bar { + width: 100%; +} + +.progress-bar-animated { + animation: 1s linear infinite progress-bar-stripes; +} +@media (prefers-reduced-motion: reduce) { + .progress-bar-animated { + animation: none; + } +} +/* END MDB5 */ + +.progress { + border-radius: 0; + box-shadow: none; +} + +.partition-whole-bar { + height: 64px; + background-color: inherit; + border: 2px #595959 solid; + margin-bottom: 0.5rem; +} + +.partition-one-bar { + background-color: var(--progress-bar-unfilled); + border-right: 2px #595959 solid; + position: relative; + height: 100%; +} + +.partition-space-bar { + height: 100%; + background-color: var(--progress-bar-filled); +} + +.partition-bar-label { + position: absolute; + left: 50%; + transform: translateX(-50%); + color: var(--progress-bar-color); +} + +.smart-table-wrapper { + column-count: 2; +} + +pre { + border: 1px solid var(--line-color); + padding: 2px; +} + +pre code { + font-family: "JetBrains Mono", monospace; + font-size: 13px; + counter-reset: line; +} + +pre code span { + display: block; + counter-increment: line; +} + +#debug-log { + display: none; +} + +/** +From PrismJS: https://github.com/PrismJS/prism/blob/master/LICENSE + */ +.file code span:before { + content: counter(line); + display: inline-block; + text-align: right; + pointer-events: none; + top: 0; + font-size: 100%; + left: -3.8em; + width: 2em; + letter-spacing: -1px; + color: var(--line-color); + border-right: 1px solid var(--line-color); + padding-right: 0.5em; + margin-right: 0.5em; + + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.machinecheck-exception:not(:last-child) { + margin-bottom: 1rem; +} + +.whea-packets { + display: grid; + grid-template-columns: repeat(2, 1fr); + row-gap: 1rem; + column-gap: 0.5rem; +} + +/* https://www.w3schools.com/tags/tag_hn.asp */ +.whea-summary { + /*display: block;*/ + font-size: 1em; + margin-top: 1.33em; + margin-bottom: 1.33em; + margin-left: 0; + margin-right: 0; + font-weight: bold; +} + +.whea-summary:hover { + cursor: pointer; +} + +.whea-row { + display: flex; + flex-direction: row; + align-items: stretch; + gap: 0.5rem; +} + +/* I want the columns of the table to line up and idk any better way to do it than this */ +.whea-descriptor td:first-child { + width: 20ch; +} + +.whea-packet { + margin: 0; +} + +.tr-focus { + border: 2px solid var(--link-color); +} + +.hidden { + display: none; +} + +/* We already have our own No Data message */ +.dataTables_empty { + display: none; +} diff --git a/new/apps/web/static/static/css/landing.css b/new/apps/web/static/static/css/landing.css new file mode 100755 index 0000000..0521965 --- /dev/null +++ b/new/apps/web/static/static/css/landing.css @@ -0,0 +1,69 @@ +.homepage-homepage section { + background-color: #252b2d; + border-radius: 15px; + margin: 25px 0; + padding: .1px 15px +} + +.homepage-homepage .link .link-description { + width: 17.5rem; + font-weight: 400 +} + +@media (max-width: 640px) { + .homepage-homepage .link { + flex-direction: column; + align-items: start; + height: auto; + padding-bottom: .75rem; + gap: .5rem + } + + .homepage-homepage .link .link-description { + width: auto; + margin-bottom: .5rem + } +} + +.homepage-homepage .feature { + display: flex; + gap: 20px; + padding-left: 20px; + margin: 30px 0 +} + +.homepage-homepage .feature > div { + max-width: 70% +} + +.homepage-homepage .feature > div h3 { + margin: 0; + color: #ffc93a +} + +.file-picker { + text-align: center; + cursor: pointer; + border: 2px dashed; + width: 100%; +} +.file-picker:hover{ + transition : border 500ms ease-out; + border-color: red; +} +.hoverBox{ + transition : border 500ms ease-out; + border-color: red; +} +.file-picker em { + font-size: 60% +} +h2 { + display: block; + font-size: 1.5em; + margin-block-start: 0.83em; + margin-block-end: 0.83em; + margin-inline-start: 0px; + margin-inline-end: 0px; + font-weight: bold; +} \ No newline at end of file diff --git a/new/apps/web/static/static/css/main.css b/new/apps/web/static/static/css/main.css new file mode 100755 index 0000000..80bcbdb --- /dev/null +++ b/new/apps/web/static/static/css/main.css @@ -0,0 +1,1052 @@ +@import url(https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;700&display=swap); + +html { + background-color: var(--bg-color); + color-scheme: var(--color-scheme); +} + +body { + background-color: var(--bg-color); + color: var(--fg-color); + font-family: JetBrains Mono, monospace; + font-size: 10pt; + line-height: 150%; + margin: 0; +} + +body, +html { + text-size-adjust: none; + -webkit-text-size-adjust: none; + -moz-text-size-adjust: none; + -ms-text-size-adjust: none; +} + +main { + flex-grow: 1; + padding: 0 20px 20px; +} + +#root, +main { + display: flex; + flex-direction: column; + justify-content: space-between; +} + +#root { + min-height: 100vh; +} + +a:active, +a:hover, +a:link, +a:visited { + color: #f77669; + text-decoration: none; +} + +a:active, +a:hover { + border-bottom: 1px solid #f77669; +} + +button, +input, +select { + background-color: var(--secondary-bg); + border-radius: 6px; + border-style: none; + color: #ccc; + font-family: JetBrains Mono, monospace; + padding: 5px; +} + +button :focus, +input :focus, +select :focus { + outline: none; +} + +select { + -webkit-appearance: none; + appearance: none; + background-image: url(data:image/svg+xml;base64,PHN2ZyBhcmlhLWhpZGRlbj0idHJ1ZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDQ4IDUxMiI+PHBhdGggZmlsbD0iI2I1YjViNSIgZD0iTTIwNy4wMjkgMzgxLjQ3NiAxMi42ODYgMTg3LjEzMmMtOS4zNzMtOS4zNzMtOS4zNzMtMjQuNTY5IDAtMzMuOTQxbDIyLjY2Ny0yMi42NjdjOS4zNTctOS4zNTcgMjQuNTIyLTkuMzc1IDMzLjkwMS0uMDRMMjI0IDI4NC41MDVsMTU0Ljc0NS0xNTQuMDIxYzkuMzc5LTkuMzM1IDI0LjU0NC05LjMxNyAzMy45MDEuMDRsMjIuNjY3IDIyLjY2N2M5LjM3MyA5LjM3MyA5LjM3MyAyNC41NjkgMCAzMy45NDFMMjQwLjk3MSAzODEuNDc2Yy05LjM3MyA5LjM3Mi0yNC41NjkgOS4zNzItMzMuOTQyIDB6Ii8+PC9zdmc+); + background-position: 97%; + background-repeat: no-repeat; + background-size: 10px; + padding-right: 20px; +} + +button { + cursor: pointer; +} + +hr { + border: 2px solid #252b2d; +} + +header { + background: #181d1f; + box-shadow: 0 0 4px #130b00; + color: #ccc; + font-weight: 400; + gap: 10px; + justify-content: space-between; + line-height: 100%; + margin: 0; + padding: 5px 20px; + z-index: 20; +} + +header, +header > #header-logo > .logo { + align-content: center; + justify-content: center; +} + +header > #header-logo > .logo { + background-color: var(--logo-bg); + border: 0; + border-radius: 5px; + padding: 6px 3px; +} + +header > #header-logo > .logo > h1 { + color: #fff; + font-size: 14pt; + font-weight: 400; + margin: 0; + padding: 0 3px; +} + +header img { + -webkit-filter: invert(0); + filter: invert(0); + padding-right: 5px; + align-self: center; +} + +header > #header-logo > .logo img { + padding: 0; +} + +/* this is only used in landing as of 2024-03-31 */ +footer { + color: #888; + font-size: 10pt; + font-weight: 400; + margin-top: 30px; + padding: 0 20px 20px; + text-align: right; +} + +/* this is only used in landing as of 2024-03-31 */ +article { + font-size: 120%; + margin: 20px auto; + max-width: 900px; +} + +article h1:before, +article h2:before { + color: #ffc93a; + content: "# "; +} + +optgroup { + width: auto; + font-style: normal; +} + +.homepage-header > div { + display: flex; + flex-grow: 1; + justify-content: space-around; + max-width: 900px; + padding: 50px 0; +} + +.homepage-header > div > img { + width: 25%; +} + +.homepage-header > div > div { + display: flex; + flex-direction: column; + justify-content: center; + text-align: center; + width: 60%; +} + +.homepage-header > div > div > h1 { + font-size: min(15vw, 150px); + line-height: 1em; + margin: 0 0 15px; +} + +.homepage-header > div > div > div { + font-size: min(2vw, 20px); + line-height: 1.1; +} + +.homepage .link { + height: 75px; +} + +.homepage .link .link-description { + font-weight: 400; + width: 280px; +} + +.homepage section { + background-color: #252b2d; + border-radius: 15px; + margin: 25px 0; + padding: 0.1px 15px; +} + +.homepage .feature { + display: flex; + gap: 20px; + margin: 30px 0; + padding-left: 20px; +} + +.homepage .feature > svg { + color: #7e7e7e; + font-size: 70px; + margin: auto 0; +} + +.homepage .feature > div { + max-width: 70%; +} + +.homepage .feature > div h3 { + color: #ffc93a; + margin: 0; +} + +.downloads h3 > span { + color: #888; + font-size: 75%; +} + +.downloads .link-description { + width: 250px; +} + +/* this is only used in homepage used as of 2024-03-31 */ +.link { + align-items: center; + background-color: #252b2d; + border-radius: 15px; + display: flex; + gap: 15px; + height: 95px; + justify-content: space-between; + margin: 10px 0; + padding: 0 15px; +} + +.link:link, +.link:visited { + border-bottom: none; + color: #ccc; +} + +.link:hover { + background-color: hsla(0, 0%, 61%, 0.1); +} + +.link .link-title { + align-items: center; + -webkit-column-gap: 15px; + column-gap: 15px; + display: flex; + flex-direction: row; + font-size: 150%; +} + +.link .link-title svg { + color: #f77669; + font-size: 40px; +} + +.link .link-description { + color: #7e7e7e; +} + +.link .link-description code { + color: #ccc; +} + +.file-picker em { + font-size: 60%; +} + +@import "https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;700&display=swap"; +:host, +:root { + --fa-font-solid: normal 900 1em/1 "Font Awesome 6 Solid"; + --fa-font-regular: normal 400 1em/1 "Font Awesome 6 Regular"; + --fa-font-light: normal 300 1em/1 "Font Awesome 6 Light"; + --fa-font-thin: normal 100 1em/1 "Font Awesome 6 Thin"; + --fa-font-duotone: normal 900 1em/1 "Font Awesome 6 Duotone"; + --fa-font-sharp-solid: normal 900 1em/1 "Font Awesome 6 Sharp"; + --fa-font-brands: normal 400 1em/1 "Font Awesome 6 Brands"; +} + +body { + font-family: JetBrains Mono, monospace; + font-size: 10pt; + line-height: 150%; + margin: 0; +} + +body, +html { + text-size-adjust: none; + -webkit-text-size-adjust: none; + -moz-text-size-adjust: none; + -ms-text-size-adjust: none; +} + +main { + padding: 0 20px 20px; + flex-grow: 1; +} + +#__next, +main { + display: flex; + flex-direction: column; + justify-content: space-between; +} + +#__next { + min-height: 100vh; +} + +a:active, +a:hover, +a:link, +a:visited { + color: var(--link-secondary); + text-decoration: none; +} + +a:active, +a:hover { + border-bottom: 1px solid var(--link-secondary); +} + +button, +input, +select { + font-family: JetBrains Mono, monospace; + background-color: var(--secondary-bg); + border-style: none; + color: var(--button-fg); + border-radius: 6px; + padding: 5px; +} + +button :focus, +input :focus, +select :focus { + outline: none; +} + +select { + -webkit-appearance: none; + appearance: none; + background-image: url(data:image/svg+xml;base64,PHN2ZyBhcmlhLWhpZGRlbj0idHJ1ZSIgZm9jdXNhYmxlPSJmYWxzZSIgcm9sZT0iaW1nIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0NDggNTEyIj48cGF0aCBmaWxsPSIjYjViNWI1IiBkPSJNMjA3LjAyOSAzODEuNDc2TDEyLjY4NiAxODcuMTMyYy05LjM3My05LjM3My05LjM3My0yNC41NjkgMC0zMy45NDFsMjIuNjY3LTIyLjY2N2M5LjM1Ny05LjM1NyAyNC41MjItOS4zNzUgMzMuOTAxLS4wNEwyMjQgMjg0LjUwNWwxNTQuNzQ1LTE1NC4wMjFjOS4zNzktOS4zMzUgMjQuNTQ0LTkuMzE3IDMzLjkwMS4wNGwyMi42NjcgMjIuNjY3YzkuMzczIDkuMzczIDkuMzczIDI0LjU2OSAwIDMzLjk0MUwyNDAuOTcxIDM4MS40NzZjLTkuMzczIDkuMzcyLTI0LjU2OSA5LjM3Mi0zMy45NDIgMHoiPjwvcGF0aD48L3N2Zz4=); + background-repeat: no-repeat; + background-position: 97%; + background-size: 10px; +} + +button { + cursor: pointer; +} + +/* not used in viewer (may be used elsewhere) as of 2024-03-31 */ +hr { + border: 2px solid #252b2d; +} + +/* not used in viewer (may be used elsewhere) as of 2024-03-31 */ +article { + max-width: 900px; + margin: 20px auto; + font-size: 120%; +} + +/* not used in viewer (may be used elsewhere) as of 2024-03-31 */ +article h1:before, +article h2:before { + content: "# "; + color: #ebcb8b; +} + +.textbox { + font-size: 130%; + letter-spacing: -1px; + color: var(--secondary-fg); + background: var(--secondary-bg); + padding: 8px; + margin: 12px 0; + border-radius: 6px; +} + +.tablebox { + overflow: scroll; + padding-top: 1rem; +} + +.dataTables_wrapper > div { + margin: 0; +} + +.tabbed-info { + padding: 24px; +} + +/* not used in viewer (may be used elsewhere) as of 2024-03-31 */ +.link { + background-color: #252b2d; + border-radius: 15px; + display: flex; + justify-content: space-between; + align-items: center; + gap: 15px; + height: 95px; + margin: 10px 0; + padding: 0 15px; +} + +.link:link, +.link:visited { + border-bottom: none; + color: #ccc; +} + +.link:hover { + background-color: hsla(0, 0%, 61%, 0.1); +} + +.link svg { + color: #f77669; + font-size: 40px; +} + +.link .link-title { + display: flex; + flex-direction: row; + align-items: center; + -webkit-column-gap: 15px; + column-gap: 15px; + font-size: 150%; +} + +.link .link-description { + color: #7e7e7e; +} + +.link .link-description code { + color: #ccc; +} + +#header-header { + display: flex; + justify-content: space-between; + align-items: center; + gap: 10px; + background: var(--header-bg); + /*color: #ccc;*/ + padding: 5px 20px; + margin: 0; + font-weight: 400; + box-shadow: 0 0 4px var(--box-shadow); + z-index: 20; + line-height: 100%; +} + +#header-header > #header-logo > a { + align-self: center; + background-color: var(--logo-bg); + border-radius: 5px; + padding: 6px 3px; + border: 0; + display: inline-flex; +} + +#header-header > :first-child, #header-header > :last-child { + flex-grow: 1; + flex-basis: 0; +} + +#style-toggles { + display: flex; + justify-content: flex-end; + flex-wrap: wrap; + gap: 8px; +} + +#header-buttons { + display: flex; + gap: 8px; + flex-flow: wrap; + justify-content: center; +} + +#header-header select > option { + background-color: var(--header-dropdown); +} + +/* not used in viewer (may be used elsewhere) as of 2024-03-31 */ +#header-header > a > h1 { + padding: 0 3px; + font-size: 14pt; + margin: 0; + font-weight: 400; + color: #fff; +} + +/* not used in viewer (may be used elsewhere) as of 2024-03-31 */ +#header-header svg { + -webkit-filter: invert(0); + filter: invert(0); + padding-right: 5px; +} + +.header-homepage { + background: #181d1f; + display: flex; + justify-content: center; +} + +.header-homepage > div { + display: flex; + justify-content: space-around; + flex-grow: 1; + max-width: 900px; + padding: 50px 0; +} + +.header-homepage > div > svg { + width: 25%; +} + +.header-homepage > div > div { + width: 60%; + display: flex; + flex-direction: column; + justify-content: center; + text-align: center; +} + +.header-homepage > div > div > h1 { + font-size: min(15vw, 150px); + line-height: 1em; + margin: 0 0 15px; +} + +.header-homepage > div > div > div { + font-size: min(2vw, 20px); + line-height: 1.1; +} + +@media screen and (max-width: 880px) { +} + +.sampler_version-warning__7BkIx > svg { + float: right; + padding: 10px; + color: #b5b5b5; + cursor: pointer; +} + +.widgets-widgets { + display: flex; + justify-content: space-evenly; + flex-wrap: wrap; + gap: 10px; + margin-bottom: 10px; +} + +.widgets-widgets[data-hide="true"] :nth-child(n + 6) { + display: none; +} + +@media screen and (max-width: 1450px) { + .widgets-widgets[data-hide="true"] :nth-child(n + 5) { + display: none; + } +} + +@media screen and (max-width: 1160px) { + .widgets-widgets[data-hide="true"] :nth-child(n + 4) { + display: none; + } +} + +@media screen and (max-width: 880px) { + .widgets-widgets[data-hide="true"] :nth-child(n + 3) { + display: none; + } +} + +.widgets-widgets .widget { + color: var(--secondary-fg); + background: var(--secondary-bg); + padding: 2px 5px; + border-radius: 6px; + width: 260px; + max-width: 340px; + flex-grow: 1; +} + +.widgets-widgets .widget h1 { + margin: 0; + padding-top: 5px; + padding-bottom: 8px; + font-size: 13pt; + font-weight: 400; + color: var(--widget-emph); + text-align: center; +} + +.widgets-widgets .widget h1 span { + vertical-align: middle; + padding-left: 6px; + font-size: 11pt; + color: var(--secondary-fg); +} + +.widgets-widgets .widget .widget-values { + display: flex; +} + +.widgets-widgets .widget .widget-value { + display: flex; + flex-direction: column; + flex-grow: 1; + text-align: center; +} + +.widgets-widgets .widget .widget-value div:first-child { + font-size: 16pt; +} + +.widgets-widgets .widget .widget-value div:nth-child(2) { + color: var(--secondary-fg); +} + +.widgets-widgets .widget .widget-single-value { + display: flex; + justify-content: center; +} + +.widgets-widgets .widget .widget-single-value span:nth-child(2) { + color: var(--secondary-fg); + padding: 0 5px; +} + +.widgets-widgets .widget .widget-single-value span:first-child { + text-align: right; +} + +.widgets-widgets .widget .widget-single-value span:nth-child(3) { + text-align: left; +} + +.widgets-widgets .widget .widget-single-value span:nth-child(2n-1) { + flex-grow: 100; + flex-basis: 0; +} + +.metadata-metadata .metadata-detail { + margin-top: 0; +} + +.metadata-metadata .metadata-detail p { + margin: 0; +} + +.metadata-metadata .metadata-detail p span { + color: var(--widget-emph); +} + +.metadata-metadata .metadata-detail .metadata-detail-controls { + padding: 0; + margin: 10px 0 15px; +} +/* +.metadata-metadata .metadata-detail .metadata-detail-controls li { + list-style-type: none; + display: inline; + cursor: pointer; + margin: 0 3px; + background-color: #293134; + padding: 7px 15px; + border-radius: 5px; +} + +.metadata-metadata .metadata-detail .metadata-detail-controls li.selected { + color: #fff; +} */ + +.metadata-metadata .metadata-detail .metadata-detail-controls button { + list-style-type: none; + display: inline; + cursor: pointer; + margin: 0 3px; + margin-bottom: 5px; + background-color: var(--tertiary-bg); + padding: 7px 15px; + border-radius: 5px; +} + +.metadata-metadata .metadata-detail .metadata-detail-controls button.selected { + color: var(--widget-emph); +} + +.metadata-metadata + .metadata-detail + .metadata-detail-content + > .configurations + > p, +.metadata-metadata .metadata-detail .metadata-detail-content > p { + margin: 0 5px; +} + +.metadata-metadata .metadata-detail .configurations ul { + padding-left: 20px; +} + +/* not used in viewer (may be used elsewhere) as of 2024-03-31 */ +.metadata-metadata .metadata-detail .configurations ul ul { + border-left: 1px solid #3c3f41; +} + +.metadata-metadata .metadata-detail .configurations li { + list-style: none; +} + +.metadata-metadata .metadata-detail .entity-counts > div { + width: 100%; +} + +.metadata-metadata .metadata-detail .entity-counts .button { + cursor: pointer; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; + padding: 0 5px; +} + +.metadata-metadata .metadata-detail .entity-counts .detail-lists > div { + width: 100%; + margin: 0 10px; +} + +.metadata-metadata .metadata-detail .entity-counts .detail-lists ul { + margin-top: 5px; + list-style-type: none; + padding-left: 15px; +} + +.metadata-metadata .metadata-detail .entity-counts .detail-lists span { + color: #fff; +} + +.controls { + display: flex; + justify-content: space-between; + gap: 10px; + margin: 10px 0; + flex-wrap: wrap; + flex-basis: 1; +} + +.controls > div, +.controls > input { + flex-grow: 1; + flex-shrink: 1; + height: 40px; +} + +.controls .textbox { + padding: 0; + margin: 0; +} + +.controls .button { + max-width: 40px; + width: 40px; + cursor: pointer; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; + display: flex; + align-items: center; + justify-content: center; +} + +.controls .button > svg { + padding: 0 5px; +} + +.controls .title { + text-align: center; + flex-grow: 2; + vertical-align: middle; + display: flex; + justify-content: center; + flex-direction: column; + min-height: 40px; + height: -webkit-fit-content; + height: -moz-fit-content; + height: fit-content; +} + +.controls .title > span { + padding: 5px; +} + +.controls .title img { + vertical-align: top; + padding-right: 3px; +} + +.controls .searchbar { + flex-grow: 2; + padding: 0 0 0 28px; + background-image: url(data:image/svg+xml;base64,PHN2ZyBhcmlhLWhpZGRlbj0idHJ1ZSIgZm9jdXNhYmxlPSJmYWxzZSIgcm9sZT0iaW1nIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIj48cGF0aCBmaWxsPSIjYjViNWI1IiBkPSJNNTA1IDQ0Mi43TDQwNS4zIDM0M2MtNC41LTQuNS0xMC42LTctMTctN0gzNzJjMjcuNi0zNS4zIDQ0LTc5LjcgNDQtMTI4QzQxNiA5My4xIDMyMi45IDAgMjA4IDBTMCA5My4xIDAgMjA4czkzLjEgMjA4IDIwOCAyMDhjNDguMyAwIDkyLjctMTYuNCAxMjgtNDR2MTYuM2MwIDYuNCAyLjUgMTIuNSA3IDE3bDk5LjcgOTkuN2M5LjQgOS40IDI0LjYgOS40IDMzLjkgMGwyOC4zLTI4LjNjOS40LTkuNCA5LjQtMjQuNi4xLTM0ek0yMDggMzM2Yy03MC43IDAtMTI4LTU3LjItMTI4LTEyOCAwLTcwLjcgNTcuMi0xMjggMTI4LTEyOCA3MC43IDAgMTI4IDU3LjIgMTI4IDEyOCAwIDcwLjctNTcuMiAxMjgtMTI4IDEyOHoiPjwvcGF0aD48L3N2Zz4=); + background-repeat: no-repeat; + background-position: 8px; + background-size: 15px; +} + +.hover { + border-size: 5px; + border-style: solid; + border-color: transparent; +} +.hover:hover { + transition-duration: 0.1s; + border-size: 5px; + border-style: solid; + border-color: var(--select-color); +} + +/* not used in viewer (may be used elsewhere) as of 2024-03-31 */ +.drive-span:hover { + color: #ffffffbf !important; +} + +#pups { + display: none; +} +#variables { + display: none; +} +#browsers { + display: none; +} +#startup { + display: none; +} +#updates { + display: none; +} + +.accordion-button { + background: none !important; + color: var(--widget-emph) !important; +} +.accordion-button:hover { + background: var(--select-color) !important; +} +.center { + display: block; + margin-left: auto; + margin-right: auto; +} + +#btn-back-to-top { + position: fixed; + bottom: 20px; + right: 20px; + z-index: 999; + + opacity: 0; + visibility: hidden; + + transition: opacity 0.1s ease-in; + will-change: opacity, visibility; +} + +#btn-back-to-top svg { + height: 20px; +} + +#archive { + margin: auto; + width: 80%; +} +#login-form { + background-color: #2e383e; + width: 20%; + position: absolute; + left: 50%; + top: 50%; + -webkit-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); +} + +/* initial property, will be changed when the button is clicked */ +#collapse-toggle-hide { + display: none; +} + +#download:hover { + text-decoration: none; + border-bottom: none; +} + +.even { + background-color: var(--tr-even); +} + +.previous { + margin-left: auto; +} + +.form-control { + width: auto; + margin-left: 1rem; + display: inline-block; +} + +.form-select { + width: auto; + display: inline-block; +} + +label { + font-size: 10pt; +} + +table { + border: 1px var(--border-color) solid; + border-radius: 5px; + border-collapse: collapse; +} + +.table td, +.table th { + font-size: 10pt; + font-weight: normal; + padding: 0.125rem 0.25rem; + border: 1px var(--border-color) solid; +} + +.table > :not(:last-child) > :last-child > * { + border-bottom-color: var(--border-color); +} + +.json-data table { + background: none; +} + +.table { + table-layout: auto; + color: var(--table-color); + background: transparent; +} + +.nic { + width: 50%; + display: inline-block; + margin: auto; +} + +.nic td:not(:first-child){ + width: 100%; +} + +.dataTables_info { + font-size: 10pt; + padding-left: 0.5rem; +} + +.dataTables_length { + margin-bottom: 0.5rem; +} + +.dataTables_filter { + float: right; +} + +#blanket{ + display:none; + width:100%; + height:100%; + position:fixed; + top:0px; + left:0px; + z-index:9999; + background-color:black; +} + +.modal-content { + background-color: var(--modal-color); +} + +.modal-column { + float: left; +} + +.modal-column:not(:first-of-type) { + margin-left: 1rem; +} + +.smart-table-wrapper { + display: flex; + gap: 1rem; +} + +.partition-whole-bar { + height: 64px; + background-color: inherit; + border: 2px var(--border-color) solid; + margin-bottom: 0.5rem; +} + +.partition-one-bar { + background-color: inherit; + border-right: 2px var(--border-color) solid; + position: relative; + height: 100%; +} + +.partition-space-bar { + height: 100%; + background-color: var(--partition-bar-filled); +} + +.partition-bar-label { + position: absolute; + left: 50%; + transform: translateX(-50%); +} + +.green { color: var(--green) !important; } +.yellow { color: var(--yellow) !important; } +.red { color: var(--red) !important; } +.amd { color: var(--amd) !important; } +.intel { color: var(--intel) !important; } diff --git a/new/apps/web/static/static/css/tables.css b/new/apps/web/static/static/css/tables.css new file mode 100644 index 0000000..5ebd0d0 --- /dev/null +++ b/new/apps/web/static/static/css/tables.css @@ -0,0 +1,95 @@ +/* + +MODIFIED DATATABLES CSS - MIT LICENSE + +Copyright (C) 2008-2023, SpryMedia Ltd. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +table.dataTable thead > tr > th.sorting, +table.dataTable thead > tr > th.sorting_asc, +table.dataTable thead > tr > th.sorting_desc { + cursor: pointer; + position: relative; + padding-right: 26px; +} + +table.dataTable thead > tr > th.sorting:before, +table.dataTable thead > tr > th.sorting:after, +table.dataTable thead > tr > th.sorting_asc:before, +table.dataTable thead > tr > th.sorting_asc:after, +table.dataTable thead > tr > th.sorting_desc:before, +table.dataTable thead > tr > th.sorting_desc:after { + position: absolute; + display: block; + opacity: 0.125; + right: 10px; + line-height: 9px; + font-size: 0.8em; +} + +table.dataTable thead > tr > th.sorting:before, +table.dataTable thead > tr > th.sorting_asc:before, +table.dataTable thead > tr > th.sorting_desc:before{ + bottom: 50%; + content: "▲"; + content: "▲"/""; +} + +table.dataTable thead > tr > th.sorting:after, +table.dataTable thead > tr > th.sorting_asc:after, +table.dataTable thead > tr > th.sorting_desc:after{ + top: 50%; + content: "▼"; + content: "▼"/""; +} + +table.dataTable thead > tr > th.sorting_asc:before, +table.dataTable thead > tr > th.sorting_desc:after, +table.dataTable thead > tr > td.sorting_asc:before, +table.dataTable thead > tr > td.sorting_desc:after { + opacity: 0.6; +} + +table.dataTable thead > tr > th:active, +table.dataTable thead > tr > td:active { + outline: none; +} + +table.dataTable td.dt-control { + text-align: center; + cursor: pointer; +} +table.dataTable td.dt-control:before { + display: inline-block; + box-sizing: border-box; + content: ""; + border-top: 5px solid transparent; + border-left: 10px solid var(--border-color); + border-bottom: 5px solid transparent; + border-right: 0px solid transparent; +} +table.dataTable tr.dt-hasChild td.dt-control:before { + border-top: 10px solid var(--border-color); + border-left: 5px solid transparent; + border-bottom: 0px solid transparent; + border-right: 5px solid transparent; +} + +html.dark table.dataTable td.dt-control:before, +:root[data-bs-theme=dark] table.dataTable td.dt-control:before, +:root[data-theme=dark] table.dataTable td.dt-control:before { + border-left-color: var(--border-color); +} +html.dark table.dataTable tr.dt-hasChild td.dt-control:before, +:root[data-bs-theme=dark] table.dataTable tr.dt-hasChild td.dt-control:before, +:root[data-theme=dark] table.dataTable tr.dt-hasChild td.dt-control:before { + border-top-color: var(--border-color); + border-left-color: transparent; +} \ No newline at end of file diff --git a/new/apps/web/static/static/css/themes.css b/new/apps/web/static/static/css/themes.css new file mode 100644 index 0000000..64f79b5 --- /dev/null +++ b/new/apps/web/static/static/css/themes.css @@ -0,0 +1,80 @@ +:root, :root[data-theme="classic-mode"] { + --color-scheme: dark; + --bg-color: #3b4252; + --fg-color: #e0e2e4; + --secondary-bg: #252b2d; + --secondary-fg: #b5b5b5; + --tertiary-bg: #293134; + --widget-emph: #fff; + --logo-bg: #252b2d; + --button-fg: #ccc; + --header-bg: #181d1f; + --box-shadow: #130b00; + --link-secondary: #f77669; + --select-color: #5e81ac; + --tr-even: #ffffff07; + --border-color: #595959; + --partition-bar-filled: hsl(0, 0%, 20%); + --table-color: #fff; + --modal-color: #424242; + --meta-h4-color: #ffffff66; + + --green: #A3BE8C; + --yellow: rgb(235, 203, 139); + --red: rgb(191, 97, 106); + --amd: rgb(215,27,27); + --intel: rgb(8,110,224); +} + +:root[data-theme="light-mode"] { + --color-scheme: only light; + --bg-color: #ffffff; + --fg-color: #0d111388; + --secondary-bg: #f0f0f0; + --secondary-fg: #444; + --tertiary-bg: #e0e0e0; + --widget-emph: black; + --logo-bg: #252b2d; + --button-fg: #222222; + --header-bg: #eeeeee; + --header-dropdown: #d0d0d0; + --box-shadow: #d6d6d6; + --link-secondary: #f77669; + --select-color: #5e81ac; + --tr-even: #ffffff07; + --border-color: #595959; + --partition-bar-filled: hsl(0, 0%, 20%); + --table-color: var(--secondary-fg); + --modal-color: #ffffff; + --meta-h4-color: #333333; + + --green: green; + --yellow: goldenrod; + --red: #ef4444; + --amd: rgb(215,27,27); + --intel: rgb(8,110,224); +} + +:root[data-theme="light-mode"] .accordion-button::after { + filter: invert(1); +} + +:root[data-theme="light-mode"] .modal-header { + color: var(--widget-emph); +} + +:root[data-theme="k9-mode"] { + --color-scheme: dark; + --bg-color: #181a1b; + --modal-color: #232527; + --fg-color: #ddd9d0; + --secondary-bg: #202325; + --widget-bg: #181d1e; + --widget-fg: #ddd9d0; + --heading-color: #181d1e; + --meta-h4-color: #ffffff; + + --green: #72ff72; + --yellow: #e2b23a; + --red: #f04d4d; +} diff --git a/new/apps/web/static/static/js/common.js b/new/apps/web/static/static/js/common.js new file mode 100644 index 0000000..5f3e2b8 --- /dev/null +++ b/new/apps/web/static/static/js/common.js @@ -0,0 +1,104 @@ +let hwapiLocal = true; + +/** + * This is extracted into its own function because we need to call localhost instead of spec-ify.com if there is a + * hwapi dev server currently running. + * + * The path should not start with a slash. + */ +export async function call_hwapi(path, payload, fallbackCallack = () => {}) { + // https://stackoverflow.com/a/57949518 + const isLocalhost = Boolean( + window.location.hostname === 'localhost' || + // [::1] is the IPv6 localhost address. + window.location.hostname === '[::1]' || + // 127.0.0.0/8 is considered localhost for IPv4. + window.location.hostname.match( + /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ + ) + ); + + let rawResponse; + if (isLocalhost && hwapiLocal) { + console.info("Trying local server for hwapi"); + + try { + if (payload) { + rawResponse = await fetch( + `http://localhost:3000/${path}`, + { + method: "POST", + mode: "cors", + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(payload) + }, + ); + } else { + rawResponse = await fetch( + `http://localhost:3000/${path}`, + { + method: "GET", + mode: "cors", + headers: { + 'Accept': 'application/json' + } + }, + ); + } + } catch (e) { + fallbackCallack(); + console.warn("Hwapi dev server not online, falling back to spec-ify.com"); + hwapiLocal = false; + } + } + if (!rawResponse) { + if (payload) { + rawResponse = await fetch( + `https://spec-ify.com/${path}`, + { + method: "POST", + mode: "cors", + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(payload) + }, + ); + } else { + rawResponse = await fetch( + `https://spec-ify.com/${path}`, + { + method: "GET", + mode: "cors", + headers: { + 'Accept': 'application/json' + } + }, + ); + } + } + + try { + return await rawResponse.json(); + } catch (e) { + if (rawResponse.status !== 404) // prevent error spam + console.error("Could not parse json from hwapi!"); + + return {}; + } +} + +export function createPcieHexId(id) { + id = id.replace("0x", "").toUpperCase(); + const regex = /^[0-9A-F]{4}$/i; + + if (!regex.test(id)) { + id = "0".repeat(4 - id.length) + id; + } + + return id; +} diff --git a/new/apps/web/static/static/js/doom-scroll.js b/new/apps/web/static/static/js/doom-scroll.js new file mode 100644 index 0000000..57ac08b --- /dev/null +++ b/new/apps/web/static/static/js/doom-scroll.js @@ -0,0 +1,324 @@ +import { call_hwapi, createPcieHexId } from "./common.js"; + +/** + * This function contains extremely hacky hacks. + * (a) To avoid scrolling horizontally to the heading when you click on it + * (making the nav bar not visible), we add a dummy span (.linker) which + * is fixed to the left which actually has the id you want to jump to. + * (b) We add two spaces on h2's to give indents to them. This makes it appear + * nested, but it is terrible. + */ +function createLinks(selector) { + // this exists to avoid duplicates + let headings = {}; + + document.querySelectorAll(selector).forEach(e => { + if (e.offsetParent === null) return; // checks if the element is visible + const kebab = e.innerText.toLowerCase().split(" ").join("-") + .replace(/[^a-zA-Z0-9-_]/g, ''); + let num = 1; + while (Object.hasOwn(headings, `${kebab}-${num}`)) + num++; + const slug = `${kebab}-${num}`; + headings[slug] = e.innerText; + + const linker = document.createElement("span"); + linker.classList.add("linker"); + linker.id = slug; + e.prepend(linker); + + const li = document.createElement("li"); + const link = document.createElement("a"); + // TODO: get rid of this abomination + link.innerHTML = e.tagName === "H2" ? `  ${e.innerText}` : e.innerText; + link.style.width = "100%"; + link.href = `#${slug}`; + li.appendChild(link); + document.querySelector("#nav-list").appendChild(li); + }); +} +// there are just too many network adapters/disks lol +// the .item-header class should be added to dynamic headers (i.e. extensions, disks, network adapters, etc.) +createLinks("h1, h2:not(.item-header)"); + +document.querySelector("#nav-collapse").onclick = () => { + document.querySelector("nav").classList.add("nav-collapsed"); + return false; +} + +document.querySelector("#nav-expand").onclick = () => { + document.querySelector("nav").classList.remove("nav-collapsed"); + return false; +} + +// show the debug log when the konami code is pressed +new Konami(() => { + document.querySelector("#debug-log").style.display = "block"; + createLinks("#debug-log h1"); +}); + +// We don't want DataTables to alert errors +DataTable.ext.errMode = 'none'; +// the event handler below will make DataTables errors log in console +// https://datatables.net/reference/event/dt-error +$("table") +.on('error.dt', function (e, settings, techNote, message) { + console.log('An error has been reported by DataTables: ', message); + }); + +// jQuery is needed just for data tables, avoid using elsewhere +$("#temps-table").DataTable({ + paging: false, + searching: false, + info: false +}); +$("#drivers-table").DataTable({ + paging: false, + searching: false, + info: false +}); +$("#installed-apps-table").DataTable({ + paging: false, + searching: false, + info: false +}); +$("#windows-store-table").DataTable({ + paging: false, + searching: false, + info: false, + fallback: false +}); +$("#services-table").DataTable({ + paging: false, + searching: false, + info: false +}); +$("#tasks-table").DataTable({ + paging: false, + searching: false, + info: false +}); +$("#network-connections-table").DataTable({ + paging: false, + searching: false, + info: false +}); +$("#routes-table").DataTable({ + paging: false, + searching: false, + info: false +}); + +// The processes data table contains functionality that I am too lazy to implement in PHP, so it remains in JavaScript +(async () => { + const json = await (await fetch(`files/${PROFILE_NAME}.json`)).json(); + + try { + let groupProcesses = {}; + json.System.RunningProcesses.forEach((e) => { + const isSystemOrNull = + e.ExePath === "Not Found" || + e.ExePath === "SYSTEM" || + e.ExePath.startsWith(null); + const keys = Object.keys(groupProcesses); + // the path is not valid if isSystemOrNull is true + if (isSystemOrNull) { + if (!keys.includes(e.ProcessName)) + groupProcesses[e.ProcessName] = [e]; + else groupProcesses[e.ProcessName].push(e); + } else { + if (!keys.includes(e.ExePath)) groupProcesses[e.ExePath] = [e]; + else groupProcesses[e.ExePath].push(e); + } + }); + const displayProcesses = Object.values(groupProcesses).flatMap((e) => { + const count = e.length; + const workingSetReal = e + .map((p) => p.WorkingSet) + .reduce((acc, cur) => acc + cur); + const intl = Intl.NumberFormat("en-US"); + const workingSetMegaBytes = ( + workingSetReal / Math.pow(2, 20) + ).toFixed(2); + const workingSetDisplay = intl.format(workingSetMegaBytes); + return { + ProcessName: `${e[0].ProcessName} (${count})`, + ExePath: e[0].ExePath, + Id: e[0].Id, // We can perhaps make this a list later + WorkingSet: workingSetDisplay, + WorkingSetReal: workingSetReal, + }; + }); + + $("#processes-table").DataTable({ + paging: false, + searching: false, + info: false, + data: displayProcesses, + pageLength: 25, + columns: [ + { data: "Id" }, + { data: "ProcessName" }, + { data: "ExePath" }, + { data: "WorkingSet" }, + { data: "WorkingSetReal" }, + ], + columnDefs: [ + { orderData: [4], targets: [3] }, + { + targets: [4], + searchable: false, + visible: false, + }, + ], + }); + } catch (e) { + console.log("Failed making Running Processes DataTable. Is it blank?"); + console.error(e); + } + + // The hwapi request calls currently takes >1s. It doesn't matter that much, but I am doing this in js so the initial + // page load is a little faster. + /** + * @type string + */ + const cpuName = json["Hardware"]["Cpu"]["Name"]; + const statusSpan = document.querySelector("#hwapi-status"); + + const cpuResponse = await call_hwapi(`api/cpus/?name=${encodeURIComponent( + cpuName + )}`, null, () => { + statusSpan.innerHTML = "Could not connect to local hwapi instance, falling back to spec-ify.com"; + }); + + if (!cpuResponse || !cpuResponse.name) { + statusSpan.textContent = "Could not get database results"; + } + + // update the title element to reflect the name fetched from the database + document.querySelector("#hwapi-header").textContent += ` for ${cpuResponse.name}`; + let tableContents = ""; + // add new elements to the table for every kv in the database + for (const [key, value] of Object.entries(cpuResponse.attributes)) { + tableContents += `${key}${value}`; + } + // cpuTable.innerHTML = tableContents; + document.getElementById("hwapi-body").innerHTML = tableContents; + + const deviceTrs = document.querySelectorAll("#devices-table tbody tr"); + + let usbIndexes = []; + let usbValues = []; + let pcieIndexes = []; + let pcieValues = []; + + // go through all the devices and build an array to + deviceTrs.forEach((tr, index) => { + const jsonDevice = json["Hardware"]["Devices"][index]; + if (jsonDevice.DeviceID.startsWith("USB")) { + usbIndexes.push(index); + usbValues.push(jsonDevice["DeviceID"]); + } + if (jsonDevice.DeviceID.startsWith("PCI")) { + pcieIndexes.push(index); + pcieValues.push(jsonDevice["DeviceID"]); + } + }) + + const usbResponsePromise = call_hwapi('api/usbs/', usbValues); + const pcieResponsePromise = call_hwapi('api/pcie/', pcieValues); + const [usbResponse, pcieResponse] = await Promise.all([usbResponsePromise, pcieResponsePromise]); + + deviceTrs.forEach((tr, trIndex) => { + const usbArrayIndex = usbIndexes.indexOf(trIndex); + const pcieArrayIndex = pcieIndexes.indexOf(trIndex); + + if (usbArrayIndex !== -1 && usbResponse[usbArrayIndex]) { // the value is a usb device and it was found + const response = usbResponse[usbArrayIndex]; + const vendor = document.createElement("td"); + vendor.innerText = response.vendor || ""; + tr.appendChild(vendor); + const device = document.createElement("td"); + device.innerText = response.device || ""; + tr.appendChild(device); + const subsystem = document.createElement("td"); // no subsystem for usb + tr.appendChild(subsystem); + } else if (pcieArrayIndex !== -1 && pcieResponse[pcieArrayIndex]) { + const response = pcieResponse[pcieArrayIndex]; + const vendor = document.createElement("td"); + vendor.innerText = response.vendor || ""; + tr.appendChild(vendor); + const device = document.createElement("td"); + device.innerText = response.device || ""; + tr.appendChild(device); + const subsystem = document.createElement("td"); + subsystem.innerText = response.subsystem || ""; + tr.appendChild(subsystem); + } else { + tr.innerHTML += ""; + } + + const linker = document.createElement("span"); + linker.classList.add("linker"); + linker.id = `device-${trIndex}`; + tr.appendChild(linker); + }); + document.querySelector("#devices-sort-warning").style.display = "none"; + $("#devices-table").DataTable({ + paging: false, + searching: false, + info: false, + order: [] // to prevent order changing on data table load + }); + + let bugcheckMalformed = false; + // bugcheck replacemenet for unexpected shutdowns + const bugCheckCodes = json['Events']['UnexpectedShutdowns'].map(shutdown => { + if (!Number.isSafeInteger(shutdown['BugcheckCode'])) bugcheckMalformed = true; + return shutdown['BugcheckCode']; + }); + if (bugcheckMalformed) { // if one of them is not an integer for now, we can add more checks later + console.error("BugCheck codes malformed") + } else { + const response = await call_hwapi(`api/bugcheck/`, bugCheckCodes); + response.forEach((bugcheck, index) => { + //console.table({ index: index, ...bugcheck}); + if (bugcheck && bugcheck.name) { + // this refers to the bugcheckcode column. we need to use "... tbody tr" because otherwise it will select the header row too + const parent = document.querySelectorAll("#unexpected-shutdowns-table tbody tr")[index].querySelectorAll("td")[1]; + parent.innerHTML = ""; // clear code that was inserted in php + const a = document.createElement("a"); // i think inserting it like this is better for sanitation + a.href = bugcheck.url; + a.title = bugcheck.name; // these names can be very long so we're making it a tooltip instead + //a.innerText = `${bugcheck.name} (0x${bugcheck.code.toString(16)})`; + a.innerText = `0x${bugcheck.code.toString(16)}`; + parent.appendChild(a); + } + }); + } + + document.querySelectorAll("#pcie-whea-table tbody tr").forEach((tr, trIndex) => { + const vendorString = `VEN_${createPcieHexId(json['Events']['PciWheaErrors'][trIndex]['VendorId'])}`; + const deviceString = `DEV_${createPcieHexId(json['Events']['PciWheaErrors'][trIndex]['DeviceId'])}`; + for (const [index, device] of json['Hardware']['Devices'].entries()) { + if (device['DeviceID'].includes(vendorString) && device['DeviceID'].includes(deviceString)) { + const matchTd = tr.querySelectorAll("td")[3]; + matchTd.innerText = `${device['Name']} `; + const jumpLink = document.createElement("a"); + jumpLink.innerText = "Jump"; + jumpLink.href = `#device-${index}`; + + jumpLink.onclick = () => { + // can't use jumpLink.href here because that makes it the whole link + document.querySelector(`#device-${index}`).parentElement.classList.add("tr-focus"); + setTimeout(() => { + document.querySelector(`#device-${index}`).parentElement.classList.remove("tr-focus"); + }, 3000); + } + + matchTd.appendChild(jumpLink); + break; + } + } + }) +})(); diff --git a/new/apps/web/static/static/js/konami.js b/new/apps/web/static/static/js/konami.js new file mode 100644 index 0000000..3617027 --- /dev/null +++ b/new/apps/web/static/static/js/konami.js @@ -0,0 +1,186 @@ +/* + * Konami-JS ~ + * :: Now with support for touch events and multiple instances for + * :: those situations that call for multiple easter eggs! + * Code: https://github.com/georgemandis/konami-js + * Copyright (c) 2009 George Mandis (https://george.mand.is) + * Version: 1.6.3 (11/11/2021) + * Licensed under the MIT License (http://opensource.org/licenses/MIT) + * Tested in: Safari 4+, Google Chrome 4+, Firefox 3+, IE7+, Mobile Safari 2.2.1+ and Android + + MIT License + + Copyright (c) 2017 Snaptortoise + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +var Konami = function (callback) { + var konami = { + addEvent: function (obj, type, fn, ref_obj) { + if (obj.addEventListener) obj.addEventListener(type, fn, false); + else if (obj.attachEvent) { + // IE + obj["e" + type + fn] = fn; + obj[type + fn] = function () { + obj["e" + type + fn](window.event, ref_obj); + }; + obj.attachEvent("on" + type, obj[type + fn]); + } + }, + removeEvent: function (obj, eventName, eventCallback) { + if (obj.removeEventListener) { + obj.removeEventListener(eventName, eventCallback); + } else if (obj.attachEvent) { + obj.detachEvent(eventName); + } + }, + input: "", + pattern: "38384040373937396665", + keydownHandler: function (e, ref_obj) { + if (ref_obj) { + konami = ref_obj; + } // IE + konami.input += e ? e.keyCode : event.keyCode; + if (konami.input.length > konami.pattern.length) { + konami.input = konami.input.substr( + konami.input.length - konami.pattern.length + ); + } + if (konami.input === konami.pattern) { + konami.code(konami._currentLink); + konami.input = ""; + e.preventDefault(); + return false; + } + }, + load: function (link) { + this._currentLink = link; + this.addEvent(document, "keydown", this.keydownHandler, this); + this.iphone.load(link); + }, + unload: function () { + this.removeEvent(document, "keydown", this.keydownHandler); + this.iphone.unload(); + }, + code: function (link) { + window.location = link; + }, + iphone: { + start_x: 0, + start_y: 0, + stop_x: 0, + stop_y: 0, + tap: false, + capture: false, + orig_keys: "", + keys: [ + "UP", + "UP", + "DOWN", + "DOWN", + "LEFT", + "RIGHT", + "LEFT", + "RIGHT", + "TAP", + "TAP", + ], + input: [], + code: function (link) { + konami.code(link); + }, + touchmoveHandler: function (e) { + if (e.touches.length === 1 && konami.iphone.capture === true) { + var touch = e.touches[0]; + konami.iphone.stop_x = touch.pageX; + konami.iphone.stop_y = touch.pageY; + konami.iphone.tap = false; + konami.iphone.capture = false; + konami.iphone.check_direction(); + } + }, + touchendHandler: function () { + konami.iphone.input.push(konami.iphone.check_direction()); + + if (konami.iphone.input.length > konami.iphone.keys.length) + konami.iphone.input.shift(); + + if (konami.iphone.input.length === konami.iphone.keys.length) { + var match = true; + for (var i = 0; i < konami.iphone.keys.length; i++) { + if (konami.iphone.input[i] !== konami.iphone.keys[i]) { + match = false; + } + } + if (match) { + konami.iphone.code(konami._currentLink); + } + } + }, + touchstartHandler: function (e) { + konami.iphone.start_x = e.changedTouches[0].pageX; + konami.iphone.start_y = e.changedTouches[0].pageY; + konami.iphone.tap = true; + konami.iphone.capture = true; + }, + load: function (link) { + this.orig_keys = this.keys; + konami.addEvent(document, "touchmove", this.touchmoveHandler); + konami.addEvent( + document, + "touchend", + this.touchendHandler, + false + ); + konami.addEvent(document, "touchstart", this.touchstartHandler); + }, + unload: function () { + konami.removeEvent( + document, + "touchmove", + this.touchmoveHandler + ); + konami.removeEvent(document, "touchend", this.touchendHandler); + konami.removeEvent( + document, + "touchstart", + this.touchstartHandler + ); + }, + check_direction: function () { + x_magnitude = Math.abs(this.start_x - this.stop_x); + y_magnitude = Math.abs(this.start_y - this.stop_y); + x = this.start_x - this.stop_x < 0 ? "RIGHT" : "LEFT"; + y = this.start_y - this.stop_y < 0 ? "DOWN" : "UP"; + result = x_magnitude > y_magnitude ? x : y; + result = this.tap === true ? "TAP" : result; + return result; + }, + }, + }; + + typeof callback === "string" && konami.load(callback); + if (typeof callback === "function") { + konami.code = callback; + konami.load(); + } + + return konami; +}; + +if (typeof module !== "undefined" && typeof module.exports !== "undefined") { + module.exports = Konami; +} else { + if (typeof define === "function" && define.amd) { + define([], function () { + return Konami; + }); + } else { + window.Konami = Konami; + } +} diff --git a/new/apps/web/static/static/js/main.js b/new/apps/web/static/static/js/main.js new file mode 100755 index 0000000..5052788 --- /dev/null +++ b/new/apps/web/static/static/js/main.js @@ -0,0 +1,238 @@ +var devClick = 0; + +// List of all tabs +const tabs = [ + "#pups", + "#notes", + "#variables", + "#browsers", + "#startup", + "#updates", +]; + +for (const tab of tabs) { + if (tab === "#notes"){ + document.querySelector(`${tab}-button`).addEventListener("click", async () => { + showTab(tab); + + if (devClick === 0) {devClickReset = setTimeout(function() { devClick = 0; }, 1000);} + if (++devClick === 3) { + openDevDiv(); + clearTimeout(devClickReset); + } + }); + } + else { + document.querySelector(`${tab}-button`).addEventListener("click", () => { showTab(tab) }); + } +} + +/** + * Toggle the currently displayed tab in the main view + * @param {("#pups" | "#notes" | "#variables" | "#startup" | "#updates")} tab + */ +function showTab(tab) { + // Removes selected tab + const hiddenTabs = tabs.filter((val) => val !== tab); + for (const t of hiddenTabs) { + $(t).hide(); + } + $(tab).show(); +} + +// TODO: the way this is defined is a little bit weird, could probably be improved, it's currently defined by updating the value on the global `window` object +console.log(PROFILE_NAME); + +// Interactivity for the cpu and motherboard widgets +{ + // Interactivity for the show more and hide more buttons for the motherboard widget + document.querySelector("#board-info-more-info-button").addEventListener("click", () => { + document.querySelector("#board-info-more-info").style.display = "block"; + document.querySelector("#board-info-more-info-button").style.display = + "none"; + }); + document.querySelector("#board-info-close").addEventListener("click", () => { + document.querySelector("#board-info-more-info").style.display = "none"; + document.querySelector("#board-info-more-info-button").style.display = + "inline-block"; + }); + + // Interactivity for the show more and hide buttons for the cpu widget + document.querySelector("#cpu-close-button").addEventListener("click", () => { + document.querySelector("#cpu-more-info-button").style.display = ""; + document.querySelector("#cpu-info-table").style.display="none"; + }); + document.querySelector("#cpu-more-info-button").addEventListener("click", () => { + document.querySelector("#cpu-more-info-button").style.display = "none"; + document.querySelector("#cpu-info-table").style.display=""; + }); +} + +// When the selected view is changed (eg, gesp mode or doomscroll), redirect the user to that page +document.querySelector("#view-toggle").addEventListener("change", e => { + const selectedView = e.target.value; + const url = new URL(window.location); + url.searchParams.append("view", selectedView); + window.location = url.toString(); +}); + +// This is extremely jank, but it works! - K9 +// Add functionality to the "Collapse all"/"Expand all" button at the top of the main viewer page +{ + document.getElementById("collapse-toggle").addEventListener("click", () => { + document.getElementById("collapse-toggle").style.display = "none"; + document.getElementById("collapse-toggle-hide").style.display = "inline"; + const accordions = document.getElementsByClassName("accordion-collapse"); + for (const accordion of accordions) { + accordion.classList.add("show"); + } + }); + document.getElementById("collapse-toggle-hide").addEventListener("click", () => { + document.getElementById("collapse-toggle").style.display = "inline"; + document.getElementById("collapse-toggle-hide").style.display = "none"; + const accordions = document.getElementsByClassName("accordion-collapse"); + for (const accordion of accordions) { + accordion.classList.remove("show"); + } + }); +} + +// This could definitely be cleaned up more, for now we hand pick accordion elements to scroll into when expanded +{ + // Where the first item is the id of a button to add an event listener to, and the second item is the id of the element to scroll into + const elementsToScrollInto = [ + ["devices-table-button", "devices"], + ["drivers-table-button", "drivers"], + ["running-processes-button", "running-processes"], + ["installed-app-button", "installed-app"], + ["services-table-button", "services"], + ["tasks-table-button", "tasks"], + ["netcon-table-button", "netcon"], + ["routes-table-button", "routes"], + ]; + for (const [button, elementToScrollInto] of elementsToScrollInto) { + document.getElementById(button).addEventListener("click", () => { + document.getElementById(elementToScrollInto).scrollIntoView({ + behavior: "smooth", + block: "start", + inline: "nearest", + }); + }); + } +} + +document.querySelector("#searchbar-div").onkeyup = searchFunction; + +//Don't even ask. +//Setting the target as the searchbar, sanitizing the inputs into the search bar into lower case, then getting all divs by class of widget into an array and looping +//through them for each keystroke, setting visibility of matched divs with class widget, searching the text into their h1 children. +function searchFunction() { + let txtValue, h1; + const input = document.getElementById("searchbar-div"); + const filter = input.value.toUpperCase(); + const mainBody = document.getElementById("main"); + const widgets = mainBody.getElementsByClassName("widget"); + + for (const widget of widgets) { + if (widget.getElementsByTagName("h1")[0]) { + h1 = widget.getElementsByTagName("h1")[0]; + } + txtValue = h1.textContent || h1.innerText; + if (txtValue.toUpperCase().indexOf(filter) > -1) { + widget.style.display = ""; + } else { + widget.style.display = "none"; + } + } +} + +// Button in the bottom right that scrolls the page back to the top +{ + const topButton = document.getElementById("btn-back-to-top"); + // Show the top button if the page isn't at the top + // and hide it if it is + document.addEventListener("scroll", () => { + if ( + document.body.scrollTop > 20 || + document.documentElement.scrollTop > 20 + ) { + topButton.style.opacity = 1; + topButton.style.visibility = "visible"; + } else { + topButton.style.opacity = 0; + setTimeout(() => { + topButton.style.visibility = "hidden"; + }, "100"); + } + }) + // Scroll the page to the top when clicked + topButton.addEventListener("click", () => { + document.body.scrollTop = 0; + document.documentElement.scrollTop = 0; + }); +} + +function openDevDiv(){ + const devDiv = document.getElementById("dev-div"); + devDiv.style.display = "block"; + devDiv.scrollIntoView(); +} + +// Konami Code - Shows Debug Log +// KonamiJS Code from https://github.com/georgemandis/konami-js +new Konami( + () => (openDevDiv()) +); + +// populate the cpu info table with stuff from hwapi +(async () => { + const report = await (await fetch(`./files/${PROFILE_NAME}.json`)).json(); + /** + * @type string + */ + const cpuName = report["Hardware"]["Cpu"]["Name"]; + + let response; + if (window.location.host.startsWith("localhost")) { + console.info("Trying local server for hwapi"); + try { + response = await ( + await fetch( + `http://localhost:3000/api/cpus/?name=${encodeURIComponent( + cpuName + )}`, + { + method: "GET", + mode: "cors", + } + ) + ).json(); + } catch (e) { + console.warn("Could not connect to local hwapi instance, falling back to spec-ify.com"); + } + } + if (!response) { + response = await ( + await fetch( + `https://spec-ify.com/api/cpus/?name=${encodeURIComponent( + cpuName + )}`, + { + method: "GET", + mode: "cors", + } + ) + ).json(); + } + const titleElement = document.getElementById("cpu-info-title"); + // update the title element to reflect the name fetched from the database + document.getElementById("cpu-info-title").innerHTML = + titleElement.innerHTML.slice(0, -3) + response.name; + let tableContents = ""; + // add new elements to the table for every kv in the database + for (const [key, value] of Object.entries(response.attributes)) { + tableContents += `${key}${value}`; + } + // cpuTable.innerHTML = tableContents; + document.getElementById("fetched-cpu-info").innerHTML = tableContents; +})(); diff --git a/new/apps/web/static/static/js/redir.js b/new/apps/web/static/static/js/redir.js new file mode 100644 index 0000000..bca5772 --- /dev/null +++ b/new/apps/web/static/static/js/redir.js @@ -0,0 +1,6 @@ +let viewmodebutton = document.getElementById("spec-toggle"); +viewmodebutton.addEventListener("click", preserveViewmode); +function preserveViewmode() { + console.log('click'); + window.localStorage.removeItem('viewmode'); +} diff --git a/new/apps/web/static/static/js/tables.js b/new/apps/web/static/static/js/tables.js new file mode 100644 index 0000000..4701279 --- /dev/null +++ b/new/apps/web/static/static/js/tables.js @@ -0,0 +1,817 @@ +import { call_hwapi, createPcieHexId } from "./common.js"; + +const filename = `files/${PROFILE_NAME}.json`; + +async function dataTables() { + + const json = await (await fetch(filename)).json(); + + modalsTables(json); + devicesAndDrivers(json); + appsTables(json); + servicesAndTasks(json); + networkTables(json); + errorTables(json); +} + +function modalsTables(json) { + try { + $("#temp-table").DataTable({ + autoWidth: false, + data: json.Hardware.Temperatures, + columns: [ + { data: "Hardware" }, + { data: "SensorName" }, + { data: "SensorValue" }, + ], + }); + } catch (e) { + console.log("Failed making Temperature DataTable"); + console.log(e.name + ": " + e.message); + } + + try { + $("#power-table").DataTable({ + autoWidth: false, + searching: false, + ordering: false, + paging: false, + data: json.System.PowerProfiles, + columns: [ + { data: "Description" }, + { data: "ElementName" }, + { data: "InstanceID" }, + { data: "IsActive" }, + ], + }); + } catch (e) { + console.log("Failed making Power Profile DataTable"); + console.log(e.name + ": " + e.message); + } + + //This function broke me as a human being. + //We do a single entrypoint ajax call to the json file like all other table generations, except we have a situation where we have an unknown amount of browsers, each with + //an unknown amount of profiles, each with an unknown amount of extensions installed. + //One part of this is done in lines 1128~ and onwards(as of commit when writing this comment). PHP creates a table element for each of the browser profiles + //then the code below will follow the same naming convention to linearly populate each appropriate table with it's data. + //At first I experimented with creating the divs and table dynamically with JS, but datatable would not initialize on a newly created div no matter what I did. + //This works, and it seems to work great too. But who knows. + try { + var Browsers = Object.keys(json.System.BrowserExtensions); + Browsers.forEach(function (Browser) { + var Profiles = Object.keys( + json.System.BrowserExtensions[Browser].Profiles + ); + Profiles.forEach(function (Profile) { + let BrowserName = + "#" + + json.System.BrowserExtensions[Browser].Name + + "Profile" + + [Profile] + + "Table"; + let BrowserJsonData = + json.System.BrowserExtensions[Browser].Profiles[Profile] + .Extensions; + BrowserJsonData = BrowserJsonData.filter((e) => e != null); + $(BrowserName).DataTable({ + autoWidth: false, + searching: false, + ordering: false, + paging: false, + data: BrowserJsonData, + columns: [ + { data: "name" }, + { data: "version" }, + { data: "description" }, + ], + }); + }); + }); + } catch (e) { + console.log("Failed making Browser Extension DataTable"); + console.log(e.name + ": " + e.message); + } + + try { + $("#audio-table").DataTable({ + autoWidth: false, + searching: false, + ordering: false, + paging: false, + data: json.Hardware.AudioDevices, + columns: [ + { data: "DeviceID" }, + { data: "Manufacturer" }, + { data: "Name" }, + { data: "Status" }, + ], + }); + } catch (e) { + console.log("Failed making Audio Devices DataTable"); + console.log(e.name + ": " + e.message); + } + + try { + $("#battery-table").DataTable({ + autoWidth: false, + data: json.Hardware.Batteries, + searching: false, + ordering: false, + paging: false, + columns: [ + { data: "Name" }, + { data: "Manufacturer" }, + { data: "Chemistry" }, + { data: "Design_Capacity" }, + { data: "Full_Charge_Capacity" }, + ], + }); + } catch (e) { + console.log("Failed making Audio Devices DataTable"); + console.log(e.name + ": " + e.message); + } +} + +function devicesAndDrivers(json){ + try { + json.Hardware.Devices.map(row => { + if (row.Status === "Error") { + row.Status = `Error (${row.ConfigManagerErrorCode})`; + } + + return row; + }); + + $("#devices-table").DataTable({ + autoWidth: false, + data: json.Hardware.Devices, + columns: [ + { + data: "Status" + }, + { data: "Description" }, + { data: "Name" }, + { data: "DeviceID" }, + ], + }); + } catch (e) { + console.log("Failed making Devices DataTable"); + console.log(e.name + ": " + e.message); + } + + try { + $("#drivers-table").DataTable({ + autoWidth: false, + data: json.Hardware.Drivers, + columns: [ + { data: "DeviceName" }, + { data: "FriendlyName" }, + { data: "Manufacturer" }, + { data: "DeviceID" }, + { data: "DriverVersion" }, + ], + }); + } catch (e) { + console.log("Failed making Drivers DataTable"); + console.log(e.name + ": " + e.message); + } +} + +function appsTables(json) { + try { + let groupProcesses = {}; + json.System.RunningProcesses.forEach((e) => { + const isSystemOrNull = + e.ExePath === "Not Found" || + e.ExePath === "SYSTEM" || + e.ExePath.startsWith(null); + const keys = Object.keys(groupProcesses); + // the path is not valid if isSystemOrNull is true + if (isSystemOrNull) { + if (!keys.includes(e.ProcessName)) + groupProcesses[e.ProcessName] = [e]; + else groupProcesses[e.ProcessName].push(e); + } else { + if (!keys.includes(e.ExePath)) groupProcesses[e.ExePath] = [e]; + else groupProcesses[e.ExePath].push(e); + } + }); + const displayProcesses = Object.values(groupProcesses).flatMap((e) => { + const count = e.length; + const workingSetReal = e + .map((p) => p.WorkingSet) + .reduce((acc, cur) => acc + cur); + const intl = Intl.NumberFormat("en-US"); + const workingSetMegaBytes = ( + workingSetReal / Math.pow(2, 20) + ).toFixed(2); + const workingSetDisplay = intl.format(workingSetMegaBytes); + return { + ProcessName: `${e[0].ProcessName} (${count})`, + ExePath: e[0].ExePath, + Id: e[0].Id, // We can perhaps make this a list later + WorkingSet: workingSetDisplay, + WorkingSetReal: workingSetReal, + }; + }); + + $("#running-processes-table").DataTable({ + autoWidth: false, + data: displayProcesses, + pageLength: 25, + columns: [ + { data: "Id" }, + { data: "ProcessName" }, + { data: "ExePath" }, + { data: "WorkingSet" }, + { data: "WorkingSetReal" }, + ], + columnDefs: [ + { orderData: [4], targets: [3] }, + { + targets: [4], + searchable: false, + visible: false, + }, + ], + }); + } catch (e) { + console.log("Failed making Running Processes DataTable. Is it blank?"); + console.log(e.name + ": " + e.message); + } + + try { + $("#installed-app-table").DataTable({ + autoWidth: false, + data: json.System.InstalledApps, + columns: [ + { data: "Name" }, + { data: "Version" }, + { data: "InstallDate" }, + ], + }); + } catch (e) { + console.log("Failed making Installed Apps DataTable"); + console.log(e.name + ": " + e.message); + } + + if (document.getElementById("installed-windows-store-table")){ + try { + $("#installed-windows-store-table").DataTable({ + autoWidth: false, + pageLength: 25, + data: json.System.WindowsStorePackages, + columns: [ + { data: "Name" }, + { data: "ProgramId" }, + { data: "Vendor" }, + { data: "Version" }, + ], + }); + } catch (e){ + console.log("Failed making Windows Store Packages table"); + console.log(e.name + ": " + e.message); + } + } +} + +function servicesAndTasks(json) { + try { + $("#services-table").DataTable({ + autoWidth: false, + data: json.System.Services, + pageLength: 25, + columns: [ + { data: "State" }, + { data: "Caption" }, + { data: "Name" }, + { data: "PathName" }, + { data: "StartMode" }, + ], + }); + } catch (e) { + console.log("Failed making Services DataTable"); + console.log(e.name + ": " + e.message); + } + + try { + $("#tasks-table").DataTable({ + autoWidth: false, + data: json.System.ScheduledTasks, + pageLength: 25, + columns: [ + { data: "State" }, + { data: "IsActive" }, + { data: "Name" }, + { data: "Path" }, + { data: "Author" }, + { data: "TriggerTypes" }, + ], + }); + } catch (e) { + console.log("Failed making Tasks DataTable"); + console.log(e.name + ": " + e.message); + } +} + +function networkTables(json) { + try { + $("#netcon-table").DataTable({ + autoWidth: false, + data: json.Network.NetworkConnections, + columns: [ + { data: "LocalIPAddress" }, + { data: "LocalPort" }, + { data: "RemoteIPAddress" }, + { data: "RemotePort" }, + { + data: "OwningPID", + render: function (data) { + json.System.RunningProcesses.forEach(function (PID) { + if (PID.Id == data) { + data = PID.ProcessName; + } + }); + return data; + }, + }, + ], + }); + } catch (e) { + console.log("Failed making Network Connections DataTable"); + console.log(e.name + ": " + e.message); + } + + // Clever little trickery in this function actually where I practically use DataTables render functionality to + // InnerJoin the InterfaceIndex from one tree in the json to another tree in the json, thus giving me the ability + // to print out the corresponding name of the NIC that's using a route, instead of just a number. + try { + $("#routes-table").DataTable({ + autoWidth: false, + data: json.Network.Routes, + columns: [ + { data: "Description" }, + { data: "Destination" }, + { + data: "InterfaceIndex" + }, + { data: "Mask" }, + { data: "Metric1" }, + { data: "NextHop" }, + ], + }); + } catch (e) { + console.log("Failed making Routes DataTable"); + console.log(e.name + ": " + e.message); + } +} + +async function errorTables(json) { + // Unexpected Shutdowns + try { + function format(d) { + return ( + `
Bugcheck Parameter 1: ${d.BugcheckParameter1}
` + + `
Bugcheck Parameter 2: ${d.BugcheckParameter2}
` + + `
Bugcheck Parameter 3: ${d.BugcheckParameter3}
` + + `
Bugcheck Parameter 4: ${d.BugcheckParameter4}
` + ); + } + + let bugcheckMalformed = false; + // bugcheck replacemenet for unexpected shutdowns + const bugCheckCodes = json['Events']['UnexpectedShutdowns'].map(shutdown => { + if (!Number.isSafeInteger(shutdown['BugcheckCode'])) bugcheckMalformed = true; + return shutdown['BugcheckCode']; + }); + let bugCheckTable = {} + if (bugcheckMalformed) { // if one of them is not an integer for now, we can add more checks later + throw new Error("BugCheck codes malformed"); + } else { + const response = await call_hwapi(`api/bugcheck/`, bugCheckCodes); + response.forEach((bugcheck, index) => { + //console.table({ index: index, ...bugcheck}); + if (bugcheck && bugcheck.name) { + const a = document.createElement("a"); // i think inserting it like this is better for sanitation + a.href = bugcheck.url; + a.title = bugcheck.name; // these names can be very long so we're making it a tooltip instead + //a.innerText = `${bugcheck.name} (0x${bugcheck.code.toString(16)})`; + a.innerText = `0x${bugcheck.code.toString(16)}`; + bugCheckTable[bugcheck.code] = a.outerHTML; + } + }); + } + + let unexpectedShutdownsTable = new DataTable(("#unexpected-shutdowns-table"), { + autoWidth: false, + data: json.Events.UnexpectedShutdowns, + columns: [ + { + className: 'dt-control', + orderable: false, + data: null, + defaultContent: '', + width: '2%', + }, + { data: "Timestamp" }, + { data: "PowerButtonTimestamp" }, + { data: "BugcheckCode", + render: function (data) { + return bugCheckTable[data] ?? `0x${data.toString(16)}`; + } + }, + ], + order: [[1,"desc"]], + }); + + unexpectedShutdownsTable.on('click', 'td', function (e) { + let tr = e.target.closest('tr'); + let row = unexpectedShutdownsTable.row(tr); + + if (row.child.isShown()) { + // This row is already open - close it + row.child.hide(); + } + else { + // Open this row + row.child(format(row.data())).show(); + } + }); + } catch (e) { + console.log("Failed making Unexpected Shutdowns DataTable"); + console.log(e.name + ": " + e.message); + } + + // Machine Check Exception Table + try { + function format(d) { + return ( + ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Timestamp${d.Timestamp}
MCI Status Register Valid${d.MciStatusRegisterValid}
Error Overflow${d.ErrorOverflow}
Uncorrected Error${d.UncorrectedError}
Error Reporting Enabled${d.ErrorReportingEnabled}
Processor Context Corrupted${d.ProcessorContextCorrupted}
Poisoned Data${d.PoisonedData}
Extended Error Code${d.ExtendedErrorCode}
MCA Error Code${d.McaErrorCode}
Error Message${d.ErrorMessage}
Transaction Type${d.TransactionType}
Memory Heirarchy Level${d.MemoryHeirarchyLevel}
Request Type${d.RequestType}
Participation${d.Participation}
Timeout${d.Timeout}
Memory Or I/O${d.MemoryOrIo}
Memory Transaction Type${d.MemoryTransactionType}
Channel Number${d.ChannelNumber}
+ ` + ); + } + + let mceTable = new DataTable("#mce-table", { + autoWidth: false, + data: json.Events.MachineCheckExceptions, + columns: [ + { + className: 'dt-control', + orderable: false, + data: null, + defaultContent: '', + width: '2%', + }, + { data: "Timestamp" }, + { data: "McaErrorCode" }, + { data: "ErrorMessage" }, + { data: "TransactionType" }, + ], + order: [[1,"desc"]], + }); + + mceTable.on('click', 'td.dt-control', function (e) { + let tr = e.target.closest('tr'); + let row = mceTable.row(tr); + + if (row.child.isShown()) { + // This row is already open - close it + row.child.hide(); + } + else { + // Open this row + row.child(format(row.data())).show(); + } + }); + } catch (e) { + console.log("Failed making Machine Check Exception DataTable"); + console.log(e.name + ": " + e.message); + } + + // WHEA Error Records Error + try { + function format(d) { + + let errorDescriptors = `
+ Error Descriptors`; + + d.ErrorDescriptors.forEach((item) => { + errorDescriptors += ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Section Offset${item.SectionOffset}
Section Length${item.SectionLength}
Revision${item.Revision}
Valid Bits${item.ValidBits}
Flags${item.Flags}
Section Type${item.SectionType}
FRU ID${item.FRUId}
Section Severity${item.SectionSeverity}
FRU Text${item.FRUText}
` + }); + + errorDescriptors += `
`; + + return ( + // Error Header + ` +
+ Error Header + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Signature${d.ErrorHeader.Signature}
Revision${d.ErrorHeader.Revision}
Signature End${d.ErrorHeader.SignatureEnd}
Section Count${d.ErrorHeader.SectionCount}
Severity${d.ErrorHeader.Severity}
Valid Bits${d.ErrorHeader.ValidBits}
Length${d.ErrorHeader.Length}
Timestamp${d.ErrorHeader.Timestamp}
Platform ID${d.ErrorHeader.PlatformId}
Partition ID${d.ErrorHeader.PartitionId}
Creator ID${d.ErrorHeader.CreatorId}
Notify Type${d.ErrorHeader.NotifyType}
Record ID${d.ErrorHeader.RecordId}
Flags${d.ErrorHeader.Flags}
Persistence Info${d.ErrorHeader.PersistenceInfo}
+
+ ` + + + // Error Descriptors + errorDescriptors + + + // Error Packets + ` +
+ Error Packets +
${d.ErrorPackets}
+
+ ` + ); + } + + let wheaErrorRecordsTable = new DataTable("#whea-records-table", { + autoWidth: false, + data: json.Events.WheaErrorRecords, + columns: [ + { + className: 'dt-control', + orderable: false, + data: null, + defaultContent: '', + width: '2%', + }, + { data: "ErrorHeader.Severity" }, + { data: "ErrorHeader.Timestamp" }, + { data: "ErrorHeader.PlatformId" }, + { data: "ErrorHeader.CreatorId" }, + { data: "ErrorHeader.NotifyType" }, + ], + }); + + wheaErrorRecordsTable.on('click', 'td.dt-control', function (e) { + let tr = e.target.closest('tr'); + let row = wheaErrorRecordsTable.row(tr); + + if (row.child.isShown()) { + // This row is already open - close it + row.child.hide(); + } + else { + // Open this row + row.child(format(row.data())).show(); + } + }); + } catch (e) { + console.log("Failed making WHEA Error Records DataTable"); + console.log(e.name + ": " + e.message); + } + + // PCI WHEA Error + try { + // this might be the most scuffed code that i have ever written + // this works similarly to how doom-scroll.js does it, + // so it runs through all of the items and pushes it to a + // separate array. but then it pushes it back to the inner rep + // of the data. very stupid but it works so im not gonna + // change it. i need coffee - k9 + + let inputIds = []; + + json.Events.PciWheaErrors.forEach((data) => { + inputIds.push(`PCI\\VEN_${createPcieHexId(data.VendorId)}&DEV_${createPcieHexId(data.DeviceId)}`); + }); + + let responseIds = await call_hwapi('api/pcie/', inputIds); + + json.Events.PciWheaErrors.forEach((data, index) => { + json["Events"]["PciWheaErrors"][index]["Vendor"] = responseIds[index]["vendor"] + json["Events"]["PciWheaErrors"][index]["Subsystem"] = responseIds[index]["subsystem"] + + let vendorIdItem = data.VendorId.replace("0x", "").toUpperCase(); + let deviceIdItem = data.VendorId.replace("0x", "").toUpperCase(); + + json.Hardware.Devices.forEach((deviceData) => { + if (deviceData.DeviceID.includes(vendorIdItem) && deviceData.DeviceID.includes(deviceIdItem)) { + json["Events"]["PciWheaErrors"][index]["Device"] = deviceData.Name; + return; + } + }) + + if (json["Events"]["PciWheaErrors"][index]["Device"] == null){ + json["Events"]["PciWheaErrors"][index]["Device"] = responseIds[index]["vendor"] + } + }); + + new DataTable("#pci-whea-table", { + autoWidth: false, + data: json.Events.PciWheaErrors, + columns: [ + { data: "Timestamp" }, + { data: "VendorId" }, + { data: "DeviceId" }, + { data: "Vendor" }, + { data: "Device" }, + { data: "Subsystem" }, + ], + }); + } catch (e) { + console.log("Failed making PCI WHEA Errors DataTable"); + console.log(e.name + ": " + e.message); + } +} + +dataTables(); + +async function errorcheck() { + const json = await (await fetch(filename)).json(); + let errors = 0; + for (let key in json) { + key = json[key]; + try { + if ("ErrorCount" in key && key["ErrorCount"] > 0) { + for (let elem of document.getElementsByClassName("btn-info")) { + elem.style.backgroundColor = "#d35400"; + elem.style.boxShadow = "0 4px 9px -4px #d35400"; + } + errors += key["ErrorCount"]; + } + } catch { + continue; + } + } + if (errors > 0) {console.log("JSON Errors Total: " + errors);} +} + +errorcheck(); diff --git a/new/apps/web/static/static/js/themes.js b/new/apps/web/static/static/js/themes.js new file mode 100644 index 0000000..b336c57 --- /dev/null +++ b/new/apps/web/static/static/js/themes.js @@ -0,0 +1,21 @@ +//Themes. Could be handled in a better, more efficient way but it does it's job. +// IMPORTANT: the variables are intialized and set to *something* before running the script +let themeBody = null; +let themeTextBox = null; + +const localStorageTheme = window.localStorage.getItem("theme"); +if (localStorageTheme !== null) { + document.querySelector(`#mode-toggle option[value="${localStorageTheme}"]`).setAttribute("selected", ""); + change_theme(); +} + +// Call the function every time it changes +document.querySelector('#mode-toggle').onchange = change_theme; + +function change_theme(){ + // Get selection for the switch + let theme = document.querySelector('#mode-toggle').value; + + document.documentElement.setAttribute("data-theme", theme); + localStorage.setItem("theme", theme); +} diff --git a/new/apps/web/static/static/js/upload.js b/new/apps/web/static/static/js/upload.js new file mode 100755 index 0000000..eceaed6 --- /dev/null +++ b/new/apps/web/static/static/js/upload.js @@ -0,0 +1,56 @@ +//This is the drag and drop upload handler, I wish it was easier, but it's pretty self-explanatory. +let form = document.querySelector("#upload-form"); +let html = document.querySelector("html"); +let text = document.querySelector("#drag-text"); +let box = document.querySelector("#upload-box"); +let input = document.querySelector("#input-file-now"); + +// Prevent Redirect +html.addEventListener("dragover", (e) => { + e.preventDefault(); + e.stopPropagation(); + text.textContent = "Drop it!"; +}); + +html.addEventListener("dragleave", (e) => { + e.preventDefault(); + e.stopPropagation(); +}); + +html.addEventListener("drop", (e) => { + e.preventDefault(); + e.stopPropagation(); +}); + +form.addEventListener("dragenter", (e) => { + e.stopPropagation(); + e.preventDefault(); + box.classList.add("hoverBox"); + text.textContent = "Drop it!"; +}); + +form.addEventListener("dragover", (e) => { + e.stopPropagation(); + e.preventDefault(); + box.classList.add("hoverBox"); + text.textContent = "Drop it!"; +}); + +form.addEventListener("dragleave", (e) => { + box.classList.remove("hoverBox"); + text.textContent = "You tease"; + e.stopPropagation(); + e.preventDefault(); +}); + +// Drop +// Selects the input box, sets the files, and submits it +form.addEventListener("drop", (e) => { + text.textContent = "Thanks! :D"; + input.files = e.dataTransfer.files; + form.submit(); +}); + +input.addEventListener("change", () => { + form.submit(); +});