Sweet dashboard for self-hosted services has just arrived
240
css/main.css
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'Material Symbols Rounded';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
src: url(../font/MaterialSymbolsRounded.woff2) format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: #DDD;
|
||||||
|
color: #222;
|
||||||
|
margin: 0;
|
||||||
|
font-family: Quicksand;
|
||||||
|
font-weight: bold;
|
||||||
|
user-select: none;
|
||||||
|
font-size: 14px;
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: #44F;
|
||||||
|
}
|
||||||
|
.icon {
|
||||||
|
font-family: 'Material Symbols Rounded';
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 1;
|
||||||
|
letter-spacing: normal;
|
||||||
|
text-transform: none;
|
||||||
|
display: inline-block;
|
||||||
|
white-space: nowrap;
|
||||||
|
word-wrap: normal;
|
||||||
|
direction: ltr;
|
||||||
|
-webkit-font-feature-settings: 'liga';
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
}
|
||||||
|
.background, #background {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
object-fit: cover;
|
||||||
|
transition: all .45s;
|
||||||
|
}
|
||||||
|
#background.scaled {
|
||||||
|
transform: scale(1.14);
|
||||||
|
}
|
||||||
|
.unloaded {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.appicon {
|
||||||
|
width: 192px;
|
||||||
|
height: 192px;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
.page {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 50%;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 920px;
|
||||||
|
height: 100vh;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
overflow-y: scroll;
|
||||||
|
transition: all .4s;
|
||||||
|
}
|
||||||
|
.home.page {
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
overflow: hidden;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
.page.hidden {
|
||||||
|
top: 320px;
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.home.page.hidden {
|
||||||
|
top: calc(50% - 72px);
|
||||||
|
}
|
||||||
|
.wrapper {
|
||||||
|
box-shadow: 2px 2px 8px #0003;
|
||||||
|
background: #FFF8;
|
||||||
|
padding: 3px;
|
||||||
|
backdrop-filter: blur(16px);
|
||||||
|
border-radius: 24px;
|
||||||
|
margin: -4px 12px 16px;
|
||||||
|
text-align: center;
|
||||||
|
overflow: hidden;
|
||||||
|
min-width: 340px;
|
||||||
|
}
|
||||||
|
.home .wrapper {
|
||||||
|
box-shadow: none;
|
||||||
|
background: #FFF0;
|
||||||
|
backdrop-filter: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.appname {
|
||||||
|
font-size: 48px;
|
||||||
|
}
|
||||||
|
.appdesc {
|
||||||
|
opacity: .7;
|
||||||
|
margin: 2px 12px;
|
||||||
|
}
|
||||||
|
.appname.about {
|
||||||
|
font-size: 36px;
|
||||||
|
}
|
||||||
|
.buttons {
|
||||||
|
box-shadow: 2px 2px 8px #0002;
|
||||||
|
display: flex;
|
||||||
|
margin: 16px auto 0;
|
||||||
|
backdrop-filter: blur(16px);
|
||||||
|
border-radius: 24px;
|
||||||
|
max-width: 480px;
|
||||||
|
background: #FFF8;
|
||||||
|
padding: 2px;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.buttons > div {
|
||||||
|
padding: 16px;
|
||||||
|
margin: 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 20px;
|
||||||
|
width: calc(100% / 2);
|
||||||
|
transition: all .2s;
|
||||||
|
}
|
||||||
|
.buttons > div:hover {
|
||||||
|
background: #0001;
|
||||||
|
}
|
||||||
|
.buttons .text {
|
||||||
|
margin-top: -2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back {
|
||||||
|
box-shadow: 2px 2px 8px #0002;
|
||||||
|
position: relative;
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
border-radius: 24px;
|
||||||
|
background: #FFF8;
|
||||||
|
margin: 20px;
|
||||||
|
backdrop-filter: blur(16px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.back .icon {
|
||||||
|
margin: 4px;
|
||||||
|
width: 56px;
|
||||||
|
height: 56px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 20px;
|
||||||
|
transition: all .2s;
|
||||||
|
}
|
||||||
|
.back .icon:hover {
|
||||||
|
background: #0001;
|
||||||
|
}
|
||||||
|
.back .icon:after {
|
||||||
|
content: "chevron_left";
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.boxes {
|
||||||
|
display: flex;
|
||||||
|
flex: 1 1 0;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.static {
|
||||||
|
margin: 24px 6px 16px;
|
||||||
|
}
|
||||||
|
.static .box:hover {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
.box {
|
||||||
|
min-width: 292px;
|
||||||
|
flex: 1;
|
||||||
|
margin: 2px;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 8px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
text-align: left;
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
transition: all .2s;
|
||||||
|
}
|
||||||
|
.box:hover {
|
||||||
|
background: #0001;
|
||||||
|
}
|
||||||
|
.box .icon {
|
||||||
|
font-size: 24px;
|
||||||
|
padding: 20px;
|
||||||
|
background: hsl(var(--color), 100%, 90%);
|
||||||
|
color: hsl(var(--color), 100%, 35%);
|
||||||
|
border-radius: 100px;
|
||||||
|
margin: 2px 12px 2px 2px;
|
||||||
|
}
|
||||||
|
a.box {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 14px;
|
||||||
|
}
|
||||||
|
.box img {
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
object-fit: cover;
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
.box .name {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
.box .desc {
|
||||||
|
opacity: .65;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin: 20px 20px 16px;
|
||||||
|
}
|
||||||
|
.header .icon {
|
||||||
|
margin-top: 1px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
.header .text {
|
||||||
|
font-size: 26px;
|
||||||
|
}
|
BIN
font/MaterialSymbolsRounded.woff2
Normal file
BIN
img/appicon.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
img/background.jpg
Normal file
After Width: | Height: | Size: 236 KiB |
BIN
img/icon.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
img/preview/caldav.png
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
img/preview/files.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
img/preview/gallery.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
img/preview/git.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
img/preview/mail.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
img/preview/music.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
img/preview/notes.png
Normal file
After Width: | Height: | Size: 15 KiB |
141
index.html
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||||
|
<title>honey</title>
|
||||||
|
<link rel="icon" href="img/icon.png">
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/main.css">
|
||||||
|
<script type="text/javascript" src="js/dom.js"></script>
|
||||||
|
<script type="text/javascript" src="js/main.js"></script>
|
||||||
|
</head>
|
||||||
|
<body onload="onload()">
|
||||||
|
<div class="background">
|
||||||
|
<img src="img/background.jpg" id="background" class="unloaded" onload="load_img(this)">
|
||||||
|
</div>
|
||||||
|
<div class="main">
|
||||||
|
<div class="page home hidden" id="page-home">
|
||||||
|
<div class="wrapper">
|
||||||
|
<div class="home">
|
||||||
|
<img src="img/icon.png" class="appicon">
|
||||||
|
<div class="appname">honey</div>
|
||||||
|
<div class="appdesc">Nice and sweet place for all your self-hosted services.</div>
|
||||||
|
</div>
|
||||||
|
<div class="buttons">
|
||||||
|
<div onclick="show('page-services')">
|
||||||
|
<div class="icon">apps</div>
|
||||||
|
<div class="text">Services</div>
|
||||||
|
</div>
|
||||||
|
<div onclick="show('page-about')">
|
||||||
|
<div class="icon">info</div>
|
||||||
|
<div class="text">About</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="page hidden" id="page-services">
|
||||||
|
<div class="back"><div class="icon"></div></div>
|
||||||
|
<div class="wrapper">
|
||||||
|
<div class="header">
|
||||||
|
<div class="icon">apps</div>
|
||||||
|
<div class="text">Services</div>
|
||||||
|
</div>
|
||||||
|
<div class="boxes">
|
||||||
|
<a class="box" href="caldav">
|
||||||
|
<img src="img/preview/caldav.png">
|
||||||
|
<div>
|
||||||
|
<div class="name">CalDav</div>
|
||||||
|
<div class="desc">Simple CalDav server for calendar sync between various devices.</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a class="box" href="files">
|
||||||
|
<img src="img/preview/files.png">
|
||||||
|
<div>
|
||||||
|
<div class="name">Files</div>
|
||||||
|
<div class="desc">Fancy file manager for the web.</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a class="box" href="gallery">
|
||||||
|
<img src="img/preview/gallery.png">
|
||||||
|
<div>
|
||||||
|
<div class="name">Gallery</div>
|
||||||
|
<div class="desc">Photo & video gallery syncable with multiple Android devices.</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a class="box" href="git">
|
||||||
|
<img src="img/preview/git.png">
|
||||||
|
<div>
|
||||||
|
<div class="name">Git</div>
|
||||||
|
<div class="desc">Self-hosted, painless, secure place for your repositories.</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a class="box" href="mail">
|
||||||
|
<img src="img/preview/mail.png">
|
||||||
|
<div>
|
||||||
|
<div class="name">E-Mail</div>
|
||||||
|
<div class="desc">Feature-rich, decentralized and secure E-Mail server.</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a class="box" href="music">
|
||||||
|
<img src="img/preview/music.png">
|
||||||
|
<div>
|
||||||
|
<div class="name">Music</div>
|
||||||
|
<div class="desc">Beautiful, moody music streaming app.</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a class="box" href="notes">
|
||||||
|
<img src="img/preview/notes.png">
|
||||||
|
<div>
|
||||||
|
<div class="name">Notes</div>
|
||||||
|
<div class="desc">Sweet & lightweight app for taking notes.</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="page hidden" id="page-about">
|
||||||
|
<div class="back"><div class="icon"></div></div>
|
||||||
|
<div class="wrapper">
|
||||||
|
<div class="header">
|
||||||
|
<div class="icon">info</div>
|
||||||
|
<div class="text">About</div>
|
||||||
|
</div>
|
||||||
|
<img src="img/appicon.png" class="appicon">
|
||||||
|
<div class="appname about">honey</div>
|
||||||
|
<div class="appdesc">Nice and sweet place for all your self-hosted services.</div>
|
||||||
|
<div class="appdesc">Source: <a href="https://gitlab.com/dani3l0/honey" target="_blank">gitlab.com/dani3l0/honey</a></div>
|
||||||
|
<div class="boxes static">
|
||||||
|
<div class="box">
|
||||||
|
<div class="icon" style="--color: 0deg">code</div>
|
||||||
|
<div>
|
||||||
|
<div class="name">Open Source</div>
|
||||||
|
<div class="desc">Code is publicly available. Download, modify, collaborate, whatever.</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="box">
|
||||||
|
<div class="icon" style="--color: 144deg">mop</div>
|
||||||
|
<div>
|
||||||
|
<div class="name">Simple & Clean</div>
|
||||||
|
<div class="desc">Interface is meant to be uncomplicated and pleasant in sight.</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="box">
|
||||||
|
<div class="icon" style="--color: 240deg">language</div>
|
||||||
|
<div>
|
||||||
|
<div class="name">Static</div>
|
||||||
|
<div class="desc">Requires no dynamic backend as it's built with plain HTML/CSS/JS.</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="box">
|
||||||
|
<div class="icon" style="--color: 36deg">auto_awesome</div>
|
||||||
|
<div>
|
||||||
|
<div class="name">Responsive</div>
|
||||||
|
<div class="desc">Layout is automatically adjusted depending on device you are using.</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
12
js/dom.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
function get(id) {
|
||||||
|
return document.getElementById(id);
|
||||||
|
}
|
||||||
|
function for_all(class_name, func) {
|
||||||
|
let a = document.getElementsByClassName(class_name);
|
||||||
|
for (let i = 0; i < a.length; i++) {
|
||||||
|
func(a[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function load_img(img) {
|
||||||
|
img.classList.remove("unloaded");
|
||||||
|
}
|
19
js/main.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
function onload() {
|
||||||
|
for_all("back", (btn) => {
|
||||||
|
btn.onclick = back;
|
||||||
|
});
|
||||||
|
back();
|
||||||
|
}
|
||||||
|
|
||||||
|
function show(id) {
|
||||||
|
for_all("page", (page) => {
|
||||||
|
page.classList.add("hidden");
|
||||||
|
});
|
||||||
|
get(id).classList.remove("hidden");
|
||||||
|
get(id).scrollTop = 0;
|
||||||
|
get("background").classList.remove("scaled");
|
||||||
|
}
|
||||||
|
function back() {
|
||||||
|
show("page-home");
|
||||||
|
get("background").classList.add("scaled");
|
||||||
|
}
|