More features, more dev life style

release
JD Cantrell 6 years ago
parent 35167888a6
commit e42e6c2e8d

@ -0,0 +1,3 @@
{
"presets": ["env"]
}

@ -0,0 +1,21 @@
{
"env": {
"browser": true,
},
"extends": [
"airbnb-base",
"prettier"
],
"plugins": [
"prettier"
],
"rules": {
"prettier/prettier": [
"error",
{
"singleQuote": true,
"trailingComma": "es5",
}
],
}
}

1
.gitignore vendored

@ -1 +1,2 @@
.DS_Store
node_modules

@ -0,0 +1 @@
8

@ -0,0 +1,258 @@
.pal {
padding: 20px !important; }
.pam {
padding: 10px !important; }
.pas {
padding: 5px !important; }
.pan {
padding: 0 !important; }
.pbl {
padding-bottom: 20px !important; }
.pbm {
padding-bottom: 10px !important; }
.pbs {
padding-bottom: 5px !important; }
.pbn {
padding-bottom: 0 !important; }
.ptl {
padding-top: 20px !important; }
.ptm {
padding-top: 10px !important; }
.pts {
padding-top: 5px !important; }
.ptn {
padding-top: 0 !important; }
.pll {
padding-left: 20px !important; }
.plm {
padding-left: 10px !important; }
.pls {
padding-left: 5px !important; }
.pln {
padding-left: 0 !important; }
.prl {
padding-right: 20px !important; }
.prm {
padding-right: 10px !important; }
.prs {
padding-right: 5px !important; }
.prn {
padding-right: 0 !important; }
.pvl {
padding-top: 20px !important;
padding-bottom: 20px !important; }
.phl {
padding-left: 20px !important;
padding-right: 20px !important; }
.pvm {
padding-top: 10px !important;
padding-bottom: 10px !important; }
.phm {
padding-left: 10px !important;
padding-right: 10px !important; }
.pvs {
padding-top: 5px !important;
padding-bottom: 5px !important; }
.phs {
padding-left: 5px !important;
padding-right: 5px !important; }
.pvn {
padding-top: 0 !important;
padding-bottom: 0 !important; }
.phn {
padding-left: 0 !important;
padding-right: 0 !important; }
html,
body {
font-size: 16px;
font-family: Menlo, Consolas, monospace;
color: #333;
padding: 0;
margin: 0; }
input {
font-size: 16px;
font-family: Menlo, Consolas, monospace;
color: #333; }
.content {
width: 700px;
margin: auto; }
table {
width: 100%;
border-spacing: 0;
border-collapse: separate; }
table .collapsing {
width: 1px;
white-space: nowrap; }
table.hover tbody > tr:hover {
background-color: #dff3ff; }
tr.row-highlight {
background-color: #a6dcfe; }
td, th {
padding: 5px; }
thead {
text-align: left; }
ul {
list-style: none; }
.list-bullets {
list-style: disc; }
.list-inline {
padding: 0;
margin: 0;
display: flex; }
.list-inline li {
display: inline-block;
margin-right: 5px; }
button, .button {
background-color: #f9f9f9;
border-radius: 3px;
border: 1px solid #ccc;
font-family: Menlo, Consolas, monospace;
font-size: 16px;
padding: 10px;
cursor: pointer; }
button:hover, .button:hover {
background-color: #e0e0e0; }
button:active, button.active, .button:active, .button.active {
background-color: lightgray; }
button.primary, .button.primary {
background-color: #0087dd;
border-radius: 3px;
padding: 10px;
color: #fff;
border: 1px solid #ccc;
border-color: #004977; }
button.primary:hover, .button.primary:hover {
background-color: #0068aa; }
button.primary:active, button.primary.active, .button.primary:active, .button.primary.active {
background-color: #005891; }
.button-group {
font-size: 0;
display: inline-block; }
.button-group button, .button-group .button {
border-radius: 0;
border-left-width: 0;
border-right-width: 0; }
.button-group button:first-child, .button-group .button:first-child {
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
border-left-width: 1px !important; }
.button-group button:last-child, .button-group .button:last-child {
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
border-right-width: 1px !important; }
.box {
border-radius: 3px;
border: 1px solid #ccc; }
.box header {
border-bottom: 1px solid #ccc;
padding: 20px; }
.box .box-content {
padding: 20px; }
.box footer {
padding: 20px;
border-top: 1px solid #ccc;
text-align: right; }
.toolbar {
display: flex;
border-bottom: 3px solid #0087dd;
padding: 8px;
margin: 0 4px 15px;
align-items: center;
justify-content: space-between; }
.toolbar .toolbar-header {
display: inline-block;
font-size: 20px;
font-weight: bold; }
.align-center {
text-align: center;
justify-content: center; }
.align-right {
text-align: right;
justify-content: right; }
.align-left {
text-align: left;
justify-content: left; }
.flex-container {
align-items: center;
justify-content: center;
display: flex; }
.flex-container.column {
flex-direction: column; }
.flex-container.row {
flex-direction: row; }
.flex-container > .start {
align-items: center;
justify-content: flex-start;
display: flex; }
.flex-container > .end {
align-items: center;
justify-content: flex-end;
display: flex; }
.flex-container > .flex-1 {
flex-basis: auto;
flex-shrink: 0;
flex-grow: 1; }
.flex-container > .flex-2 {
flex-basis: auto;
flex-shrink: 0;
flex-grow: 2; }
.flex-container > .flex-3 {
flex-basis: auto;
flex-shrink: 0;
flex-grow: 3; }
.padding-char-horizontal {
padding-left: 1em;
padding-right: 1em; }
.emphasize {
font-weight: bold; }
.caps {
text-transform: uppercase; }

@ -0,0 +1,79 @@
@font-face {
font-family: 'Fantasque Sans Mono';
src: url('/fonts/FantasqueSansMono-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
body, textarea {
font-family: 'Fantasque Sans Mono', monospace;
color: #4f4b51;
font-size: 18px;
}
textarea {
resize: vertical;
border: none;
padding: 0;
margin: 0;
width: 100%;
margin-bottom: 18.6667px;
}
.header {
padding: 10px 15px;
}
.columns {
display: flex;
flex-grow: columns;
justify-content: center;
}
.columns > div {
flex: 1;
max-width: 400px;
padding: 30px;
}
.blockTitle {
font-size: 36px;
line-height: 38px;
}
.add {
}
.addColumn {
flex: 0 !important;
width: 24px;
}
.color08 { color: #d8137f; }
.color09 { color: #d65407; }
.color0A { color: #dc8a0e; }
.color0B { color: #17ad98; }
.color0C { color: #149bda; }
.color0D { color: #775dff; }
.color0E { color: #aa17e6; }
.color0F { color: #e013d0; }
.tools {
list-style: none;
margin: 0;
padding: 0;
font-size: 0;
}
.tools li {
display: inline-block;
}
.with-tools {
margin-bottom: 0;
}
.icon {
vertical-align: text-bottom;
display: inline-block;
}

@ -3,90 +3,18 @@
<head>
<title>Hello there!</title>
<meta charset="utf-8" />
<link rel="stylesheet" media="screen" href="https://fontlibrary.org/face/fantasque-sans-mono" type="text/css"/>
<style>
body, textarea {
font-family: 'FantasqueSansMonoRegular', monospace;
color: #4f4b51;
font-size: 18px;
}
textarea {
resize: vertical;
border: none;
padding: 0;
margin: 0;
width: 100%;
margin-bottom: 18.6667px;
}
.columns {
display: flex;
flex-grow: columns;
justify-content: center;
}
.columns > div {
flex: 1;
max-width: 400px;
padding: 10px;
}
.blockTitle {
font-size: 36px;
line-height: 38px;
}
.add {
text-align: center;
}
.addColumn {
flex: 0 !important;
width: 24px;
}
.color08 { color: #d8137f; }
.color09 { color: #d65407; }
.color0A { color: #dc8a0e; }
.color0B { color: #17ad98; }
.color0C { color: #149bda; }
.color0D { color: #775dff; }
.color0E { color: #aa17e6; }
.color0F { color: #e013d0; }
.tools {
list-style: none;
margin: 0;
padding: 0;
font-size: 0;
}
.tools li {
display: inline-block;
}
.with-tools {
margin-bottom: 0;
}
.icon {
vertical-align: middle;
display: inline-block;
}
</style>
</head>
<link rel="stylesheet" type="text/css" href="/css/mono.css" />
<link rel="stylesheet" type="text/css" href="/css/sparkbot.css" />
</head>
<body>
<div id="sparkbot">
<div class="header">
<div class="header flex-container row">
<div>sparkbot</div>
<div>Move a little bit further every day</div>
<div class="flex-1 align-center">Move a little bit further every day</div>
<div>
<div class="icon" v-on:click="edit=!edit">
<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="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 class="icon" 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="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>
</div>
August 12, 2017
</div>
@ -95,24 +23,16 @@
<div class="columns">
<div v-for="blocks in content">
<div v-for="block in blocks">
<template v-if="edit">
<textarea rows="1" :class="block.titleClass + ' with-tools blockTitle'" spellcheck="false" v-autosize v-model="block.title"></textarea>
<ul class="tools">
<li v-on:click="remove(block)"><img width="24" height="24" src="img/trash-2.svg"></li>
<li v-on:click="block.titleClass=nextClass(block.titleClass)" :class="block.titleClass">
<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"><path d="M20.24 12.24a6 6 0 0 0-8.49-8.49L5 10.5V19h8.5z"></path><line x1="16" y1="8" x2="2" y2="22"></line><line x1="17" y1="15" x2="9" y2="15"></line></svg>
</li>
</ul>
</template>
<textarea v-else rows="1" :class="block.titleClass + ' with-tools blockTitle'" spellcheck="false" v-autosize v-model="block.title"></textarea>
<textarea spellcheck="false" v-autosize v-model="block.content"></textarea>
<note-block v-model="block.data" v-on:remove="remove(block)" :edit="edit"></note-block>
</div>
<div class="add" v-on:click="add(blocks)" v-if="edit">
<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-plus-circle"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="16"></line><line x1="8" y1="12" x2="16" y2="12"></line></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="icon icon-plus-circle"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="16"></line><line x1="8" y1="12" x2="16" y2="12"></line></svg>
Add Section
</div>
</div>
<div class="addColumn" v-on:click="add()" v-if="edit">
<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-plus-circle"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="16"></line><line x1="8" y1="12" x2="16" y2="12"></line></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="icon icon-plus-circle"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="16"></line><line x1="8" y1="12" x2="16" y2="12"></line></svg>
Add Column
</div>
</div>

@ -1,77 +1,97 @@
'use strict';
const classNames = [
'color08',
'color09',
'color0A',
'color0B',
'color0C',
'color0D',
'color0E',
'color0F',
]
// based off of https://codepen.io/supraniti/pen/Lypobx
Vue.component('heading',{
template:'<h1 :class="classname" contenteditable="true" @input="update"></h1>',
props:['content', 'classname'],
mounted:function(){
this.$el.innerText = this.content;
},
methods:{
update:function(event){
this.$emit('update',event.target.innerText);
}
}
})
/* globals Vue, autosize */
var classNames = ['color08', 'color09', 'color0A', 'color0B', 'color0C', 'color0D', 'color0E', 'color0F'];
Vue.directive('autosize', {
inserted: function (el) {
inserted: function initAutosize(el) {
autosize(el);
}
});
const app = new Vue({
el: "#sparkbot",
data: {
edit: true,
content: [
[
{
title: 'Daily',
titleClass: 'color08',
content: 'bleh theres things'
},
{
title: 'Notes',
titleClass: 'color09',
content: 'okay yea things'
},
],
[
{
title: 'Second Column',
titleClass: 'color0A',
content: 'okay like here are some other items'
},
]
]
},
var NoteBlock = Vue.extend({
props: ['value', 'edit'],
template: '<div>\n <template v-if="edit">\n <textarea rows="1" :class="value.titleClass + \' with-tools blockTitle\'" spellcheck="false" v-autosize v-model="value.title"></textarea>\n <ul class="tools">\n <li v-on:click="remove(value)"><img class="icon" width="24" height="24" src="img/trash-2.svg"></li>\n <li v-on:click="value.titleClass=nextClass(value.titleClass)" :class="value.titleClass">\n <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="icon"><path d="M20.24 12.24a6 6 0 0 0-8.49-8.49L5 10.5V19h8.5z"></path><line x1="16" y1="8" x2="2" y2="22"></line><line x1="17" y1="15" x2="9" y2="15"></line></svg>\n </li>\n </ul>\n </template>\n <textarea v-else rows="1" :class="value.titleClass + \' with-tools blockTitle\'" spellcheck="false" v-autosize v-model="value.title"></textarea>\n <textarea spellcheck="false" v-autosize v-model="value.content"></textarea>\n </div>\n ',
methods: {
add: function (blocks) {
const newBlock = {
title: 'Pancakes?',
nextClass: function nextClass(className) {
var idx = classNames.indexOf(className);
if (idx === -1 || idx === classNames.length - 1) {
return classNames[0];
}
return classNames[idx + 1];
},
remove: function remove() {
this.$emit('remove');
}
}
});
Vue.component('note-block', NoteBlock);
// todo
// load from local storage
// build so start up state that is nice
// make sane defaults
// date
// theme
/* exported app */
var app = new Vue({
el: '#sparkbot',
data: {
edit: false,
content: [[{
data: {
title: 'Daily',
titleClass: 'color08',
content: 'bleh theres thingss'
}
}, {
data: {
title: 'Notes',
titleClass: 'color09',
content: 'okay yea things'
}
}], [{
data: {
title: 'Second Column',
titleClass: 'color0A',
content: 'or just eggs and bacon?'
content: 'okay like here are some other items'
}
}]]
},
created: function init() {
var content = window.localStorage.getItem('sparkbot_content');
if (content) {
this.$set(this.$data, 'content', JSON.decode(content));
}
},
watch: {
content: {
handler: function save() {
window.localStorage.setItem('sparkbox_content', JSON.stringify(this.content));
},
deep: true
}
},
methods: {
add: function add(blocks) {
var newBlock = {
data: {
title: 'Pancakes?',
titleClass: 'color0A',
content: 'or just eggs and bacon?'
}
};
if (!blocks) {
this.content.push([newBlock]);
} else {
blocks.push(newBlock);
}
},
remove: function (block) {
console.log('remove', block);
this.content = this.content.reduce((all, columns) => {
const blocks = columns.filter(b => {
remove: function remove(block) {
this.content = this.content.reduce(function (all, columns) {
var blocks = columns.filter(function (b) {
console.log(b !== block, b.title);
return b !== block;
});
@ -81,13 +101,7 @@ const app = new Vue({
console.log(all);
return all;
}, []);
},
nextClass: function (className) {
const idx = classNames.indexOf(className);
if (idx === -1 || idx === classNames.length - 1) {
return classNames[0];
}
return classNames[idx + 1];
}
}
});
window.app = app;

@ -0,0 +1,16 @@
{
"license": "GPL-3.0",
"scripts": {
"build": "babel ./src -d ./js"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-preset-env": "^1.6.1",
"eslint": "^4.11.0",
"eslint-config-airbnb-base": "^12.1.0",
"eslint-config-prettier": "^2.8.0",
"eslint-plugin-import": "^2.8.0",
"eslint-plugin-prettier": "^2.3.1",
"prettier": "1.8.2"
}
}

@ -0,0 +1,138 @@
/* globals Vue, autosize */
const classNames = [
'color08',
'color09',
'color0A',
'color0B',
'color0C',
'color0D',
'color0E',
'color0F',
];
Vue.directive('autosize', {
inserted: function initAutosize(el) {
autosize(el);
},
});
const NoteBlock = Vue.extend({
props: ['value', 'edit'],
template: `<div>
<template v-if="edit">
<textarea rows="1" :class="value.titleClass + ' with-tools blockTitle'" spellcheck="false" v-autosize v-model="value.title"></textarea>
<ul class="tools">
<li v-on:click="remove(value)"><img class="icon" width="24" height="24" src="img/trash-2.svg"></li>
<li v-on:click="value.titleClass=nextClass(value.titleClass)" :class="value.titleClass">
<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="icon"><path d="M20.24 12.24a6 6 0 0 0-8.49-8.49L5 10.5V19h8.5z"></path><line x1="16" y1="8" x2="2" y2="22"></line><line x1="17" y1="15" x2="9" y2="15"></line></svg>
</li>
</ul>
</template>
<textarea v-else rows="1" :class="value.titleClass + ' with-tools blockTitle'" spellcheck="false" v-autosize v-model="value.title"></textarea>
<textarea spellcheck="false" v-autosize v-model="value.content"></textarea>
</div>
`,
methods: {
nextClass: function nextClass(className) {
const idx = classNames.indexOf(className);
if (idx === -1 || idx === classNames.length - 1) {
return classNames[0];
}
return classNames[idx + 1];
},
remove: function remove() {
this.$emit('remove');
},
},
});
Vue.component('note-block', NoteBlock);
// todo
// load from local storage
// build so start up state that is nice
// make sane defaults
// date
// theme
/* exported app */
const app = new Vue({
el: '#sparkbot',
data: {
edit: false,
content: [
[
{
data: {
title: 'Daily',
titleClass: 'color08',
content: 'bleh theres thingss',
},
},
{
data: {
title: 'Notes',
titleClass: 'color09',
content: 'okay yea things',
},
},
],
[
{
data: {
title: 'Second Column',
titleClass: 'color0A',
content: 'okay like here are some other items',
},
},
],
],
},
created: function init() {
const content = window.localStorage.getItem('sparkbot_content');
if (content) {
this.$set(this.$data, 'content', JSON.decode(content));
}
},
watch: {
content: {
handler: function save() {
window.localStorage.setItem(
'sparkbox_content',
JSON.stringify(this.content)
);
},
deep: true,
},
},
methods: {
add: function add(blocks) {
const newBlock = {
data: {
title: 'Pancakes?',
titleClass: 'color0A',
content: 'or just eggs and bacon?',
},
};
if (!blocks) {
this.content.push([newBlock]);
} else {
blocks.push(newBlock);
}
},
remove: function remove(block) {
this.content = this.content.reduce((all, columns) => {
const blocks = columns.filter(b => {
console.log(b !== block, b.title);
return b !== block;
});
if (blocks.length) {
all.push(blocks);
}
console.log(all);
return all;
}, []);
},
},
});
window.app = app;

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save