Add basic capabilities
stores and loads bookmarks from localStorage, import/export capabilities
This commit is contained in:
parent
bee398bcef
commit
5798bad50a
34
.gitignore
vendored
Normal file
34
.gitignore
vendored
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
|
||||||
|
bootstrap/css/
|
||||||
|
|
||||||
|
bootstrap/js/
|
||||||
|
|
||||||
|
js/jquery-3\.2\.1\.js
|
||||||
|
|
||||||
|
js/jquery-3\.2\.1\.min\.js
|
||||||
|
|
||||||
|
js/jquery-3\.2\.1\.min\.map
|
||||||
|
|
||||||
|
js/popper\.js
|
||||||
|
|
||||||
|
img/0\.png
|
||||||
|
|
||||||
|
img/1\.png
|
||||||
|
|
||||||
|
img/2\.png
|
||||||
|
|
||||||
|
img/3\.png
|
||||||
|
|
||||||
|
img/4\.png
|
||||||
|
|
||||||
|
img/5\.png
|
||||||
|
|
||||||
|
img/6\.png
|
||||||
|
|
||||||
|
img/7\.png
|
||||||
|
|
||||||
|
img/8\.png
|
||||||
|
|
||||||
|
js/popper\.js\.map
|
||||||
|
|
||||||
|
bookmarkList\.json
|
0
bootstrap/.gitkeep
Normal file
0
bootstrap/.gitkeep
Normal file
BIN
favicon.png
Normal file
BIN
favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
0
img/.gitkeep
Normal file
0
img/.gitkeep
Normal file
177
index.html
Normal file
177
index.html
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
|
<meta name="description" content="A new tab page">
|
||||||
|
<meta name="author" content="Neil Brommer">
|
||||||
|
<link rel="icon" href="favicon.png">
|
||||||
|
|
||||||
|
<title>New Start</title>
|
||||||
|
|
||||||
|
<!-- Bootstrap core CSS -->
|
||||||
|
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- Custom styles -->
|
||||||
|
<link href="main.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<nav class="navbar navbar-expand-md navbar-dark bg-dark mb-4">
|
||||||
|
<!-- <a class="navbar-brand" href=".">Start</a >-->
|
||||||
|
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" aria-controls="navbarCollapse"
|
||||||
|
aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarCollapse">
|
||||||
|
<ul class="navbar-nav mr-auto">
|
||||||
|
<!-- Keep this to push elements to the right -->
|
||||||
|
</ul>
|
||||||
|
<form class="form-inline mt-2 mt-md-0">
|
||||||
|
<button class="btn btn-light ml-sm-2" type="button" data-Toggle="modal" data-target="#aboutModal">About</button>
|
||||||
|
<button class="btn btn-light ml-sm-2" type="button" data-Toggle="modal" data-target="#importExportModal">Import/Export</button>
|
||||||
|
<button class="btn btn-light ml-sm-2" type="button">Edit</button>
|
||||||
|
<button class="btn btn-light ml-sm-2" type="button" data-toggle="modal" data-target="#newBookmarkModal">Add</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div id="wrapper" class="container">
|
||||||
|
<div id="cardList" class="card-columns">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="newBookmarkModal" class="modal fade" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Add Bookmark</h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="newBookmarkName">Name</label>
|
||||||
|
<input id="newBookmarkName" type="text" class="form-control">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="newBookmarkURL">Address</label>
|
||||||
|
<input id="newBookmarkURL" type="url" class="form-control">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="newBookmarkGroup">Group</label>
|
||||||
|
<select id="newBookmarkGroup" name="Group" class="form-control" onchange="selectGroupChanged(this.value)">
|
||||||
|
<option value="-">New Group</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div id="createGroup" class="form-group newGroup">
|
||||||
|
<label for="newBookMarkGroupNew">New Group</label>
|
||||||
|
<input id="newBookMarkGroupNew" type="text" class="form-control">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-primary">Add</button>
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="importExportModal" class="modal fade" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Import/Export</h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="exportText">Export</label>
|
||||||
|
<textarea id="exportText" class="form-control" rows="4"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="importText">Import</label>
|
||||||
|
<textarea id="importText" class="form-control" rows="4"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" id="btnImport" class="btn btn-primary">Import</button>
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="aboutModal" class="modal fade" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">About</h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p>
|
||||||
|
<a href="https://github.com/NeilBrommer/NewTabPage">Project on GitHub</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
This page keeps a list of bookmarks separated into groups. It's intended to be used a a new tab page.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
It uses localStorage to store the list of bookmarks rather than storing them server side.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The format for the import/export JSON is:
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"title": "Group title",
|
||||||
|
"bookmarks": [
|
||||||
|
{
|
||||||
|
"name": "Bookmark 1",
|
||||||
|
"address": "http://example.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bookmark 2",
|
||||||
|
"address": "http://example.net"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Group 2",
|
||||||
|
"bookmarks": [
|
||||||
|
{
|
||||||
|
"name": "Bookmark 3",
|
||||||
|
"address": "http://example.org"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Bootstrap core JavaScript
|
||||||
|
================================================== -->
|
||||||
|
<!-- Placed at the end of the document so the pages load faster -->
|
||||||
|
<script src="js/jquery-3.2.1.min.js"></script>
|
||||||
|
<script src="js/popper.js"></script>
|
||||||
|
<script src="bootstrap/js/bootstrap.min.js"></script>
|
||||||
|
<script src="js/main.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
145
js/main.js
Normal file
145
js/main.js
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
$(document).ready(function () {
|
||||||
|
calcBackground();
|
||||||
|
loadBookmarks();
|
||||||
|
|
||||||
|
$("#importExportModal").on("shown.bs.modal", function () {
|
||||||
|
var data = getListString();
|
||||||
|
if (data != null)
|
||||||
|
$("#exportText").text(data);
|
||||||
|
else
|
||||||
|
$("#exportText").text("[]");
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#newBookmarkModal").on("shown.bs.modal", function () {
|
||||||
|
var combo = $("#newBookmarkGroup");
|
||||||
|
var data = getList();
|
||||||
|
for (var i = 0; i < data.length; i++) {
|
||||||
|
combo.append($("<option></option>").attr({ "value": i }).text(data[i].title));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO complete adding bookmarks
|
||||||
|
window.alert("Adding bookmarks is still incomplete");
|
||||||
|
$("#newBookmarkModal").modal("hide");
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#btnImport").click(importBookmarks);
|
||||||
|
$("#exportText").click(function () {
|
||||||
|
$("#exportText").select();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function importBookmarks() {
|
||||||
|
try {
|
||||||
|
var newData = $.parseJSON($("#importText").val());
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Import failed: " + err.message);
|
||||||
|
window.alert("Failed to import");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setList(newData);
|
||||||
|
|
||||||
|
$(".bookmarkGroup").remove();
|
||||||
|
loadBookmarks();
|
||||||
|
$("#importExportModal").modal("hide");
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadBookmarks() {
|
||||||
|
var groups = getList();
|
||||||
|
|
||||||
|
if (groups != null) {
|
||||||
|
for (var i = 0; i < groups.length; i++) {
|
||||||
|
var item = groups[i];
|
||||||
|
buildCard(item.title, item.bookmarks);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$("#aboutModal").modal("show");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildCard(title, itemList) {
|
||||||
|
var card = $(document.createElement("div"));
|
||||||
|
card.attr({ "id": "group-" + title, "class": "card bookmarkGroup" });
|
||||||
|
|
||||||
|
var cardHead = $(document.createElement("div"));
|
||||||
|
cardHead.attr({ "class": "card-header" });
|
||||||
|
cardHead.text(title);
|
||||||
|
card.append(cardHead);
|
||||||
|
|
||||||
|
var cardList = $(document.createElement("div"));
|
||||||
|
cardList.attr({ "class": "list-group list-group-flush" });
|
||||||
|
card.append(cardList);
|
||||||
|
|
||||||
|
for (var i = 0; i < itemList.length; i++) {
|
||||||
|
var item = itemList[i];
|
||||||
|
var link = $(document.createElement("a"));
|
||||||
|
link.attr({
|
||||||
|
"class": "list-group-item list-group-item-action",
|
||||||
|
"href": item.address
|
||||||
|
});
|
||||||
|
link.text(item.name);
|
||||||
|
|
||||||
|
cardList.append(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#cardList").append(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectGroupChanged(value) {
|
||||||
|
if (value == "-")
|
||||||
|
$("#createGroup").show();
|
||||||
|
else
|
||||||
|
$("#createGroup").hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
function calcBackground() {
|
||||||
|
var now = new Date();
|
||||||
|
var hours = now.getHours();
|
||||||
|
var mins = now.getMinutes();
|
||||||
|
var total = (hours * 60) + mins;
|
||||||
|
|
||||||
|
// 24*60 = 1440
|
||||||
|
// 2:40 between each step
|
||||||
|
if (total > 300 && total < 460) // 5:00 - 7:40
|
||||||
|
setBackground(1, false);
|
||||||
|
else if (total > 460 && total < 620)
|
||||||
|
setBackground(2, false);
|
||||||
|
else if (total > 620 && total < 780)
|
||||||
|
setBackground(3, false);
|
||||||
|
else if (total > 780 && total < 940)
|
||||||
|
setBackground(4, false);
|
||||||
|
else if (total > 940 && total < 1100)
|
||||||
|
setBackground(5, false);
|
||||||
|
else if (total > 1100 && total < 1260)
|
||||||
|
setBackground(6, true);
|
||||||
|
else if (total > 1260 && total < 1420)
|
||||||
|
setBackground(7, true);
|
||||||
|
else
|
||||||
|
setBackground(8, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setBackground(num, dark) {
|
||||||
|
$("body").css("background-image", "url(img/" + num + ".png)");
|
||||||
|
if (dark)
|
||||||
|
$(".btn-light").removeClass("btn-light").addClass("btn-dark");
|
||||||
|
else
|
||||||
|
$(".btn-dark").removeClass("btn-dark").addClass("btn-light");
|
||||||
|
}
|
||||||
|
|
||||||
|
function getList() {
|
||||||
|
return $.parseJSON(window.localStorage.getItem("bookmarks"));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getListString() {
|
||||||
|
return window.localStorage.getItem("bookmarks");
|
||||||
|
}
|
||||||
|
|
||||||
|
function setList(list) {
|
||||||
|
if (typeof list == "string") {
|
||||||
|
window.localStorage.setItem("bookmarks", list);
|
||||||
|
} else {
|
||||||
|
var stringified = JSON.stringify(list, null, 4);
|
||||||
|
window.localStorage.setItem("bookmarks", stringified);
|
||||||
|
}
|
||||||
|
}
|
68
main.css
Normal file
68
main.css
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: white no-repeat center center fixed;
|
||||||
|
background-size: cover;
|
||||||
|
|
||||||
|
tab-size: 4;
|
||||||
|
-moz-tab-size: 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
#wrapper {
|
||||||
|
width: 60%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
background-color: #FEA63C;
|
||||||
|
color: white;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
height: 32px;
|
||||||
|
padding-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-group-item {
|
||||||
|
height: 32px;
|
||||||
|
padding-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
border: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar {
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* change the number of columns in card-columns */
|
||||||
|
@media (min-width: 34em) {
|
||||||
|
.card-columns {
|
||||||
|
-webkit-column-count: 1;
|
||||||
|
-moz-column-count: 1;
|
||||||
|
column-count: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 48em) {
|
||||||
|
.card-columns {
|
||||||
|
-webkit-column-count: 1;
|
||||||
|
-moz-column-count: 1;
|
||||||
|
column-count: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 62em) {
|
||||||
|
.card-columns {
|
||||||
|
-webkit-column-count: 2;
|
||||||
|
-moz-column-count: 2;
|
||||||
|
column-count: 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 75em) {
|
||||||
|
.card-columns {
|
||||||
|
-webkit-column-count: 2;
|
||||||
|
-moz-column-count: 2;
|
||||||
|
column-count: 2;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue