Commit 33c17509 authored by MrMan's avatar MrMan

Merge branch 'build-rhs-content'

parents 636f34f0 6f4a1197
......@@ -3,7 +3,7 @@
[ TODO: MithMail webp ]
This project goes with the [Mithril SystemJS and Rollup guide post over @ vadosware.io](). It's meant to be a demo of how to run the relatively simple combination of [Mithril](https://mithril.js.org/), [SystemJS](https://github.com/systemjs/systemjs)
, and [Rollup](https://rollupjs.org/) all together to write modern [Single Page Applications (SPAs)](https://en.wikipedia.org/wiki/Single-page_application).
, and [Parcel](https://parceljs.org/) all together to write modern [Single Page Applications (SPAs)](https://en.wikipedia.org/wiki/Single-page_application).
Here are the pieces and how they fit together:
......@@ -15,4 +15,20 @@ For more background on these tools, check out their doucmentation/websites below
[Mithril](https://mithril.js.org/)
[SystemJS (v2.0+)](https://github.com/systemjs/systemjs)
[Rollup](https://rollupjs.org/)
[Parcel](https://parceljs.org/)
## Development ##
Development work flow consists of starting the following:
```shell
$ yarn build-watch # in the background/another window so you can see output
$ yarn serve # in the background/another window
$ emacs -nw <file> # the lightest operating system you'll ever use which also happens to edit text
```
## FAQ ##
**What happened to [Rollup](https://rollupjs.org/)?**
Well half way through I decided after fiddling with Rollup and it's various plugins that facilitate front end development I realized how bad the usage story was in comparison to [Parcel](https://parceljs.org) (which I've used in the past) -- so I decided to use parcel for the main branch and make an offshoot that switches to Rollup (if I do it at all). The concrete advantages of Rollup over Parcel seem to be few and far between these days so while I like Rollup (or more precisely I am a fan of [SystemJS](https://github.com/systemjs/systemjs) and the integration it had with [JSPM](https://jspm.org/) of old), I'm not going to torture myself (and by proxy any readers) setting up Rollup (I'm doing it from scratch) when Parcel offers an easy and relatively equally functional alternative.
......@@ -44,15 +44,70 @@ var LHS_LABEL_ITEMS = [
},
];
var ONE_MINUTE_MS = 1000 * 60;
var ONE_HOUR_MS = 60 * ONE_MINUTE_MS;
var ONE_DAY_MS = 24 * ONE_HOUR_MS;
var ONE_WEEK_MS = 27 * ONE_DAY_MS;
function randomPastDate() {
var mins = Math.floor(Math.random() * 60) * ONE_MINUTE_MS;
var hours = Math.floor(Math.random() * 24) * ONE_HOUR_MS;
var days = Math.floor(Math.random() * 7) * ONE_DAY_MS;
return new Date(new Date().getTime() - mins - hours - days);
}
var EMAILS = [
{
from: {name: "Victor Erixon", email: "victor.erixon@example.com"},
subject: "Theories of Design",
text: "Molestias deserunt veritatis modi ut fugiat sint. Dolorum vel autem sint. Dolores accusamus dolores occaecati tenetur adipisci asperiores",
sendDate: randomPastDate(),
},
{
from: {name: "Jacob Hubertus", email: "jacob.hubertus@example.com"},
subject: "Street Photography",
text: "Molestias deserunt veritatis modi ut fugiat sint. Dolorum vel autem sint. Dolores accusamus dolores occaecati tenetur adipisci asperiores",
sendDate: randomPastDate(),
},
{
from: {name: "August Berglund", email: "august.berglund@example.com"},
subject: "HTML+CSS Tutorials?",
text: "Molestias deserunt veritatis modi ut fugiat sint. Dolorum vel autem sint. Dolores accusamus dolores occaecati tenetur adipisci asperiores",
sendDate: randomPastDate(),
},
{
from: {name: "Rick Brunstedt", email: "rick.brunstedt@example.com"},
subject: "Train Crossing",
text: "Molestias deserunt veritatis modi ut fugiat sint. Dolorum vel autem sint. Dolores accusamus dolores occaecati tenetur adipisci asperiores",
sendDate: randomPastDate(),
},
{
from: {name: "Webydo Team", email: "team@webydo.com"},
subject: "Does Webydo have what you're looking for? ",
text: "Molestias deserunt veritatis modi ut fugiat sint. Dolorum vel autem sint. Dolores accusamus dolores occaecati tenetur adipisci asperiores",
sendDate: randomPastDate(),
},
];
EMAILS = EMAILS.sort(function(a, b) {
var aTime = a.sendDate.getTime();
var bTime = b.sendDate.getTime();
if (aTime < aTime) { return -1; }
if (bTime > bTime) { return 1; }
return 0;
});
var ELLIPSIS_CHAR_LIMIT = 60;
////////////////////
// LHS Navigation //
////////////////////
var HeaderButton = {
view: function(vnode) {
const text = vnode.attrs.title || "Compose Mail";
const iconName = vnode.attrs.iconName || "pencil-white.svg";
const iconPrefix = "static/images/icons/";
var text = vnode.attrs.title || "Compose Mail";
var iconName = vnode.attrs.iconName || "pencil-white.svg";
var iconPrefix = "static/images/icons/";
return m("button", {class: "component header-button"}, [
m("span", text),
......@@ -137,14 +192,14 @@ var NavItemListing = {
var LHSNavPageList = {
view: function() {
const navItems = LHS_NAV_ITEMS;
var navItems = LHS_NAV_ITEMS;
return m(NavItemListing, {items: navItems});
}
};
var LHSNavLabelList = {
view: function() {
const labelItems = LHS_LABEL_ITEMS;
var labelItems = LHS_LABEL_ITEMS;
return m(NavItemListing, {items: labelItems});
}
};
......@@ -162,14 +217,238 @@ var LHSNav = {
}
};
var MailContent = {
///////////////
// RHS Pages //
///////////////
var RHSHeader = {
view: function(vnode) {
var title = vnode.attrs.title || "Title";
var bgColor = vnode.attrs.bgColor || "#2285c6";
var newCount = vnode.attrs.newCount;
return m("div.component.rhs-header.flex", {class: vnode.attrs.class}, [
m(".title-container", [
m("span.title", title),
newCount ? m("span.new-count", "(" + newCount + ")"): undefined,
]),
m(".controls", [
m("input.search-box[type='text'][placeholder='Search']"),
m("img.sm-margin-left.icon", {src: "static/images/icons/settings-white.svg"}),
m("img.sm-margin-left.avatar", {src: "static/images/example-avatar.jpg"}),
])
]);
}
};
var MultiSelectCheckbox = {
view: function() {
return m("div", {class: "component mail-content"}, [
m("h1", "RHS Stuff here"),
return m("span.component.multi-select-checkbox.gray-boxed.clickable", [
m("input[type=checkbox]"),
m("img.xs-margin-left.icon", {src: "static/images/icons/chevron-down.svg"}),
]);
}
};
var ButtonGroup = {
view: function(vnode) {
return m("span.component.button-group", {class: vnode.attrs.class}, vnode.children);
}
};
var DropDownButton = {
view: function(vnode) {
var title = vnode.attrs.title || "Button";
return m("button.component.drop-down-button.gray-boxed.clickable", [
m("span", title),
m("img.xs-margin-left.icon", {src: "static/images/icons/chevron-down.svg"}),
]);
}
};
var PaginationControls = {
view: function(vnode) {
var title = vnode.attrs.title || "Button";
var lowerBound = 0;
var upperBound = 50;
var boundStatement = lowerBound + " - " + upperBound;
var total = 100;
return m(".component.pagination-controls", [
m("strong", boundStatement),
m("span", " of "),
m("strong", total),
m("img.xs-margin-left.icon-lg.gray-boxed.valign-mid", {src: "static/images/icons/chevron-left.svg"}),
m("img.xs-margin-left.icon-lg.gray-boxed.valign-mid", {src: "static/images/icons/chevron-right.svg"}),
]);
}
};
var EmailListItem = {
view: function(vnode) {
var email = vnode.attrs.email;
var textContent = email.text || "";
var formattedSendDate = email.sendDate.toLocaleString();
return m(".component.email-list-item", [
m(".header", [
m(".lhs", [
m("input[type=checkbox]", {
onclick: function() {
if (vnode.attrs.onSelected) {
vnode.attrs.onSelected(email);
}
}
}),
m("span.sm-margin-left.sender", email.from.name),
m("span.sm-margin-left.tag", email.label),
]),
m(".rhs", [
m(".date", formattedSendDate)
])
]),
m(".blurb.md-margin-top", [
m("p.subject", email.subject),
// This is not a great way to do ellipsis but... it'll work for the demo.
m("p.body-preview", textContent.substring(0, ELLIPSIS_CHAR_LIMIT) + "..."),
]),
]);
}
};
var EmailList = {
oninit: function() {
this.selectedEmails = {};
},
view: function(vnode) {
var emails = vnode.attrs.emails || [];
return m(".component.email-list", emails.map(function(email) {
return m(EmailListItem, {
email: email,
onEmailSelect: function(email) { this.selectedEmails[email.id] = true; },
});
}));
}
};
var MailPageSubNav = {
view: function(vnode) {
// Container with buttons
return m(".component.mail-page-subnav", [
m(".lhs", [
m(MultiSelectCheckbox),
m(ButtonGroup, {class: "sm-margin-left"}, [
m("button.clickable", "Archive"),
m("button.clickable", "Spam"),
m("button.clickable", "Delete"),
]),
m(ButtonGroup, {class: "sm-margin-left"}, [
m(DropDownButton, {title: "Move to"}),
m(DropDownButton, {title: "Label"}),
]),
]),
m(".rhs", [
m(PaginationControls)
]),
]);
},
};
var InboxPage = {
view: function(vnode) {
var newCount = vnode.attrs.newCount;
return m(".component.inbox-page", [
// Colored header
m(RHSHeader, {class: "inbox-blue-bg white-fg", title: "Inbox", newCount: newCount}),
// Container with buttons
m(MailPageSubNav),
// EmailList
m(EmailList, {emails: EMAILS}),
]);
}
};
var StarredEmailsPage = {
view: function(vnode) {
var newCount = vnode.attrs.newCount;
return m(".component.starred-emails-page", [
// Colored header
m(RHSHeader, {class: "starred-orange-bg white-fg", title: "Inbox", newCount: newCount}),
// Container with buttons
m(MailPageSubNav),
// EmailList
m(EmailList, {emails: EMAILS}),
]);
}
};
var DraftEmailsPage = {
view: function(vnode) {
var newCount = vnode.attrs.newCount;
return m(".component.draft-emails-page", [
// Colored header
m(RHSHeader, {class: "draft-gray-bg white-fg", title: "Inbox", newCount: newCount}),
// Container with buttons
m(MailPageSubNav),
// EmailList
m(EmailList, {emails: EMAILS}),
]);
}
};
var ImportantEmailsPage = {
view: function(vnode) {
var newCount = vnode.attrs.newCount;
return m(".component.important-emails-page", [
// Colored header
m(RHSHeader, {class: "important-gray-bg white-fg", title: "Inbox", newCount: newCount}),
// Container with buttons
m(MailPageSubNav),
// EmailList
m(EmailList, {emails: EMAILS}),
]);
}
};
var MailContent = {
oninit: function() {
this.subpage = "inbox";
},
view: function() {
// TODO: decide *which* view to show
switch (this.subpage) {
case "starred": return m(StarredEmailsPage);
case "draft": return m(DraftEmailsPage);
case "draft": return m(ImportantEmailsPage);
case "inbox":
default:
return m(InboxPage, {newCount: 2});
}
}
};
var App = {
view: function() {
return m("div", {class: "component app"}, [
......
......@@ -13,7 +13,8 @@
"build-js": "cp app.js dist/",
"build-static": "mkdir -p dist && cp -r static dist/",
"build-watch": "ls index.html app.js static/css/app.css | entr -rc npm run build",
"serve": "./node_modules/.bin/http-server dist/"
"serve": "./node_modules/.bin/http-server dist/",
"serve-watch": "ls index.html app.js static/css/app.css | entr -rc bash -c 'npm run build && npm run serve'"
},
"devDependencies": {
"http-server": "^0.11.1"
......
......@@ -5,10 +5,21 @@ html,body {
font-family: sans-serif;
}
img.icon {
height: 1em;
* {
box-sizing: border-box;
}
img.icon { height: 1em; }
img.icon-lg { height: 2em; }
.xs-margin-top { margin-top: 0.5em; }
.xs-margin-left { margin-left: 0.5em; }
.xs-margin-right { margin-right: 0.5em; }
.xs-margin-bottom { margin-bottom: 0.5em; }
.xs-padding-horiz {
padding-left: 0.5em;
padding-right: 0.5em;
}
.sm-margin-top { margin-top: 1em; }
.sm-margin-left { margin-left: 1em; }
......@@ -52,6 +63,19 @@ img.icon {
display: inline-block
}
.inbox-blue-bg { background-color: #2285c6; }
.white-fg { color: white; }
.gray-boxed {
padding: 0.5em;
background-color: #DDD;
border: 1.5px solid #BBB;
}
.clickable { cursor: pointer; }
.valign-mid { vertical-align: middle; }
/*******/
/* App */
/*******/
......@@ -143,3 +167,105 @@ img.icon {
height: 1em;
width: 1em;
}
/*************/
/* RHSHeader */
/*************/
.component.rhs-header {
box-sizing: border-box;
height: 5em;
padding: .5em;
display: flex;
align-items: center;
justify-content: space-between;
}
.component.rhs-header .title { font-size: 2em; }
.component.rhs-header .new-count {
margin-left: .25em;
padding-top: .5em;
}
.component.rhs-header img.avatar {
height: 2em;
vertical-align: middle;
border-radius: 50%;
border: 2px solid #AAA;
}
/***************/
/* ButtonGroup */
/***************/
.component.button-group button {
height: 3em;
padding: 0.5em 1em;
background-color: #EFEFEF;
border: 1.5px solid #BBB;
}
.component.button-group button:first-child {
border-top-left-radius: 0.25em;
border-bottom-left-radius: 0.25em;
}
.component.button-group button:last-child {
border-top-right-radius: 0.25em;
border-bottom-right-radius: 0.25em;
}
/*************/
/* EmailList */
/*************/
.component.email-list {
overflow: none, scroll;
}
/*****************/
/* EmailListItem */
/*****************/
.component.email-list-item .header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0em 1em;
}
.component.email-list-item {
padding: 1em;
border-bottom: 2px solid #EFEFEF;
}
.component.email-list-item .sender {
font-weight: bold;
}
.component.email-list-item .blurb .body-preview {
color: gray;
}
/********************/
/* Mail Page Subnav */
/********************/
.component.mail-page-subnav {
background-color: #EEE;
height: 4em;
display: flex;
align-items: center;
padding-left: 1em;
padding-right: 1em;
justify-content: space-between;
}
/*********/
/* Inbox */
/*********/
.component.inbox-page {
width: 100%;
}
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-down"><polyline points="6 9 12 15 18 9"></polyline></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-left"><polyline points="15 18 9 12 15 6"></polyline></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-right"><polyline points="9 18 15 12 9 6"></polyline></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-settings"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-settings"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment