diff --git a/server.js b/server.js
index aaa8da5..03ac3ff 100644
--- a/server.js
+++ b/server.js
@@ -9,6 +9,7 @@ const fetch = require('node-fetch');
const IMAGE_PATH = "./images";
+
// express config
const app = express();
const port = 3000;
@@ -18,6 +19,14 @@ app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json());
app.set('json spaces', 2);
+// emulate slow down
+app.use( (req,res,next) => {
+ console.log("slow...");
+ setTimeout(() => {
+ next();
+ }, 2000);
+});
+
const OK = {status: "ok"};
const NOT_FOUND = {status: "error", error: "not found"};
const ALREADY_EXISTS = {status: "error", error: "already exists"};
@@ -28,7 +37,6 @@ initDb();
// list boards
app.get("/api/boards", async (req, res) => {
try{
- await sleep(1000);
let boards = db.prepare("SELECT * FROM boards").all();
for( let i = 0; i < boards.length; ++i ){
@@ -50,7 +58,8 @@ app.get("/api/boards", async (req, res) => {
// get board
app.get("/api/boards/:boardId", async (req, res) => {
try{
- await sleep(1000);
+
+
let board = db.prepare("SELECT * FROM boards WHERE id = ?").get(req.params.boardId);
if ( board ){
@@ -103,8 +112,7 @@ app.post("/api/boards/:boardId", (req, res) =>{
// delete board
app.delete("/api/boards/:boardId", async (req, res) => {
- try{
- await sleep(1000);
+ try{
let pins = db.prepare("SELECT id FROM pins WHERE boardId = ?").all(req.params.boardId);
for ( let i = 0; i < pins.length; ++i ){
@@ -141,20 +149,10 @@ app.get("/api/pins/:pinId", (req, res) => {
}
});
-async function sleep(millis){
- return new Promise( (resolve,reject) => {
- setTimeout(() => {
- resolve();
- }, millis)
- });
-}
-
// create pin
app.post("/api/pins", async (req, res) => {
try {
- await sleep(1000);
-
console.log(req.body);
let image = await downloadImage(req.body.imageUrl);
@@ -248,9 +246,6 @@ app.post("/api/pins/:pinId", (req,res) => {
});
app.delete("/api/pins/:pinId", async (req, res) => {
-
- await sleep(1000);
-
try {
await fs.unlink(getThumbnailImagePath(req.params.pinId).file);
diff --git a/static/app.js b/static/app.js
index a2b9f1d..474c703 100644
--- a/static/app.js
+++ b/static/app.js
@@ -19,6 +19,8 @@ app.addSetter("load.boards", async (data) => {
let res = await fetch("/api/boards");
data.boards = await res.json();
+
+ data.initialized = true;
store.do("loader.hide");
});
@@ -54,10 +56,12 @@ let store = new Reef.Store({
hash: {
board: null
},
+ initialized: false,
loading: 0,
boards: [],
board: null,
addPinModal: {
+ pinId: null,
active: false,
boardId: "",
newBoardName: null,
@@ -78,6 +82,12 @@ let store = new Reef.Store({
editBoardModal: {
active: false,
name: ""
+ },
+ editPinModal: {
+ active: false,
+ pin: null,
+ newBoardName: null,
+ saveInProgress: false
}
},
getters: app.getGetters(),
@@ -108,6 +118,7 @@ const appComponent = new Reef("#app", {
+
`
//
}
diff --git a/static/client.css b/static/client.css
index ce3c042..1ea12e8 100644
--- a/static/client.css
+++ b/static/client.css
@@ -64,33 +64,34 @@
object-fit: contain;
}
-#addPinModal-boardName {
+#addPinModal-boardName, #editPinModal-boardName {
font-weight: bold;
}
-#addPinModal .add-pin-flex {
+#addPinModal .add-pin-flex, #editPinModal .add-pin-flex {
display: flex;
}
-#addPinModal .add-pin-flex-left {
+#addPinModal .add-pin-flex-left, #editPinModal .add-pin-flex-left {
flex: 1;
margin: 10px;
margin-top: 40px;
}
-#addPinModal .add-pin-flex-left img{
+#addPinModal .add-pin-flex-left img, #editPinModal .add-pin-flex-left img{
border-radius: 12px;
width: 100%;
height: auto;
display: block;
}
-#addPinModal .add-pin-flex-right {
+#addPinModal .add-pin-flex-right, #editPinModal .add-pin-flex-right {
flex: 2;
margin: 10px;
}
+
#footer {
padding: 1rem 1.5rem 1rem;
}
@@ -156,8 +157,6 @@
opacity: 1;
}
-
-
#pinZoomModal .pinZoomModal-description {
position: fixed;
height: 24px;
diff --git a/static/components/brickwall.js b/static/components/brickwall.js
index ff634fa..8b5f864 100644
--- a/static/components/brickwall.js
+++ b/static/components/brickwall.js
@@ -4,10 +4,27 @@ app.addComponent('brickwall', (store) => { return new Reef('#brickwall', {
template: (data, el) => {
// if the hash says we are supposed to be drawing a board, but it hasn't loaded yet... draw an empty div.
- if ( data.hash.board && !data.board ){
+ if ( !data.initialized || (data.hash.board && !data.board) ){
return '';
}
+ if ( data.hash.board && data.board.pins.length == 0 ){
+ return `
+
This board has no pins :(
+
+
`;
+
+ } else if ( !data.hash.board && data.boards.length == 0 ){
+ return `
+
There are no boards :(
+
+
`;
+ }
+
let numberOfColumns = 1;
let width = el.offsetWidth;
// matching bulma breakpoints - https://bulma.io/documentation/overview/responsiveness/
diff --git a/static/components/editpin.js b/static/components/editpin.js
new file mode 100644
index 0000000..696b514
--- /dev/null
+++ b/static/components/editpin.js
@@ -0,0 +1,203 @@
+app.addSetter('editPinModal.open', (data) => {
+ data.editPinModal.active = true;
+});
+
+app.addSetter('editPinModal.close', (data) => {
+ data.editPinModal.active = false;
+
+ data.editPinModal.pin = null;
+ data.editPinModal.newBoardName = null;
+ data.editPinModal.saveInProgress = false;
+});
+
+app.addGetter('editPinModal.isValid', (data) => {
+
+ if ( !data.editPinModal.pin ){
+ return false;
+ }
+
+ if ( data.editPinModal.boardId == "new"){
+ if ( !data.editPinModal.newBoardName ){
+ return false;
+ } else if ( data.editPinModal.newBoardName.trim().length < 1 ){
+ return false;
+ }
+ }
+
+ let pin = getPinById(data.editPinModal.pin.id);
+
+ if ( pin.siteUrl == data.editPinModal.pin.siteUrl &&
+ pin.description == data.editPinModal.pin.description &&
+ pin.boardId == data.editPinModal.pin.boardId ){
+ return false;
+ }
+
+ return true;
+});
+
+app.addSetter("editPinModal.save", async (data) => {
+
+ store.do("loader.show");
+
+ data.editPinModal.saveInProgress = true;
+
+ let pin = data.editPinModal.pin;
+
+ let boardId = data.editPinModal.pin.boardId;
+
+ let newBoard = null;
+
+ if ( boardId == "new" ){
+
+ // TODO: make a helper method
+ let res = await fetch("/api/boards", {
+ method: 'POST',
+ headers: {'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ "name": data.editPinModal.newBoardName
+ })
+ });
+
+ if ( res.status == 200 ){
+ newBoard = await res.json();
+ boardId = newBoard.id;
+ data.boards.push(newBoard);
+ }
+
+ }
+
+ let postData = {
+ boardId: boardId,
+ siteUrl: pin.siteUrl,
+ description: pin.description
+ };
+
+ let res = await fetch('api/pins/' + pin.id, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify(postData)
+ });
+
+ if ( res.status == 200 ){
+ console.log(`updated pin#${pin.id}`);
+
+ // update the local copy of the pin
+ let idx = getPinIndexById(pin.id);
+ data.board.pins[idx].boardId = boardId;
+ data.board.pins[idx].siteUrl = pin.siteUrl;
+ data.board.pins[idx].description = pin.description;
+
+ console.log(data.board.pins[idx]);
+
+ store.do("editPinModal.close");
+ } else {
+ console.log(`error updating pin#${pin.id}`);
+ }
+
+ store.do("loader.hide");
+
+});
+
+
+app.addComponent('editPinModal', (store) => { return new Reef("#editPinModal", {
+
+ store: store,
+ template: (data) => {
+
+ let options = "";
+ for ( let i = 0; i < data.boards.length; ++i ){
+ options += ``;
+ }
+
+ console.log("render", data);
+
+ console.log("set new board field");
+ let newBoardField = '';
+ if ( data.editPinModal.pin && data.editPinModal.pin.boardId == "new" ){
+ // if ( true ) {
+ console.log("is new");
+ newBoardField = /*html*/`
+
+ `;
+ }
+
+ if ( data.editPinModal.pin ){
+ console.log(getThumbnailImagePath(data.editPinModal.pin.id));
+ }
+
+
+
+ return /*html*/`
+
+
+
+
+
+
+
+
+
 : ''})
+
+
+
+
+
+
+
+
+
+ `;
+
+ }
+
+}); });
\ No newline at end of file
diff --git a/static/components/pinzoom.js b/static/components/pinzoom.js
index a720550..99f692e 100644
--- a/static/components/pinzoom.js
+++ b/static/components/pinzoom.js
@@ -32,7 +32,9 @@ app.addSetter('pinZoomModal.open', (data, el) => {
let pinId = el.getAttribute("data-pinid");
if( pinId ){
- data.pinZoomModal.pin = getPinById(pinId);
+ let idx = getPinIndexById(pinId);
+
+ data.pinZoomModal.pin = data.board.pins[idx];
data.pinZoomModal.active = true;
}
@@ -101,6 +103,16 @@ app.addSetter('pinZoomModal.deletePin', async (data) => {
store.do('loader.hide');
});
+app.addSetter('pinZoomModal.editPin', (data) => {
+
+ // intentially read from store so we get an immutable copy
+ data.editPinModal.pin = store.data.pinZoomModal.pin;
+
+ console.log(data.editPinModal.pin);
+ store.do('editPinModal.open');
+
+});
+
app.addComponent('pinZoomModal', (store) => { return new Reef("#pinZoomModal", {
store: store,
template: (data) => {
diff --git a/static/index.html b/static/index.html
index aa8b47a..d1741e8 100644
--- a/static/index.html
+++ b/static/index.html
@@ -27,6 +27,7 @@
+