checked off items

This commit is contained in:
slynn1324 2021-01-24 11:16:09 -06:00
parent b79827087b
commit da9d05597b
14 changed files with 221 additions and 79 deletions

View file

@ -6,3 +6,6 @@
.git
docker-run.sh
docker-build.sh
images
images*
*.db*

2
.gitignore vendored
View file

@ -1,6 +1,8 @@
images
images*
node_modules
tinypin.db
tinypin.db*
.DS_Store
chrome-extension.crx
chrome-extension.pem

10
TODO.md
View file

@ -1,9 +1,9 @@
# todo list
- update brick layout algo to be height aware, rather than simply add to columns in order
- check breakpoints for iOS
- add hidden flag to boards / control
- --update brick layout algo to be height aware, rather than simply add to columns in order--
- --check breakpoints for iOS--
- --add hidden flag to boards / control--
- add change password function
- add logged in user name to menu
- addpin.html remember last board
- --add logged in user name to menu--
- --addpin.html remember last board--

View file

@ -200,6 +200,7 @@ app.use ( async (req, res, next) => {
if ( !req.user ){
res.redirect("/login");
return;
}
if ( req.method == "GET" && req.originalUrl == "/logout" ){
@ -247,6 +248,10 @@ const ALREADY_EXISTS = {status: "error", error: "already exists"};
const SERVER_ERROR = {status: "error", error: "server error"};
app.get("/api/whoami", (req, res) => {
res.send({name: req.user.name});
});
// list boards
app.get("/api/boards", async (req, res) => {
try{
@ -290,7 +295,7 @@ app.get("/api/boards/:boardId", async (req, res) => {
// create board
app.post('/api/boards', (req, res) => {
try{
let result = db.prepare("INSERT INTO boards (name, userId, createDate) VALUES (@name, @userId, @createDate)").run({name: req.body.name, userId: req.user.id, createDate: new Date().toISOString()});
let result = db.prepare("INSERT INTO boards (name, userId, hidden, createDate) VALUES (@name, @userId, @hidden, @createDate)").run({name: req.body.name, userId: req.user.id, hidden: req.body.hidden, createDate: new Date().toISOString()});
let id = result.lastInsertRowid;
let board = db.prepare("SELECT * FROM boards WHERE userId = @userId and id = @boardId").get({userId: req.user.id, boardId: id});
board.titlePinId = 0;
@ -310,7 +315,7 @@ app.post('/api/boards', (req, res) => {
// update board
app.post("/api/boards/:boardId", (req, res) =>{
try{
let result = db.prepare("UPDATE boards SET name = @name WHERE userId = @userId and id = @boardId").run({name: req.body.name, userId: req.user.id, boardId: req.params.boardId});
let result = db.prepare("UPDATE boards SET name = @name, hidden = @hidden WHERE userId = @userId and id = @boardId").run({name: req.body.name, hidden: req.body.hidden, userId: req.user.id, boardId: req.params.boardId});
if ( result.changes == 1 ){
res.send(OK);
} else {
@ -498,10 +503,15 @@ function initDb(){
`).run();
let schemaVersion = db.prepare('select max(id) as id from migrations').get().id;
let isNewDb = false;
let createdBackup = false;
if ( !schemaVersion || schemaVersion < 1 ){
console.log(" running migration v1");
isNewDb = true;
db.transaction( () => {
db.prepare(`
CREATE TABLE users (
@ -557,6 +567,38 @@ function initDb(){
db.prepare("INSERT INTO migrations (id, createDate) VALUES ( @id, @createDate )").run({id:1, createDate: new Date().toISOString()});
schemaVersion = 1;
})();
}
if ( schemaVersion < 2 ){
console.log(" running migration v2");
if ( !isNewDb ){
let backupPath = DB_PATH + ".backup-" + new Date().toISOString();
console.log(" backing up to: " + backupPath);
db.prepare(`
VACUUM INTO ?
`).run(backupPath);
createdBackup = true;
}
db.transaction( () => {
db.prepare(`
ALTER TABLE boards ADD COLUMN hidden INTEGER
`).run();
db.prepare(`
UPDATE boards SET hidden = 0
`).run();
db.prepare(`
INSERT INTO migrations (id, createDate) VALUES ( @id, @createDate )
`).run({id:2, createDate: new Date().toISOString()});
schemaVersion = 2;
})();
}
console.log(`database ready - schema version v${schemaVersion}`);

View file

@ -77,7 +77,9 @@ app.addSetter("load.boards", async (data) => {
data.initialized = true;
if ( data.boards && data.boards.length > 0 ){
if ( window.localStorage.addPinLastBoardId ){
data.addPinModal.boardId = window.localStorage.addPinLastBoardId;
} else if ( data.boards && data.boards.length > 0 ){
data.addPinModal.boardId = data.boards[0].id;
} else {
data.addPinModal.boardId = "new";
@ -87,7 +89,6 @@ app.addSetter("load.boards", async (data) => {
});
app.addSetter('addPinModal.updatePreview', (data) => {
console.log("update preview");
if ( data.addPinModal.imageUrl.startsWith("http") ){
( async() => {
let res = await fetch(data.addPinModal.imageUrl, {
@ -161,6 +162,7 @@ app.addSetter('addPinModal.save', async (data) => {
});
if ( res.status == 200 ){
window.localStorage.addPinLastBoardId = boardId;
window.close();
}
@ -228,7 +230,7 @@ const appComponent = new Reef("#app", {
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Add Pin</p>
<p class="modal-card-title">Add Pin ${data.addPinModal.boardId}</p>
<div id="loader" class="button is-text ${data.loading ? 'is-loading' : ''}"></div>
</header>
<section class="modal-card-body">

View file

@ -36,6 +36,15 @@ app.addSetter('load.board', async (data) => {
store.do("loader.hide");
});
app.addSetter('load.user', async (data) => {
store.do("loader.show");
let res = await fetch("/api/whoami");
data.user = await res.json();
store.do("loader.hide");
});
app.addSetter("hash.update", (data) => {
console.log("hash update");
data.hash = parseQueryString(window.location.hash.substr(1));
@ -59,6 +68,8 @@ let store = new Reef.Store({
initialized: false,
menuOpen: false,
loading: 0,
user: null,
showHiddenBoards: window.localStorage.showHiddenBoards == "true" || false,
boards: [],
board: null,
addPinModal: {
@ -82,7 +93,8 @@ let store = new Reef.Store({
},
editBoardModal: {
active: false,
name: ""
name: "",
hidden: 0
},
editPinModal: {
active: false,
@ -203,6 +215,7 @@ window.addEventListener('resize', (evt) => {
Reef.databind(appComponent);
store.do('load.user');
store.do('load.boards');
store.do('hash.update');

View file

@ -11,7 +11,7 @@
margin: 0 5px 10px 5px;
}
.brick img {
.brick img.thumb {
width: 100%;
height: auto;
display: block;
@ -40,7 +40,7 @@
width: 100%;
}
.board-brick a img{
.board-brick a img.thumb{
height: 200px;
object-fit: cover;
}

View file

@ -42,6 +42,8 @@ app.addComponent('aboutModal', (store) => { return new Reef("#aboutModal", {
<br />
&nbsp;missing icon &raquo; <a href="https://materialdesignicons.com/icon/dots-square">dots-square by Jeff Hilnbrand</a>
<br />
&nbsp;hidden icon &raquo; <a href="https://thenounproject.com/term/hidden/3543981/">hidden by vittorio longo from the Noun Project</a>
<br />
<br />
server
<br />

View file

@ -2,6 +2,8 @@ app.addSetter('addPinModal.open', (data) => {
if ( data.board ){
data.addPinModal.boardId = data.board.id;
} else if ( window.localStorage.addPinLastBoardId ){
data.addPinModal.boardId = window.localStorage.addPinLastBoardId;
} else if ( data.boards && data.boards.length > 0 ){
data.addPinModal.boardId = data.boards[0].id;
} else {
@ -91,6 +93,7 @@ app.addSetter('addPinModal.save', async (data) => {
newBoard.titlePinId = body.id;
}
window.localStorage.addPinLastBoardId = boardId;
store.do("addPinModal.close");
}

View file

@ -1,3 +1,8 @@
app.addSetter('brickwall.toggleHiddenBoards', (data) => {
data.showHiddenBoards = !data.showHiddenBoards;
window.localStorage.showHiddenBoards = data.showHiddenBoards;
});
app.addComponent('brickwall', (store) => { return new Reef('#brickwall', {
store: store,
@ -27,7 +32,8 @@ app.addComponent('brickwall', (store) => { return new Reef('#brickwall', {
// TODO: check these breakpoints for iPhone
let numberOfColumns = 1;
let width = el.offsetWidth;
let width = window.innerWidth; //el.offsetWidth;
// matching bulma breakpoints - https://bulma.io/documentation/overview/responsiveness/
if( width >= 1216 ){
numberOfColumns = 5;
@ -39,6 +45,11 @@ app.addComponent('brickwall', (store) => { return new Reef('#brickwall', {
numberOfColumns = 2;
}
if ( !data.hash.board && width < 400 ){
numberOfColumns = 1;
}
function createBrickForBoard(board){
// https://materialdesignicons.com/icon/dots-square
@ -46,29 +57,36 @@ app.addComponent('brickwall', (store) => { return new Reef('#brickwall', {
let boardImage = null;
if ( board.titlePinId > 0 ){
boardImage = `<img src="${getThumbnailImagePath(board.titlePinId)}" />`;
boardImage = `<img class="thumb" src="${getThumbnailImagePath(board.titlePinId)}" />`;
} else {
boardImage = `<div class="board-brick-missing-thumbnail"><img src="${missingThumbnailSrc}" /></div>`;
boardImage = `<div class="board-brick-missing-thumbnail"><img class="thumb" src="${missingThumbnailSrc}" /></div>`;
}
return /*html*/`
let hiddenBoardImage = '';
if ( board.hidden ){
hiddenBoardImage = '<img alt="(hidden)" style="width: 24px; height: 24px; vertical-align: middle;" src="data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9JzMwMHB4JyB3aWR0aD0nMzAwcHgnICBmaWxsPSIjMDAwMDAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGRhdGEtbmFtZT0iTGF5ZXIgMSIgdmlld0JveD0iMCAwIDI0IDI0IiB4PSIwcHgiIHk9IjBweCI+PHRpdGxlPkFydGJvYXJkIDY8L3RpdGxlPjxwYXRoIGQ9Ik0xMiw2LjkyQTguNjUsOC42NSwwLDAsMSwxOS44NSwxMmE4LjYxLDguNjEsMCwwLDEtMTUuNywwQTguNjUsOC42NSwwLDAsMSwxMiw2LjkybTAtMkExMC42MiwxMC42MiwwLDAsMCwyLDEyYTEwLjYsMTAuNiwwLDAsMCwyMCwwQTEwLjYyLDEwLjYyLDAsMCwwLDEyLDQuOTJaIj48L3BhdGg+PHBhdGggZD0iTTE0LjIxLDExLjEyYTEuMzQsMS4zNCwwLDAsMS0xLjMzLTEuMzMsMS4zMSwxLjMxLDAsMCwxLC41Mi0xQTMuNDQsMy40NCwwLDAsMCwxMiw4LjQ2LDMuNTQsMy41NCwwLDEsMCwxNS41NCwxMmEzLjQ0LDMuNDQsMCwwLDAtLjI5LTEuNEExLjMxLDEuMzEsMCwwLDEsMTQuMjEsMTEuMTJaIj48L3BhdGg+PHBhdGggZD0iTTE5LDIwYTEsMSwwLDAsMS0uNzEtLjI5bC0xNC0xNEExLDEsMCwwLDEsNS43MSw0LjI5bDE0LDE0YTEsMSwwLDAsMSwwLDEuNDJBMSwxLDAsMCwxLDE5LDIwWiI+PC9wYXRoPjwvc3ZnPg==" />';
}
return { height: 1, template: /*html*/`
<div class="brick board-brick">
<a href="#board=${board.id}">
${boardImage}
<div class="board-brick-name">${board.name}</div>
<div class="board-brick-name">${board.name}
${hiddenBoardImage}
</div>
</a>
</div>
`;
`};
}
function createBrickForPin(board, pin){
return /*html*/`
return { height: pin.thumbnailHeight, template: /*html*/`
<div class="brick" >
<a data-pinid="${pin.id}" data-onclick="pinZoomModal.open">
<img src="${getThumbnailImagePath(pin.id)}" width="${pin.thumbnailWidth}" height="${pin.thumbnailHeight}" />
<img class="thumb" src="${getThumbnailImagePath(pin.id)}" width="${pin.thumbnailWidth}" height="${pin.thumbnailHeight}" />
</a>
</div>
`;
`};
}
// create the brick elements
@ -80,9 +98,11 @@ app.addComponent('brickwall', (store) => { return new Reef('#brickwall', {
}
} else {
for ( let i = 0; i < data.boards.length; ++i ){
if ( data.showHiddenBoards || !data.boards[i].hidden ) {
bricks.push(createBrickForBoard(data.boards[i]));
}
}
}
// create column objects
let columns = [];
@ -96,7 +116,19 @@ app.addComponent('brickwall', (store) => { return new Reef('#brickwall', {
// TODO: make this height aware
// sort bricks into columns
for ( let i = 0; i < bricks.length; ++i ){
columns[i % columns.length].bricks.push(bricks[i]);
// find shortest column
let shortestIndex = 0;
let shortestHeight = columns[0].height;
for ( let c = 1; c < columns.length; ++c ){
if ( columns[c].height < shortestHeight ){
shortestIndex = c;
shortestHeight = c.height;
}
}
columns[shortestIndex].bricks.push(bricks[i]);
columns[shortestIndex].height += bricks[i].height;
}
@ -107,7 +139,7 @@ app.addComponent('brickwall', (store) => { return new Reef('#brickwall', {
result += '<div class="brickwall-column">';
for ( let i = 0; i < columns[col].bricks.length; ++i ){
result += columns[col].bricks[i];
result += columns[col].bricks[i].template;
}
result += '</div>';

View file

@ -1,10 +1,12 @@
app.addSetter('editBoardModal.open', (data) => {
data.editBoardModal.name = data.board.name;
data.editBoardModal.hidden = data.board.hidden;
data.editBoardModal.active = true;
});
app.addSetter('editBoardModal.close', (data) => {
data.editBoardModal.name = "";
data.editBoardModal.hidden = 0;
data.editBoardModal.active = false;
});
@ -14,11 +16,17 @@ app.addSetter('editBoardModal.save', async (data) => {
let boardId = data.board.id;
let name = data.editBoardModal.name;
let hidden = data.editBoardModal.hidden;
let idx = getBoardIndexById(boardId);
if ( idx >= 0 ){
data.boards[idx].name = name;
data.boards[idx].hidden = hidden;
}
if ( data.board ){
data.board.name = name;
data.board.hidden = hidden;
}
let res = await fetch(`/api/boards/${boardId}`, {
@ -27,7 +35,8 @@ app.addSetter('editBoardModal.save', async (data) => {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: name
name: name,
hidden: hidden
})
});
@ -106,6 +115,11 @@ app.addComponent('editBoardModal', (store) => { return new Reef("#editBoardModal
</div>
</div>
<label class="checkbox">
<input type="checkbox" data-bind="editBoardModal.hidden" value="1">
Hidden
</label>
</section>
<footer class="modal-card-foot">
<button class="button is-success ${data.editBoardModal.saveInProgress ? 'is-loading' : '' }" ${!store.get('editBoardModal.isValid') || data.editBoardModal.saveInProgress ? 'disabled' : ''} data-onclick="editBoardModal.save">Save</button>

View file

@ -20,11 +20,17 @@ app.addComponent('navbar', (store) => { return new Reef("#navbar", {
let boardName = "";
let hiddenBoardImage = '';
if ( data.board && data.board.hidden ){
hiddenBoardImage = '<img alt="(hidden)" style="width: 16px; height: 16px; vertical-align: middle; margin-top: 2px;" src="data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9JzMwMHB4JyB3aWR0aD0nMzAwcHgnICBmaWxsPSIjMDAwMDAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGRhdGEtbmFtZT0iTGF5ZXIgMSIgdmlld0JveD0iMCAwIDI0IDI0IiB4PSIwcHgiIHk9IjBweCI+PHRpdGxlPkFydGJvYXJkIDY8L3RpdGxlPjxwYXRoIGQ9Ik0xMiw2LjkyQTguNjUsOC42NSwwLDAsMSwxOS44NSwxMmE4LjYxLDguNjEsMCwwLDEtMTUuNywwQTguNjUsOC42NSwwLDAsMSwxMiw2LjkybTAtMkExMC42MiwxMC42MiwwLDAsMCwyLDEyYTEwLjYsMTAuNiwwLDAsMCwyMCwwQTEwLjYyLDEwLjYyLDAsMCwwLDEyLDQuOTJaIj48L3BhdGg+PHBhdGggZD0iTTE0LjIxLDExLjEyYTEuMzQsMS4zNCwwLDAsMS0xLjMzLTEuMzMsMS4zMSwxLjMxLDAsMCwxLC41Mi0xQTMuNDQsMy40NCwwLDAsMCwxMiw4LjQ2LDMuNTQsMy41NCwwLDEsMCwxNS41NCwxMmEzLjQ0LDMuNDQsMCwwLDAtLjI5LTEuNEExLjMxLDEuMzEsMCwwLDEsMTQuMjEsMTEuMTJaIj48L3BhdGg+PHBhdGggZD0iTTE5LDIwYTEsMSwwLDAsMS0uNzEtLjI5bC0xNC0xNEExLDEsMCwwLDEsNS43MSw0LjI5bDE0LDE0YTEsMSwwLDAsMSwwLDEuNDJBMSwxLDAsMCwxLDE5LDIwWiI+PC9wYXRoPjwvc3ZnPg==" />';
}
if ( data.board ){
boardName = /*html*/`
<span class="navbar-item">
<span>${data.board.name} &nbsp;</span>
<a data-onclick="editBoardModal.open"><img style="margin-top: -4px;" alt="edit" width="16" height="16" src="data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9JzMwMHB4JyB3aWR0aD0nMzAwcHgnICBmaWxsPSIjMDAwMDAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGRhdGEtbmFtZT0iTGF5ZXIgMSIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHg9IjBweCIgeT0iMHB4Ij48dGl0bGU+NTE8L3RpdGxlPjxwYXRoIGQ9Ik04NC44NTAxMiw1MFY4MS43NDUxMkExMy4yNzAxMiwxMy4yNzAxMiwwLDAsMSw3MS41OTUyNCw5NUgxOC4yNTQ5MUExMy4yNzAxMiwxMy4yNzAxMiwwLDAsMSw1LDgxLjc0NTEyVjI4LjQwNTI4QTEzLjI3MDEyLDEzLjI3MDEyLDAsMCwxLDE4LjI1NDkxLDE1LjE1MDRINTBhMi41LDIuNSwwLDAsMSwwLDVIMTguMjU0OTFBOC4yNjQyMyw4LjI2NDIzLDAsMCwwLDEwLDI4LjQwNTI4VjgxLjc0NTEyQTguMjY0MjQsOC4yNjQyNCwwLDAsMCwxOC4yNTQ5MSw5MEg3MS41OTUyNGE4LjI2NDIzLDguMjY0MjMsMCwwLDAsOC4yNTQ4OC04LjI1NDg5VjUwYTIuNSwyLjUsMCwwLDEsNSwwWk04OS4xNDg0Niw2LjIzNzkyYTQuMjI2NjEsNC4yMjY2MSwwLDAsMC01Ljk3NzI5LDBsLTMzLjk2MjksMzMuOTYzTDU5Ljc5OTE2LDUwLjc5MTc2bDMzLjk2Mjg5LTMzLjk2M2E0LjIyNjUzLDQuMjI2NTMsMCwwLDAsMC01Ljk3NzIzWk00My42MjM4LDU4LjMxMjg3bDEzLjAwOTQtNC4zNTUxNkw0Ni4wNDIyNiw0My4zNjY4M2wtNC4zNTUxLDEzLjAwOTRBMS41MzAwNSwxLjUzMDA1LDAsMCwwLDQzLjYyMzgsNTguMzEyODdaIj48L3BhdGg+PC9zdmc+" /></a>
<span>${data.board.name}</span>
${hiddenBoardImage}
<a data-onclick="editBoardModal.open"><img style="margin-left: 5px; margin-top: -3px; vertical-align: middle;" alt="edit" width="16" height="16" src="data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9JzMwMHB4JyB3aWR0aD0nMzAwcHgnICBmaWxsPSIjMDAwMDAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGRhdGEtbmFtZT0iTGF5ZXIgMSIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHg9IjBweCIgeT0iMHB4Ij48dGl0bGU+NTE8L3RpdGxlPjxwYXRoIGQ9Ik04NC44NTAxMiw1MFY4MS43NDUxMkExMy4yNzAxMiwxMy4yNzAxMiwwLDAsMSw3MS41OTUyNCw5NUgxOC4yNTQ5MUExMy4yNzAxMiwxMy4yNzAxMiwwLDAsMSw1LDgxLjc0NTEyVjI4LjQwNTI4QTEzLjI3MDEyLDEzLjI3MDEyLDAsMCwxLDE4LjI1NDkxLDE1LjE1MDRINTBhMi41LDIuNSwwLDAsMSwwLDVIMTguMjU0OTFBOC4yNjQyMyw4LjI2NDIzLDAsMCwwLDEwLDI4LjQwNTI4VjgxLjc0NTEyQTguMjY0MjQsOC4yNjQyNCwwLDAsMCwxOC4yNTQ5MSw5MEg3MS41OTUyNGE4LjI2NDIzLDguMjY0MjMsMCwwLDAsOC4yNTQ4OC04LjI1NDg5VjUwYTIuNSwyLjUsMCwwLDEsNSwwWk04OS4xNDg0Niw2LjIzNzkyYTQuMjI2NjEsNC4yMjY2MSwwLDAsMC01Ljk3NzI5LDBsLTMzLjk2MjksMzMuOTYzTDU5Ljc5OTE2LDUwLjc5MTc2bDMzLjk2Mjg5LTMzLjk2M2E0LjIyNjUzLDQuMjI2NTMsMCwwLDAsMC01Ljk3NzIzWk00My42MjM4LDU4LjMxMjg3bDEzLjAwOTQtNC4zNTUxNkw0Ni4wNDIyNiw0My4zNjY4M2wtNC4zNTUxLDEzLjAwOTRBMS41MzAwNSwxLjUzMDA1LDAsMCwwLDQzLjYyMzgsNTguMzEyODdaIj48L3BhdGg+PC9zdmc+" /></a>
</span>`;
} else if ( !data.hash.board ) {
boardName = /*html*/`<span class="navbar-item">Boards</span>`;
@ -41,6 +47,26 @@ app.addComponent('navbar', (store) => { return new Reef("#navbar", {
`;
}
let hiddenBoardsItem = '';
let hasHiddenBoards = false;
for ( let i = 0; i < data.boards.length; ++i ){
if ( data.boards[i].hidden == true ){
hasHiddenBoards = true;
break;
}
}
if (hasHiddenBoards) {
hiddenBoardsItem = `
<a class="navbar-item has-text-right" data-onclick="brickwall.toggleHiddenBoards">
<span>${data.showHiddenBoards ? 'hide hidden boards' : 'show hidden boards'}</span>
<img style="24px; height:24px;" src="data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9JzMwMHB4JyB3aWR0aD0nMzAwcHgnICBmaWxsPSIjMDAwMDAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGRhdGEtbmFtZT0iTGF5ZXIgMSIgdmlld0JveD0iMCAwIDI0IDI0IiB4PSIwcHgiIHk9IjBweCI+PHRpdGxlPkFydGJvYXJkIDY8L3RpdGxlPjxwYXRoIGQ9Ik0xMiw2LjkyQTguNjUsOC42NSwwLDAsMSwxOS44NSwxMmE4LjYxLDguNjEsMCwwLDEtMTUuNywwQTguNjUsOC42NSwwLDAsMSwxMiw2LjkybTAtMkExMC42MiwxMC42MiwwLDAsMCwyLDEyYTEwLjYsMTAuNiwwLDAsMCwyMCwwQTEwLjYyLDEwLjYyLDAsMCwwLDEyLDQuOTJaIj48L3BhdGg+PHBhdGggZD0iTTE0LjIxLDExLjEyYTEuMzQsMS4zNCwwLDAsMS0xLjMzLTEuMzMsMS4zMSwxLjMxLDAsMCwxLC41Mi0xQTMuNDQsMy40NCwwLDAsMCwxMiw4LjQ2LDMuNTQsMy41NCwwLDEsMCwxNS41NCwxMmEzLjQ0LDMuNDQsMCwwLDAtLjI5LTEuNEExLjMxLDEuMzEsMCwwLDEsMTQuMjEsMTEuMTJaIj48L3BhdGg+PHBhdGggZD0iTTE5LDIwYTEsMSwwLDAsMS0uNzEtLjI5bC0xNC0xNEExLDEsMCwwLDEsNS43MSw0LjI5bDE0LDE0YTEsMSwwLDAsMSwwLDEuNDJBMSwxLDAsMCwxLDE5LDIwWiI+PC9wYXRoPjwvc3ZnPg==" />
</a>`;
}
return /*html*/`
<nav class="navbar is-light" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
@ -73,10 +99,12 @@ app.addComponent('navbar', (store) => { return new Reef("#navbar", {
<img alt="about" style="width:24px;height:24px;" src="data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9JzMwMHB4JyB3aWR0aD0nMzAwcHgnICBmaWxsPSIjMDAwMDAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGRhdGEtbmFtZT0iTGF5ZXIgMSIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHg9IjBweCIgeT0iMHB4Ij48dGl0bGU+QXJ0Ym9hcmQgNzwvdGl0bGU+PHJlY3QgeD0iNDciIHk9IjQ5IiB3aWR0aD0iNiIgaGVpZ2h0PSIxNSI+PC9yZWN0PjxjaXJjbGUgY3g9IjUwIiBjeT0iMzkiIHI9IjMiPjwvY2lyY2xlPjxwYXRoIGQ9Ik01MCwyMEEzMCwzMCwwLDAsMCwyMCw1MGEyNy44OCwyNy44OCwwLDAsMCwzLjM1LDEzLjc0bC0zLDguMjFhNiw2LDAsMCwwLDcuNjksNy42OWw4LjIxLTNBMjcuODgsMjcuODgsMCwwLDAsNTAsODBhMzAsMzAsMCwxLDAsMC02MFptMCw1NGEyMS4wOCwyMS4wOCwwLDAsMS0xMy00TDI2LDc0bDQtMTFhMjEuMDgsMjEuMDgsMCwwLDEtNC0xM0EyNCwyNCwwLDEsMSw1MCw3NFoiPjwvcGF0aD48L3N2Zz4=" />
</a>
${hiddenBoardsItem}
${refreshItem}
<a class="navbar-item has-text-right" data-onclick="navbar.logout">
<span>log out</span>
<span>log out ${data.user ? data.user.name : ''}</span>
<img alt="log out" width="32" height="32" src="data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9JzMwMHB4JyB3aWR0aD0nMzAwcHgnICBmaWxsPSIjMDAwMDAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGRhdGEtbmFtZT0iTGF5ZXIgMSIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHg9IjBweCIgeT0iMHB4Ij48dGl0bGU+QXJ0Ym9hcmQgODQ8L3RpdGxlPjxnPjxwYXRoIGQ9Ik0yOCw4MkgzOFY3NEgyOGEyLDIsMCwwLDEtMi0yVjI4YTIsMiwwLDAsMSwyLTJIMzhWMThIMjhBMTAsMTAsMCwwLDAsMTgsMjhWNzJBMTAsMTAsMCwwLDAsMjgsODJaIj48L3BhdGg+PHBhdGggZD0iTTY2LDMyLjM0LDYwLjM0LDM4bDgsOEgzNHY4SDY4LjM0bC04LDhMNjYsNjcuNjYsODAuODMsNTIuODNhNCw0LDAsMCwwLDAtNS42NloiPjwvcGF0aD48L2c+PC9zdmc+" />
<a>

View file

@ -106,13 +106,12 @@ Reef.databind = function(reef){
let store = reef.store;
if ( !store ){
console.log("Databind only works when using a store.");
console.error("Databind only works when using a store.");
return;
}
// bind all elements on the page that have a data-bind item
const bindData = debounce(() => {
console.log("bindData");
let elems = el.querySelectorAll("[data-bind]");
for ( let i = 0; i < elems.length; ++i ){
@ -135,7 +134,6 @@ Reef.databind = function(reef){
// multiple selects need special handling
if ( elem.tagName == "SELECT" && elem.matches("[multiple]") ){
console.log("multiple");
let options = elem.querySelectorAll("option");
for ( let i = 0; i < options.length; ++i ){
if ( val.indexOf(options[i].value) > -1 ){

View file

@ -56,6 +56,9 @@
</div>
<script>
// clear previously stored values
window.localStorage.clear();
if ( window.location.hash == "#nope" ){
document.getElementById("nope").innerText = "nope.";
}