Mobile reading secret
This commit is contained in:
parent
912c623048
commit
9fb8e50463
|
@ -14,6 +14,7 @@ const {
|
|||
uploadPicture,
|
||||
identityFilename,
|
||||
ssbFolder,
|
||||
isPhone,
|
||||
} = require("./utils");
|
||||
const queries = require("./queries");
|
||||
const serveBlobs = require("./serve-blobs");
|
||||
|
@ -26,7 +27,6 @@ const sgMail = require("@sendgrid/mail");
|
|||
const ejs = require("ejs");
|
||||
const cookieEncrypter = require("cookie-encrypter");
|
||||
const expressLayouts = require("express-ejs-layouts");
|
||||
const isMobile = require("ismobilejs").default;
|
||||
|
||||
let ssbServer;
|
||||
let mode = process.env.MODE || "client";
|
||||
|
@ -85,7 +85,7 @@ const cookieOptions = {
|
|||
httpOnly: true,
|
||||
signed: true,
|
||||
expires: new Date(253402300000000), // Friday, 31 Dec 9999 23:59:59 GMT, nice date from stackoverflow
|
||||
sameSite: true,
|
||||
sameSite: "Lax",
|
||||
};
|
||||
app.use(cookieParser(cookieSecret));
|
||||
app.use(cookieEncrypter(cookieSecret));
|
||||
|
@ -160,7 +160,7 @@ router.get("/", { public: true }, async (req, res) => {
|
|||
if (!req.context.profile) {
|
||||
return res.render("index");
|
||||
}
|
||||
if (isMobile(req.headers["user-agent"]).phone) {
|
||||
if (isPhone(req)) {
|
||||
return res.redirect("/mobile");
|
||||
}
|
||||
|
||||
|
@ -178,10 +178,9 @@ router.get("/", { public: true }, async (req, res) => {
|
|||
});
|
||||
|
||||
router.get("/mobile", async (req, res) => {
|
||||
// TODO
|
||||
// if (!isMobile(req.headers["user-agent"]).phone) {
|
||||
// return res.redirect("/");
|
||||
// }
|
||||
if (!isPhone(req)) {
|
||||
return res.redirect("/");
|
||||
}
|
||||
|
||||
const posts = await queries.getPosts(ssbServer, req.context.profile);
|
||||
|
||||
|
@ -192,6 +191,20 @@ router.get("/mobile", async (req, res) => {
|
|||
});
|
||||
});
|
||||
|
||||
router.get("/mobile/secrets", async (req, res) => {
|
||||
if (!isPhone(req)) {
|
||||
return res.redirect("/");
|
||||
}
|
||||
|
||||
const secretMessages = await queries.getSecretMessages(ssbServer, req.context.profile);
|
||||
|
||||
res.render("mobile/secrets", {
|
||||
secretMessages,
|
||||
profile: req.context.profile,
|
||||
layout: "mobile/_layout",
|
||||
});
|
||||
});
|
||||
|
||||
router.get("/login", { public: true }, (_req, res) => {
|
||||
res.render("login", { mode });
|
||||
});
|
||||
|
|
|
@ -3,6 +3,7 @@ const leftpad = require("left-pad"); // I don't believe I'm depending on this
|
|||
const pull = require("pull-stream");
|
||||
const split = require("split-buffer");
|
||||
const metrics = require("./metrics");
|
||||
const isMobile = require("ismobilejs").default;
|
||||
|
||||
module.exports.asyncRouter = (app) => {
|
||||
const debug = require("debug")("router");
|
||||
|
@ -112,3 +113,7 @@ module.exports.promisePull = (...streams) =>
|
|||
});
|
||||
|
||||
module.exports.mapValues = (x) => x.map((y) => y.value);
|
||||
|
||||
module.exports.isPhone = (req) => {
|
||||
return isMobile(req.headers["user-agent"]).phone;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
/**
|
||||
* Compose Post
|
||||
*/
|
||||
|
||||
const composePost = document.querySelector(".js-compose-post");
|
||||
if (composePost) {
|
||||
const composeButton = document.querySelector(".js-publish-button");
|
||||
composePost.addEventListener("focus", () => {
|
||||
composeButton.style.display = "block";
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Modal
|
||||
*/
|
||||
|
||||
const openModalFor = (elem, onConfirm, afterClose = null) => {
|
||||
const overlay = elem.parentElement.querySelector(".overlay");
|
||||
const modal = elem.parentElement.querySelector(".modal");
|
||||
const confirmButtons = elem.parentElement.querySelectorAll(".modal-confirm");
|
||||
const steps = elem.parentElement.querySelectorAll(".js-step");
|
||||
|
||||
overlay.hidden = false;
|
||||
modal.hidden = false;
|
||||
|
||||
const onClose = () => {
|
||||
overlay.hidden = true;
|
||||
modal.hidden = true;
|
||||
steps.forEach((step) => {
|
||||
step.style.display = "none";
|
||||
});
|
||||
if (steps[0]) steps[0].style.display = "flex";
|
||||
if (afterClose) afterClose();
|
||||
};
|
||||
|
||||
const nextOrConfirm = () => {
|
||||
if (steps.length == 0) {
|
||||
onConfirm();
|
||||
} else {
|
||||
let currentStep;
|
||||
steps.forEach((step, index) => {
|
||||
if (currentStep == index) {
|
||||
step.style.display = "flex";
|
||||
} else if (step.style.display != "none") {
|
||||
currentStep = index;
|
||||
currentStep++;
|
||||
if (currentStep < steps.length) step.style.display = "none";
|
||||
}
|
||||
});
|
||||
if (currentStep == steps.length) {
|
||||
onConfirm();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
overlay.addEventListener("click", onClose);
|
||||
Array.from(confirmButtons).forEach((button) =>
|
||||
button.addEventListener("click", nextOrConfirm)
|
||||
);
|
||||
|
||||
return { close: onClose };
|
||||
};
|
||||
|
||||
/**
|
||||
* Secret Messages Reading
|
||||
*/
|
||||
|
||||
const messages = document.querySelectorAll(".js-secret-message");
|
||||
messages.forEach((message) => {
|
||||
message.addEventListener("click", () => {
|
||||
const afterClose = () => {
|
||||
const parent = message.parentElement;
|
||||
const composeMessage = parent.parentElement.querySelector(
|
||||
".js-compose-secret-message"
|
||||
);
|
||||
composeMessage.style.display = "flex";
|
||||
parent.parentElement.removeChild(parent);
|
||||
};
|
||||
|
||||
const modal = openModalFor(message, () => modal.close(), afterClose);
|
||||
|
||||
fetch("/vanish", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||
body: "keys=" + encodeURIComponent(message.dataset.keys),
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,6 +1,9 @@
|
|||
body {
|
||||
background: #fff;
|
||||
padding-bottom: 70px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
nav {
|
||||
|
@ -42,3 +45,55 @@ nav a.selected {
|
|||
.post {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.modal {
|
||||
top: 100%;
|
||||
left: 0;
|
||||
transform: none;
|
||||
min-width: auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
animation: slide 0.5s forwards;
|
||||
}
|
||||
|
||||
@keyframes slide {
|
||||
100% {
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-group {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
border-bottom: 1px solid #ddd;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.secret-chat {
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
min-width: auto;
|
||||
flex-grow: 1;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.secret-button {
|
||||
padding: 8px 14px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.secret-chat .link-profile-pic {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
</main>
|
||||
<script src="/js/index.js"></script>
|
||||
<script src="/js/desktop.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,25 +1,23 @@
|
|||
<div style="padding-top: 15px;">
|
||||
<% posts.map(post => { %>
|
||||
<% if (!post.content.text) return %>
|
||||
<div class="post">
|
||||
<div>
|
||||
<a href="<%= profileUrl(post.author) %>">
|
||||
<img src="<%= profileImageUrl(post.authorProfile) %>" class="post-profile-pic" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="post-content">
|
||||
<a href="<%= profileUrl(post.author) %>" class="no-link-style">
|
||||
<b><%= post.authorProfile.name %></b>
|
||||
</a>
|
||||
<% let text = post.content.text %>
|
||||
<% if (typeof dont_cut == "undefined") { %>
|
||||
<% text = post.content.text.slice(0, 140) %>
|
||||
<% if (post.content.text.length > 140) text += "..." %>
|
||||
<% } %>
|
||||
<% text.split("\n").map((line, index) => { %>
|
||||
<%- index > 0 ? "<br />" : "" %><%= line %>
|
||||
<% }) %>
|
||||
</div>
|
||||
<% posts.map(post => { %>
|
||||
<% if (!post.content.text) return %>
|
||||
<div class="post">
|
||||
<div>
|
||||
<a href="<%= profileUrl(post.author) %>">
|
||||
<img src="<%= profileImageUrl(post.authorProfile) %>" class="post-profile-pic" />
|
||||
</a>
|
||||
</div>
|
||||
<% }) %>
|
||||
</div>
|
||||
<div class="post-content">
|
||||
<a href="<%= profileUrl(post.author) %>" class="no-link-style">
|
||||
<b><%= post.authorProfile.name %></b>
|
||||
</a>
|
||||
<% let text = post.content.text %>
|
||||
<% if (typeof dont_cut == "undefined") { %>
|
||||
<% text = post.content.text.slice(0, 140) %>
|
||||
<% if (post.content.text.length > 140) text += "..." %>
|
||||
<% } %>
|
||||
<% text.split("\n").map((line, index) => { %>
|
||||
<%- index > 0 ? "<br />" : "" %><%= line %>
|
||||
<% }) %>
|
||||
</div>
|
||||
</div>
|
||||
<% }) %>
|
|
@ -27,15 +27,15 @@
|
|||
</form>
|
||||
|
||||
<h2 style="margin: 0">Your Wall</h2>
|
||||
<% if (posts.length > 0) { %>
|
||||
<%- include('_posts', { posts }) %>
|
||||
<% } else { %>
|
||||
<div style="padding-top: 15px;">
|
||||
<div style="padding: 15px;">
|
||||
<% if (posts.length > 0) { %>
|
||||
<%- include('_posts', { posts }) %>
|
||||
<% } else { %>
|
||||
<div class="post">
|
||||
You have no posts yet, publish something!
|
||||
</div>
|
||||
</div>
|
||||
<% } %>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="friends-communities">
|
||||
|
|
|
@ -14,23 +14,23 @@
|
|||
</div>
|
||||
</header>
|
||||
<nav>
|
||||
<a href="/" class="<%= context.path == "/mobile" ? "selected" : "" %>">
|
||||
<a href="/mobile" class="<%= context.path == "/mobile" ? "selected" : "" %>">
|
||||
<div class="nav-icon">🙂</div>
|
||||
Profile
|
||||
</a>
|
||||
<a href="/secrets">
|
||||
<a href="/mobile/secrets" class="<%= context.path == "/mobile/secrets" ? "selected" : "" %>">
|
||||
<div class="nav-icon">🤫</div>
|
||||
Secrets
|
||||
</a>
|
||||
<a href="/friends">
|
||||
<a href="/mobile/friends" class="<%= context.path == "/mobile/friends" ? "selected" : "" %>">
|
||||
<div class="nav-icon">👨👧👦</div>
|
||||
Friends
|
||||
</a>
|
||||
<a href="/communities">
|
||||
<a href="/mobile/communities" class="<%= context.path == "/mobile/communities" ? "selected" : "" %>">
|
||||
<div class="nav-icon">🌆</div>
|
||||
Communities
|
||||
</a>
|
||||
<a href="/search">
|
||||
<a href="/mobile/search" class="<%= context.path == "/mobile/search" ? "selected" : "" %>">
|
||||
<div class="nav-icon">💬</div>
|
||||
Search
|
||||
</a>
|
||||
|
@ -38,5 +38,7 @@
|
|||
</nav>
|
||||
|
||||
<%- body %>
|
||||
|
||||
<script src="/js/mobile.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -8,6 +8,12 @@
|
|||
</div>
|
||||
|
||||
<% if (posts.length > 0) { %>
|
||||
<form action="/publish" method="POST" style="padding: 0px 8px 5px 8px;">
|
||||
<textarea name="message" class="compose-post js-compose-post" placeholder="Post something on your wall..."></textarea>
|
||||
<div class="reverse-columns">
|
||||
<input type="submit" value="Publish" style="display: none; margin: 5px 0" class="js-publish-button" />
|
||||
</div>
|
||||
</form>
|
||||
<%- include('../_posts', { posts }) %>
|
||||
<% } else { %>
|
||||
<div style="padding-top: 15px;">
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
<div class="secret-chat">
|
||||
<div class="column-side-padding" <%= secretMessages.length > 0 ? "hidden" : "" %> style="margin: 25px 0 20px 0; font-size: 14px;">
|
||||
👻 You don't have any secret messages yet
|
||||
</div>
|
||||
|
||||
<% secretMessages.map(chat => { %>
|
||||
<div>
|
||||
<div>
|
||||
<button class="secret-button js-compose-secret-message" style="<%= chat.messages.length == 0 ? "" : "display: none" %>" data-url="<%= profileUrl(chat.authorProfile.id, "/publish_secret") %>">
|
||||
<img class="link-profile-pic" src="<%= profileImageUrl(chat.authorProfile) %>" class="post-profile-pic" />
|
||||
<div style="flex-grow: 1;">
|
||||
<%= chat.authorProfile.name %> <br />
|
||||
<small>
|
||||
No new secrets
|
||||
</small>
|
||||
</div>
|
||||
</button>
|
||||
<%- include('../secrets/_compose_single', { profile: chat.authorProfile }) %>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button class="secret-button js-secret-message" style="<%= chat.messages.length == 0 ? "display: none" : "" %>" data-keys="<%= chat.messages.map(m => m.key).join(",") %>">
|
||||
<img class="link-profile-pic" src="<%= profileImageUrl(chat.authorProfile) %>" class="post-profile-pic" />
|
||||
<div style="flex-grow: 1;">
|
||||
<%= chat.authorProfile.name %> <br />
|
||||
<small>
|
||||
👁 <%= chat.messages.length == 1 ? "1 new message" : chat.messages.length + " new messages" %>
|
||||
</small>
|
||||
</div>
|
||||
</button>
|
||||
<div class="overlay" hidden></div>
|
||||
<div class="modal" hidden>
|
||||
<% chat.messages.reverse().map((message, index) => { %>
|
||||
<div class="modal-group js-step" <%- index > 0 ? 'style="display: none"' : "" %>>
|
||||
<div class="modal-footer">
|
||||
<% if (index == chat.messages.length - 1) { %>
|
||||
<span></span>
|
||||
<button class="modal-confirm">Close</button>
|
||||
<% } else { %>
|
||||
<span></span>
|
||||
<button class="modal-confirm">Next</button>
|
||||
<% } %>
|
||||
</div>
|
||||
|
||||
<a href="<%= profileUrl(chat.authorProfile.id) %>" class="modal-header">
|
||||
<img src="<%= profileImageUrl(chat.authorProfile) %>" class="post-profile-pic" />
|
||||
<div style="padding-left: 10px"><%= chat.authorProfile.name %></div>
|
||||
</a>
|
||||
<div class="modal-body">
|
||||
<div style="margin-top: -60px"><%= message.value.content.text %></div>
|
||||
</div>
|
||||
</div>
|
||||
<% }) %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% }) %>
|
||||
</div>
|
|
@ -63,15 +63,15 @@
|
|||
</form>
|
||||
|
||||
<h2 style="margin: 0"><%= profile.name %>'s Wall</h2>
|
||||
<% if (posts.length == 0) { %>
|
||||
<div style="padding-top: 15px">
|
||||
<div style="padding-top: 15px;">
|
||||
<% if (posts.length == 0) { %>
|
||||
<div class="post">
|
||||
No posts yet
|
||||
</div>
|
||||
</div>
|
||||
<% } else { %>
|
||||
<%- include('_posts', { posts }) %>
|
||||
<% } %>
|
||||
<% } else { %>
|
||||
<%- include('_posts', { posts }) %>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="friends-communities">
|
||||
|
|
Loading…
Reference in New Issue