mirror of
https://github.com/slynn1324/tinypin.git
synced 2026-01-22 18:16:28 +00:00
checked off items
This commit is contained in:
parent
b79827087b
commit
da9d05597b
14 changed files with 221 additions and 79 deletions
|
|
@ -6,3 +6,6 @@
|
|||
.git
|
||||
docker-run.sh
|
||||
docker-build.sh
|
||||
images
|
||||
images*
|
||||
*.db*
|
||||
|
|
|
|||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,6 +1,8 @@
|
|||
images
|
||||
images*
|
||||
node_modules
|
||||
tinypin.db
|
||||
tinypin.db*
|
||||
.DS_Store
|
||||
chrome-extension.crx
|
||||
chrome-extension.pem
|
||||
10
TODO.md
10
TODO.md
|
|
@ -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--
|
||||
|
||||
|
|
|
|||
138
server.js
138
server.js
|
|
@ -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,65 +503,102 @@ 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.prepare(`
|
||||
CREATE TABLE users (
|
||||
id INTEGER NOT NULL PRIMARY KEY,
|
||||
username TEXT NOT NULL UNIQUE,
|
||||
key TEXT NOT NULL,
|
||||
salt TEXT NOT NULL,
|
||||
createDate TEXT
|
||||
)
|
||||
`).run();
|
||||
db.transaction( () => {
|
||||
|
||||
db.prepare(`
|
||||
CREATE TABLE properties (
|
||||
key TEXT NOT NULL UNIQUE PRIMARY KEY,
|
||||
value TEXT NOT NULL
|
||||
db.prepare(`
|
||||
CREATE TABLE users (
|
||||
id INTEGER NOT NULL PRIMARY KEY,
|
||||
username TEXT NOT NULL UNIQUE,
|
||||
key TEXT NOT NULL,
|
||||
salt TEXT NOT NULL,
|
||||
createDate TEXT
|
||||
)
|
||||
`).run();
|
||||
`).run();
|
||||
|
||||
db.prepare(`
|
||||
CREATE TABLE boards (
|
||||
id INTEGER NOT NULL PRIMARY KEY,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
userId INTEGER NOT NULL,
|
||||
createDate TEXT,
|
||||
|
||||
FOREIGN KEY (userId) REFERENCES users(id)
|
||||
db.prepare(`
|
||||
CREATE TABLE properties (
|
||||
key TEXT NOT NULL UNIQUE PRIMARY KEY,
|
||||
value TEXT NOT NULL
|
||||
)
|
||||
`).run();
|
||||
|
||||
db.prepare(`
|
||||
CREATE TABLE boards (
|
||||
id INTEGER NOT NULL PRIMARY KEY,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
userId INTEGER NOT NULL,
|
||||
createDate TEXT,
|
||||
|
||||
FOREIGN KEY (userId) REFERENCES users(id)
|
||||
)
|
||||
`).run();
|
||||
|
||||
// autoincrement on pins so that pin ids are stable and are not reused.
|
||||
// this allows for better caching of images
|
||||
db.prepare(`
|
||||
CREATE TABLE pins (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
boardId INTEGER NOT NULL,
|
||||
imageUrl TEXT,
|
||||
siteUrl TEXT,
|
||||
description TEXT,
|
||||
sortOrder INTEGER,
|
||||
originalHeight INTEGER,
|
||||
originalWidth INTEGER,
|
||||
thumbnailHeight INTEGER,
|
||||
thumbnailWidth INTEGER,
|
||||
userId INTEGER NOT NULL,
|
||||
createDate TEXT,
|
||||
|
||||
FOREIGN KEY (boardId) REFERENCES boards(id),
|
||||
FOREIGN KEY (userId) REFERENCES users(id)
|
||||
)
|
||||
`).run();
|
||||
`).run();
|
||||
|
||||
// autoincrement on pins so that pin ids are stable and are not reused.
|
||||
// this allows for better caching of images
|
||||
db.prepare(`
|
||||
CREATE TABLE pins (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
boardId INTEGER NOT NULL,
|
||||
imageUrl TEXT,
|
||||
siteUrl TEXT,
|
||||
description TEXT,
|
||||
sortOrder INTEGER,
|
||||
originalHeight INTEGER,
|
||||
originalWidth INTEGER,
|
||||
thumbnailHeight INTEGER,
|
||||
thumbnailWidth INTEGER,
|
||||
userId INTEGER NOT NULL,
|
||||
createDate TEXT,
|
||||
db.prepare("INSERT INTO properties (key, value) VALUES (@key, @value)").run({key: "cookieKey", value: crypto.randomBytes(32).toString('hex')});
|
||||
db.prepare("INSERT INTO migrations (id, createDate) VALUES ( @id, @createDate )").run({id:1, createDate: new Date().toISOString()});
|
||||
|
||||
FOREIGN KEY (boardId) REFERENCES boards(id),
|
||||
FOREIGN KEY (userId) REFERENCES users(id)
|
||||
)
|
||||
`).run();
|
||||
schemaVersion = 1;
|
||||
|
||||
db.prepare("INSERT INTO properties (key, value) VALUES (@key, @value)").run({key: "cookieKey", value: crypto.randomBytes(32).toString('hex')});
|
||||
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}`);
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@ app.addComponent('aboutModal', (store) => { return new Reef("#aboutModal", {
|
|||
<br />
|
||||
missing icon » <a href="https://materialdesignicons.com/icon/dots-square">dots-square by Jeff Hilnbrand</a>
|
||||
<br />
|
||||
hidden icon » <a href="https://thenounproject.com/term/hidden/3543981/">hidden by vittorio longo from the Noun Project</a>
|
||||
<br />
|
||||
<br />
|
||||
server
|
||||
<br />
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -37,6 +43,11 @@ app.addComponent('brickwall', (store) => { return new Reef('#brickwall', {
|
|||
numberOfColumns = 3;
|
||||
} else if ( width > 320 ){
|
||||
numberOfColumns = 2;
|
||||
}
|
||||
|
||||
|
||||
if ( !data.hash.board && width < 400 ){
|
||||
numberOfColumns = 1;
|
||||
}
|
||||
|
||||
function createBrickForBoard(board){
|
||||
|
|
@ -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
|
||||
|
|
@ -79,8 +97,10 @@ app.addComponent('brickwall', (store) => { return new Reef('#brickwall', {
|
|||
bricks.push(createBrickForPin(data.board, data.board.pins[i]));
|
||||
}
|
||||
} else {
|
||||
for ( let i = 0; i < data.boards.length; ++i ){
|
||||
bricks.push(createBrickForBoard(data.boards[i]));
|
||||
for ( let i = 0; i < data.boards.length; ++i ){
|
||||
if ( data.showHiddenBoards || !data.boards[i].hidden ) {
|
||||
bricks.push(createBrickForBoard(data.boards[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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>';
|
||||
|
|
|
|||
|
|
@ -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
|
||||
})
|
||||
});
|
||||
|
||||
|
|
@ -105,6 +114,11 @@ app.addComponent('editBoardModal', (store) => { return new Reef("#editBoardModal
|
|||
<input class="input" type="text" data-bind="editBoardModal.name" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" data-bind="editBoardModal.hidden" value="1">
|
||||
Hidden
|
||||
</label>
|
||||
|
||||
</section>
|
||||
<footer class="modal-card-foot">
|
||||
|
|
|
|||
|
|
@ -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} </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">
|
||||
|
|
@ -72,11 +98,13 @@ app.addComponent('navbar', (store) => { return new Reef("#navbar", {
|
|||
<span>about tinypin</span>
|
||||
<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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ){
|
||||
|
|
|
|||
|
|
@ -56,6 +56,9 @@
|
|||
</div>
|
||||
<script>
|
||||
|
||||
// clear previously stored values
|
||||
window.localStorage.clear();
|
||||
|
||||
if ( window.location.hash == "#nope" ){
|
||||
document.getElementById("nope").innerText = "nope.";
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue