index.html back in this repo
This commit is contained in:
parent
4d469a6169
commit
3b4b063c8a
|
@ -17,13 +17,15 @@ services:
|
||||||
- type: bind
|
- type: bind
|
||||||
source: /srv/sys/caddy
|
source: /srv/sys/caddy
|
||||||
target: /data/caddy
|
target: /data/caddy
|
||||||
- type: bind
|
|
||||||
source: /srv/storage/www
|
|
||||||
target: /www
|
|
||||||
read_only: true
|
|
||||||
configs:
|
configs:
|
||||||
- source: Caddyfile
|
- source: Caddyfile
|
||||||
target: /etc/caddy/Caddyfile
|
target: /etc/caddy/Caddyfile
|
||||||
|
- source: index.html
|
||||||
|
target: /www/index.html
|
||||||
|
- source: index.mjs
|
||||||
|
target: /www/index.mjs
|
||||||
|
- source: index.css
|
||||||
|
target: /www/index.css
|
||||||
extra_hosts:
|
extra_hosts:
|
||||||
- host.docker.internal:host-gateway
|
- host.docker.internal:host-gateway
|
||||||
|
|
||||||
|
@ -223,7 +225,17 @@ configs:
|
||||||
name: dave.yaml-v3
|
name: dave.yaml-v3
|
||||||
Caddyfile:
|
Caddyfile:
|
||||||
file: Caddyfile
|
file: Caddyfile
|
||||||
name: Caddyfile-v63
|
name: Caddyfile-v65
|
||||||
|
index.html:
|
||||||
|
file: www/index.html
|
||||||
|
name: index.html-v32
|
||||||
|
index.mjs:
|
||||||
|
file: www/index.mjs
|
||||||
|
name: index.mjs-v1
|
||||||
|
index.css:
|
||||||
|
file: www/index.css
|
||||||
|
name: index.css-v1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
secrets:
|
secrets:
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
font-family: Helvetica, sans-serif;
|
||||||
|
background-color: #222;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
overflow-x: auto;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 12pt;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
nav img {
|
||||||
|
max-height: 2em;
|
||||||
|
}
|
||||||
|
nav a {
|
||||||
|
padding: 0.5em 1.5em;
|
||||||
|
color: #aaa;
|
||||||
|
text-decoration: none;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
nav a[target] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
nav a:hover {
|
||||||
|
background: #555;
|
||||||
|
}
|
||||||
|
nav a.active {
|
||||||
|
background: #8b8;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
iframe {
|
||||||
|
display: block;
|
||||||
|
border: none;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icons {
|
||||||
|
margin: auto 2em;
|
||||||
|
}
|
||||||
|
.icons {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
max-width: 40em;
|
||||||
|
margin: auto;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
.icons a {
|
||||||
|
background-color: #444;
|
||||||
|
color: #fff;
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
border-radius: 10px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.icons a img {
|
||||||
|
max-width: 66%;
|
||||||
|
max-height: 66%;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
image-rendering: pixelated;
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Deer Grove</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="icon" href="icons/deergrove.png">
|
||||||
|
<link rel="stylesheet" href="index.css">
|
||||||
|
<script src="index.mjs" type="module"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav>
|
||||||
|
<a href="/sonarr/" data-icon="/sonarr/Content/Images/logo.svg" title="Episode manager">Shows</a>
|
||||||
|
<a href="/radarr/" data-icon="/radarr/Content/Images/logo.svg" title="Movie manager">Movies</a>
|
||||||
|
<a href="/lidarr/" data-icon="/lidarr/Content/Images/logo.svg" title="Music manager">Music</a>
|
||||||
|
<a href="/readarr/" data-icon="/readarr/Content/Images/logo.svg" title="Book manager">Books</a>
|
||||||
|
<a href="/sucker/" data-icon="/sucker/cd-dvd.svg" title="Media Sucker">Sucker</a>
|
||||||
|
<hr>
|
||||||
|
<a href="/prowlarr/" data-icon="/prowlarr/Content/Images/logo.png" title="Indexer/Searcher">Search</a>
|
||||||
|
<a href="/nzbget/" data-icon="/nzbget/img/favicon-256x256.png" title="Usenet downloader">Usenet</a>
|
||||||
|
<a href="/transmission/web/" data-icon="/transmission/web/style/transmission/images/logo.png" title="BitTorrent downloader">BitTorrent</a>
|
||||||
|
<hr>
|
||||||
|
<a href="/octoprint/" data-icon="/octoprint/static/img/logo.png" title="3D Printer Front-End">Octoprint</a>
|
||||||
|
<a href="/wallart/" data-icon="/wallart/wallart.png" title="Wall Art uploader">Wall Art</a>
|
||||||
|
|
||||||
|
<!-- Items that launch a new tab don't appear in the top menu -->
|
||||||
|
<a href="https://git.woozle.org" target="_blank" data-icon="https://git.woozle.org/assets/img/logo.svg" title="Git repositories">Git</a>
|
||||||
|
<a href="https://drive.woozle.org/" target="_blank" data-icon="/public/icons/cloud-folder.png" titled="Shared storage">Drive</a>
|
||||||
|
<a href="https://ancestry.woozle.org/" target="_blank" data-icon="https://ancestry.woozle.org/images/favicon_gwd.png" title="Genealogy">Ancestry</a>
|
||||||
|
</nav>
|
||||||
|
<section id="app">
|
||||||
|
<iframe></iframe>
|
||||||
|
</section>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,94 @@
|
||||||
|
let frames = {}
|
||||||
|
function activate(event, element) {
|
||||||
|
if (element.target) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
event.preventDefault()
|
||||||
|
|
||||||
|
let parent = element.parentElement
|
||||||
|
for (let e of parent.getElementsByClassName("active")) {
|
||||||
|
e.classList.remove("active")
|
||||||
|
}
|
||||||
|
element.classList.add("active")
|
||||||
|
let href = element.href
|
||||||
|
let app = document.querySelector("#app")
|
||||||
|
|
||||||
|
let frame = frames[href]
|
||||||
|
if (frame) {
|
||||||
|
frame.dispatchEvent(new Event("load"))
|
||||||
|
} else {
|
||||||
|
frame = app.appendChild(document.createElement("iframe"))
|
||||||
|
frame.addEventListener("load", e => frameLoaded(frame))
|
||||||
|
frame.src = href
|
||||||
|
frames[href] = frame
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let fhref in frames) {
|
||||||
|
let f = frames[fhref]
|
||||||
|
if (fhref == href) {
|
||||||
|
f.classList.remove("hidden")
|
||||||
|
} else {
|
||||||
|
f.classList.add("hidden")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function frameLoaded(frame) {
|
||||||
|
let doc = frame.contentDocument
|
||||||
|
if (doc.title.length > 0) {
|
||||||
|
document.title = doc.title
|
||||||
|
}
|
||||||
|
let icon = document.querySelector("link[rel~='icon']")
|
||||||
|
let dicon = doc.querySelector("link[rel~='icon']")
|
||||||
|
if (dicon) {
|
||||||
|
icon.href = dicon.href
|
||||||
|
} else {
|
||||||
|
icon.href = defaultIcon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let defaultIcon = null
|
||||||
|
function init() {
|
||||||
|
let doc = document.querySelector("iframe").contentDocument
|
||||||
|
|
||||||
|
defaultIcon = document.querySelector("link[rel~='icon']").href
|
||||||
|
|
||||||
|
for (let l of document.head.querySelectorAll("style")) {
|
||||||
|
doc.head.appendChild(l.cloneNode(true))
|
||||||
|
}
|
||||||
|
for (let l of document.head.querySelectorAll("link[rel='stylesheet']")) {
|
||||||
|
doc.head.appendChild(l.cloneNode())
|
||||||
|
}
|
||||||
|
for (let f of document.querySelectorAll("#app iframe")) {
|
||||||
|
frames[f.src] = f
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let icons = doc.body.appendChild(doc.createElement("section"))
|
||||||
|
icons.classList.add("icons")
|
||||||
|
|
||||||
|
for (let link of document.querySelectorAll("nav a")) {
|
||||||
|
let dlink = icons.appendChild(link.cloneNode(true))
|
||||||
|
dlink.textContent = ""
|
||||||
|
|
||||||
|
if (link.dataset.icon) {
|
||||||
|
let icon = dlink.appendChild(doc.createElement("img"))
|
||||||
|
icon.src = link.dataset.icon
|
||||||
|
icon.style.objectFit = "cover"
|
||||||
|
} else {
|
||||||
|
let text = dlink.appendChild(doc.createElement("div"))
|
||||||
|
text.textContent = link.textContent
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make both of them update the selected tab
|
||||||
|
link.addEventListener("click", event => activate(event, link))
|
||||||
|
dlink.addEventListener("click", event => activate(event, link))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.readyState === "loading") {
|
||||||
|
document.addEventListener("DOMContentLoaded", init)
|
||||||
|
} else {
|
||||||
|
init()
|
||||||
|
}
|
Loading…
Reference in New Issue