local-startpage
Version:
Editable web browser frontpage without dependencies using local storage.
331 lines • 12.3 kB
HTML
<html>
<head>
<meta charset="utf8">
<link rel="icon" href="favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Startpage</title>
<style>
:root {
--main-bg-color: #272d36;
/*
* uncomment next line and set image url
--main-bg-image: url('');
*/
--main-accent-color: #C96070;
--main-color: rgb(102, 102, 107);
--main-text-color: #f0f0f0;
--white: #ffffff;
--main-focus-color: #1d2125;
}
body, html {
height: 100%;
width:100%;
}
body {
font-family: "Times New Roman", Times, serif;
font-size: 1.4em;
background-image: var(--main-bg-image);
background-color: var(--main-bg-color);
background-size: cover;
background-position: center;
box-sizing: border-box;
margin: 0;
position: relative;
display: flex;
justify-content: center;
align-items: center;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
ul {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-flow: row wrap;
max-width: 320px;
text-align: center;
}
li {
flex-grow: 1;
display: flex;
justify-content: center;
padding: 8px 6px;
}
a {
color: var(--main-text-color);
text-decoration: none;
outline: 0;
border: 0;
background: var(--main-color);
padding: 8px;
border-radius: 3px;
box-shadow: 0 0 5px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);
}
a:hover, a:focus {
background: var(--main-accent-color);
box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22);
}
span {
position: relative;
margin: 8px 0;
}
.btnAdd {
position: fixed;
width: 54px;
height: 54px;
border-radius: 54px;
box-shadow: 0 0 0 6px var(--main-color);
background: var(--main-bg-color);
border: 0;
right: 24px;
bottom: 24px;
z-index: 9999;
cursor: pointer;
text-align: center;
-webkit-tap-highlight-color: rgba(0,0,0,0);
-webkit-touch-callout: none;
}
.btnAdd svg {
fill: var(--white);
opacity: .6;
width: 18px;
height: 18px;
margin-top: 2px;
}
.btnAdd:active {
background: var(--main-focus-color);
}
.btnAdd:focus {
box-shadow: 0 0 0 6px var(--main-accent-color);
}
.active {
box-shadow: 0 0 0 6px var(--main-accent-color);
background: var(--main-focus-color);
}
.hide {
display: none;
}
button {
cursor: pointer;
margin-right: 3px;
}
button::-moz-focus-inner {
border: 0;
}
button, input {
outline: 0;
border: 0;
padding: 0;
margin: 0;
}
.remove {
color: var(--main-bg-color);
background: var(--white);
width: 21px;
height: 21px;
border-radius: 21px;
border-bottom-left-radius: 0;
font-size: 9px;
position: absolute;
right: -14px;
top: -20px;
}
.remove:hover, .remove:focus {
color: var(--white);
background: var(--main-accent-color);
}
#panel {
min-width: 100%;
position: fixed;
top: 0;
background: var(--main-focus-color);
padding: 2px;
}
form {
padding: 0;
width: 100%;
display: flex;
-webkit-flex-flow: column wrap;
flex-flow: column wrap;
}
@media only screen and (min-width: 480px) {
form {
width: none;
-webkit-flex-flow: row wrap;
flex-flow: row wrap;
}
button {
width: 56px;
margin-right: 2px;
}
input {
flex: 1 auto;
margin-right: 2px;
}
}
input {
height: 48px;
}
form button {
min-height: 48px;
}
#panel button {
background: var(--white);
color: var(--white);
}
#panel button:focus {
border: 1px solid var(--white);
}
#panel input {
padding-left: 8px;
color: var(--white);
background: var(--main-bg-color);
box-shadow: none;
border-bottom: 2px solid white;
}
#panel input:focus {
border-color: var(--main-accent-color);
}
#panel input:valid ~ button {
background: var(--main-accent-color);
}
#panel input:valid {
border-color: var(--main-accent-color);
}
#panel input:invalid ~ button {
color: var(--main-bg-color);
background: var(--main-color);
}
/*remove datalist arrow in webkit*/
input::-webkit-calendar-picker-indicator {
display: none;
}
</style>
</head>
<body>
<base target="_blank"><!-- opens all links in a new window -->
<div id="links"></div>
<button aria-pressed="false" class="btnAdd" id="btnToggle" title="Toggle form to add link">
<svg id="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26.6 26.6">
<path d="M21.2.3L2.8 18.7l5.1 5.1L26.3 5.4c.4-.4.4-1 0-1.4L22.6.3c-.4-.4-1-.4-1.4 0zM1.3 26.5l4.8-1.3-4.8-4.8L0 25.2c-.2 1 .4 1.5 1.3 1.3z"/>
</svg>
</button>
<div class="hide" id="panel">
<form name="submitform" onsubmit="return false">
<input id="urlLabel" list="defaultLabels" type="text" name="label" placeholder="label" title="Input label" required>
<datalist id="defaultLabels">
<option value="Startpagex">
<option value="DuckDuckGo">
<option value="Hacker News">
<option value="/.">
<option value="Wikipedia">
<option value="Reddit">
<option value="/tech/">
</datalist>
<input id="urlInput" list="defaultURLs" type="url" name="hostname" placeholder="link" title="Input link (URLs must start with https://)" required>
<datalist id="defaultURLs">
<option value="https://">
<option value="https://startpage.com/">
<option value="https://duckduckgo.com/">
<option value="https://news.ycombinator.com/">
<option value="https://slashdot.org/">
<option value="https://en.m.wikipedia.org/">
<option value="https://reddit.com/">
<option value="https://nerv.8ch.net/tech/cyber/g/sudo/prog/sci/">
</datalist>
<button type="submit" title="Add link" id="addUrl" formnovalidate>➜</button>
</form>
</div>
<script type="text/javascript">
(function() {
var linkOptions = {
fetchLinks: function() {
var links = new Array;
var links_str = localStorage.getItem('link');
if (links_str != null) {
links = JSON.parse(links_str);
}
return links;
},
removeLink: function() {
var id = this.getAttribute('id');
var links = linkOptions.fetchLinks();
links.splice(id, 1);
localStorage.setItem('link', JSON.stringify(links));
linkOptions.showLinks();
return false;
},
showLinks: function() {
var links = linkOptions.fetchLinks();
var html = '<ul>';
for (var i=0; i<links.length; i++) {
html += '<li><span class="link"><a href="' + links[i].url + '">' + links[i].label + '</a><button title="Remove" class="remove" id="' + i + '">✖</button></span></li>';
};
html += '</ul>';
document.getElementById('links').innerHTML = html;
var buttons = document.getElementsByClassName('remove');
for (var i=0; i<buttons.length; i++) {
buttons[i].addEventListener('click', linkOptions.removeLink);
};
},
addLink: function() {
var linkNew = document.getElementById('urlInput').value;
var labelNew = document.getElementById('urlLabel').value;
var newLink = { "url": linkNew, "label": labelNew };
var links = linkOptions.fetchLinks();
if (linkNew == "" || labelNew == "") {
return false;
} else {
links.push(newLink);
localStorage.setItem('link', JSON.stringify(links));
linkOptions.showLinks();
document.getElementById('urlInput').value = ""
document.getElementById('urlLabel').value = ""
}
}
};
document.getElementById('addUrl').addEventListener('click', linkOptions.addLink);
linkOptions.showLinks();
var toggleMenu = {
btnToggle: document.getElementById('btnToggle'),
menu: document.getElementById('panel'),
btnIcon: document.getElementById('icon'),
btnClose: document.getElementsByClassName('remove'),
btnClick: function() {
toggleMenu.btnToggle.addEventListener('click', function() {
toggleMenu.menu.classList.toggle('hide');
toggleMenu.btnToggle.classList.toggle('active');
for (i=0; i<toggleMenu.btnClose.length; i++) {
if (toggleMenu.btnClose[i].style.display == "none") {
toggleMenu.btnClose[i].style.display = "block";
toggleMenu.btnIcon.style.opacity = "1";
} else {
toggleMenu.btnClose[i].style.display = "none";
toggleMenu.btnIcon.style.opacity = "0.7";
}
};
});
},
btnCloseVis: function() {
for (i=0; i<toggleMenu.btnClose.length; i++) {
if (toggleMenu.btnClose[i].style.display = "block") {
toggleMenu.btnClose[i].style.display = "none";
} else {
toggleMenu.btnClose[i].style.display = "block";
}
};
}
};
toggleMenu.btnClick();
document.onload = toggleMenu.btnCloseVis();
})();
</script>
</body>
</html>
<!-- TODO:
[ ] svg icon for arrow
[ ] editable entries
-->