add clear all
This commit is contained in:
parent
96854572a0
commit
28d647861a
10 changed files with 253 additions and 33 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -10,6 +10,9 @@
|
|||
/build
|
||||
/functions-build
|
||||
|
||||
# netlify
|
||||
.netlify
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Example of using FaunaDB with [netlify functions](https://www.netlify.com/docs/functions/)
|
||||
|
||||
Try it out on your own account via this link:
|
||||
Deploy this app with one-click via this link:
|
||||
|
||||
<!-- Markdown snippet -->
|
||||
[](https://app.netlify.com/start/deploy?repository=https://github.com/netlify/netlify-faunadb-example)
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
<path id="todo__check" stroke="url(#boxGradient)" d="M10 13l2 2 5-5"></path>
|
||||
<path id="todo__box" stroke="url(#boxGradientGrey)" d="M21 12.7v5c0 1.3-1 2.3-2.3 2.3H8.3C7 20 6 19 6 17.7V7.3C6 6 7 5 8.3 5h10.4C20 5 21 6 21 7.3v5.4"></path>
|
||||
<path id="todo__box__done" stroke="url(#boxGradient)" d="M21 12.7v5c0 1.3-1 2.3-2.3 2.3H8.3C7 20 6 19 6 17.7V7.3C6 6 7 5 8.3 5h10.4C20 5 21 6 21 7.3v5.4"></path>
|
||||
<g id="settings" transform="translate(0,-936.36218)"><path d="m 43.999998,959.36216 -3,10.43754 c -2.71536,0.748 -5.26077,1.8245 -7.65625,3.1875 l -9.5,-5.2813 -8.5,8.5 5.28125,9.5 c -1.36295,2.3955 -2.43943,4.9409 -3.1875,7.6563 l -10.4375,3 0,12 10.4375,3 c 0.74807,2.7154 1.82455,5.2608 3.1875,7.6562 l -5.28125,9.5 8.5,8.5 9.5,-5.2812 c 2.39548,1.3629 4.94089,2.4394 7.65625,3.1875 l 3,10.4375 12,0 3,-10.4375 c 2.71537,-0.7481 5.26077,-1.8246 7.65625,-3.1875 l 9.500004,5.2812 8.5,-8.5 -5.28125,-9.5 c 1.36294,-2.3954 2.43943,-4.9408 3.1875,-7.6562 l 10.4375,-3 0,-12 -10.4375,-3 c -0.74807,-2.7154 -1.82456,-5.2608 -3.1875,-7.6563 l 5.28125,-9.5 -8.5,-8.5 -9.500004,5.2813 c -2.39548,-1.363 -4.94088,-2.4395 -7.65625,-3.1875 l -3,-10.43754 -12,0 z m 6,23.00004 c 11.0457,0 20,8.9543 20,20 0,11.0457 -8.9543,20 -20,20 -11.0457,0 -20,-8.9543 -20,-20 0,-11.0457 8.9543,-20 20,-20 z" stroke="none" visibility="visible" display="inline" overflow="visible"></path></g>
|
||||
</defs>
|
||||
</svg>
|
||||
</body>
|
||||
|
|
|
|||
66
scripts/bootstrap-fauna-database.js
vendored
66
scripts/bootstrap-fauna-database.js
vendored
|
|
@ -1,26 +1,47 @@
|
|||
/* bootstrap database in your FaunaDB account */
|
||||
const readline = require('readline');
|
||||
const faunadb = require('faunadb');
|
||||
const q = faunadb.query;
|
||||
const readline = require('readline')
|
||||
const faunadb = require('faunadb')
|
||||
const chalk = require('chalk')
|
||||
const insideNetlify = insideNetlifyBuildContext()
|
||||
const q = faunadb.query
|
||||
|
||||
ask('Enter your faunaDB server key', function(err, answer) {
|
||||
const key = answer || process.env.FAUNADB_SECRET
|
||||
if (!key) {
|
||||
console.log('Please set supply a faunaDB server key')
|
||||
process.exit()
|
||||
console.log(chalk.cyan('Creating your FaunaDB Database...\n'))
|
||||
|
||||
// 1. Check for required enviroment variables
|
||||
if (!process.env.FAUNADB_SECRET) {
|
||||
console.log(chalk.yellow('Required FAUNADB_SECRET enviroment variable not found.'))
|
||||
if (insideNetlify) {
|
||||
console.log(`Visit https://app.netlify.com/sites/YOUR_SITE_HERE/settings/deploys`)
|
||||
console.log('and set a `FAUNADB_SECRET` value in the "Build environment variables" section')
|
||||
process.exit(1)
|
||||
}
|
||||
// Local machine warning
|
||||
if (!insideNetlify) {
|
||||
console.log()
|
||||
console.log('You can create fauna DB keys here: https://dashboard.fauna.com/db/keys')
|
||||
console.log()
|
||||
ask(chalk.bold('Enter your faunaDB server key'), (err, answer) => {
|
||||
if (!answer) {
|
||||
console.log('Please supply a faunaDB server key')
|
||||
process.exit(1)
|
||||
}
|
||||
createFaunaDB(process.env.FAUNADB_SECRET).then(() => {
|
||||
console.log('Database created')
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const client = new faunadb.Client({
|
||||
secret: answer
|
||||
});
|
||||
|
||||
createFaunaDB(key).then(() => {
|
||||
// Has var. Do the thing
|
||||
if (process.env.FAUNADB_SECRET) {
|
||||
createFaunaDB(process.env.FAUNADB_SECRET).then(() => {
|
||||
console.log('Database created')
|
||||
})
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/* idempotent operation */
|
||||
function createFaunaDB(key) {
|
||||
console.log('Create the database!')
|
||||
const client = new faunadb.Client({
|
||||
secret: key
|
||||
});
|
||||
|
|
@ -33,9 +54,20 @@ function createFaunaDB(key) {
|
|||
name: "all_todos",
|
||||
source: q.Ref("classes/todos")
|
||||
}))
|
||||
}).catch((e) => {
|
||||
// Database already exists
|
||||
if (e.requestResult.statusCode === 400 && e.message === 'instance not unique') {
|
||||
console.log('DB already exists')
|
||||
throw e
|
||||
}
|
||||
})
|
||||
.then(console.log.bind(console))
|
||||
.catch(console.error.bind(console))
|
||||
}
|
||||
|
||||
function insideNetlifyBuildContext() {
|
||||
if (process.env.DEPLOY_PRIME_URL) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Readline util
|
||||
|
|
|
|||
|
|
@ -1,14 +1,33 @@
|
|||
const chalk = require('chalk')
|
||||
if (!process.env.FAUNADB_SECRET) {
|
||||
console.log('Please set supply a faunaDB server key')
|
||||
console.log(`
|
||||
var util = require('util');
|
||||
var exec = require('child_process').exec;
|
||||
|
||||
function clear(){
|
||||
exec('clear', function(error, stdout, stderr){
|
||||
util.puts(stdout);
|
||||
});
|
||||
}
|
||||
function checkForFaunaKey() {
|
||||
if (!process.env.FAUNADB_SECRET) {
|
||||
console.log(chalk.yellow('Required FAUNADB_SECRET enviroment variable not found.'))
|
||||
console.log(`
|
||||
=========================
|
||||
|
||||
In your terminal run the following command
|
||||
|
||||
export FAUNADB_SECRET=abcYourKeyHere
|
||||
export FAUNADB_SECRET=YourFaunaDBKeyHere
|
||||
|
||||
=========================
|
||||
`)
|
||||
process.exit(1)
|
||||
|
||||
process.exit(1)
|
||||
process.stdout.write('\u001b[2J')
|
||||
process.stdout.write('\u001b[1;1H')
|
||||
}
|
||||
}
|
||||
|
||||
process.on('exit', (err) => {
|
||||
console.log('errr')
|
||||
});
|
||||
|
||||
checkForFaunaKey()
|
||||
|
|
|
|||
20
src/App.css
20
src/App.css
|
|
@ -3,9 +3,20 @@
|
|||
padding-top: 10px;
|
||||
width: 600px;
|
||||
}
|
||||
|
||||
.todo-settings-toggle {
|
||||
fill: #b7b9bd;
|
||||
width: 25px;
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.todo-create-wrapper {
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.todo-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.todo-create-input {
|
||||
font-size: 14px;
|
||||
|
|
@ -62,12 +73,17 @@
|
|||
max-width: 80%;
|
||||
margin-left: 40px;
|
||||
}
|
||||
.todo-create-wrapper {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.todo-create-input {
|
||||
appearance: none;
|
||||
margin-bottom: 15px;
|
||||
border: 1px solid rgba(120, 130, 152, 0.25);
|
||||
/* Disable Auto Zoom in Input “Text” tag - Safari on iPhone */
|
||||
font-size: 16px;
|
||||
margin-bottom: 15px;
|
||||
min-width: 85%;
|
||||
}
|
||||
.todo-item button {
|
||||
padding: 4px 12px;
|
||||
|
|
|
|||
37
src/App.js
37
src/App.js
|
|
@ -1,21 +1,22 @@
|
|||
import React, { Component } from 'react'
|
||||
import ContentEditable from './components/ContentEditable'
|
||||
import AppHeader from './components/AppHeader'
|
||||
import SettingsMenu from './components/SettingsMenu'
|
||||
import api from './utils/api'
|
||||
import sortByDate from './utils/sortByDate'
|
||||
import './App.css'
|
||||
|
||||
export default class App extends Component {
|
||||
state = {
|
||||
todos: []
|
||||
todos: [],
|
||||
showMenu: false
|
||||
}
|
||||
componentDidMount() {
|
||||
// Fetch all todos
|
||||
api.readAll().then((response) => {
|
||||
console.log('all todos', response)
|
||||
|
||||
api.readAll().then((todos) => {
|
||||
console.log('all todos', todos)
|
||||
this.setState({
|
||||
todos: response
|
||||
todos: todos
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
@ -156,6 +157,17 @@ export default class App extends Component {
|
|||
})
|
||||
}
|
||||
}
|
||||
closeModal = (e) => {
|
||||
this.setState({
|
||||
showMenu: false
|
||||
})
|
||||
}
|
||||
openModal = () => {
|
||||
console.log('settings')
|
||||
this.setState({
|
||||
showMenu: true
|
||||
})
|
||||
}
|
||||
renderTodos() {
|
||||
const { todos } = this.state
|
||||
|
||||
|
|
@ -228,12 +240,21 @@ export default class App extends Component {
|
|||
autoComplete='off'
|
||||
style={{marginRight: 20}}
|
||||
/>
|
||||
<button className='todo-create-button'>
|
||||
Create todo
|
||||
</button>
|
||||
<div className='todo-actions'>
|
||||
<button className='todo-create-button'>
|
||||
Create todo
|
||||
</button>
|
||||
<span onClick={this.openModal}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 125" className="todo-settings-toggle">
|
||||
<use xlinkHref="#settings" className="settings-gear"></use>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{this.renderTodos()}
|
||||
</div>
|
||||
<SettingsMenu showMenu={this.state.showMenu} handleModalClose={this.closeModal} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
56
src/components/SettingsMenu/SettingsMenu.css
Normal file
56
src/components/SettingsMenu/SettingsMenu.css
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
|
||||
.settings-wrapper {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
background: rgba(95, 95, 95, 0.50);
|
||||
font-size: 13px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.settings-content {
|
||||
margin-top: 3em;
|
||||
margin-bottom: 3em;
|
||||
padding: 1.5em 3em;
|
||||
padding-bottom: 3em;
|
||||
background: #fff;
|
||||
color: rgba(14,30,37,0.54);
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 1px 6px 0 rgba(14,30,37,0.12);
|
||||
position: relative;
|
||||
}
|
||||
.settings-close {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
top: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.settings-content h2 {
|
||||
color: #000;
|
||||
}
|
||||
.settings-section {
|
||||
margin-top: 20px;
|
||||
}
|
||||
.settings-header {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.settings-options-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.settings-option {
|
||||
padding: 3px 8px;
|
||||
margin: 5px;
|
||||
border: 1px solid;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
&:hover, &.activeClass {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
59
src/components/SettingsMenu/index.js
Normal file
59
src/components/SettingsMenu/index.js
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
import React, { Component } from 'react'
|
||||
import styles from './SettingsMenu.css' // eslint-disable-line
|
||||
|
||||
export default class Menu extends Component {
|
||||
componentDidMount() {
|
||||
// attach event listeners
|
||||
document.body.addEventListener('keydown', this.handleEscKey)
|
||||
}
|
||||
componentWillUnmount() {
|
||||
// remove event listeners
|
||||
document.body.removeEventListener('keydown', this.handleEscKey)
|
||||
}
|
||||
handleEscKey = (e) => {
|
||||
if (this.props.showMenu && e.which === 27) {
|
||||
this.props.handleModalClose()
|
||||
}
|
||||
}
|
||||
handleDelete = (e) => {
|
||||
e.preventDefault()
|
||||
const deleteConfirm = window.confirm("Are you sure you want to clear all completed todos?");
|
||||
if (deleteConfirm) {
|
||||
console.log('delete')
|
||||
}
|
||||
}
|
||||
render() {
|
||||
const { showMenu } = this.props
|
||||
const showOrHide = (showMenu) ? 'flex' : 'none'
|
||||
return (
|
||||
<div className='settings-wrapper' style={{display: showOrHide}}>
|
||||
<div className='settings-content'>
|
||||
<span className='settings-close' onClick={this.props.handleModalClose}>❌</span>
|
||||
<h2>Settings</h2>
|
||||
<div className='settings-section' onClick={this.handleDelete}>
|
||||
<button className='btn-danger'>
|
||||
Clear All Completed Todos
|
||||
</button>
|
||||
</div>
|
||||
<div className='settings-section' style={{display: 'none'}}>
|
||||
<div className='settings-header'>Sort Todos:</div>
|
||||
<div className='settings-options-wrapper' data-setting='sortOrder'>
|
||||
<div
|
||||
className='settings-option'
|
||||
onClick={this.changeSetting}
|
||||
data-value='desc'>
|
||||
Oldest First ▼
|
||||
</div>
|
||||
<div
|
||||
className='settings-option'
|
||||
onClick={this.changeSetting}
|
||||
data-value='asc'>
|
||||
Most Recent First ▲
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -32,3 +32,16 @@ button:focus, button:hover {
|
|||
box-shadow: 0 8px 12px 0 rgba(233,235,235,.16), 0 2px 8px 0 rgba(0,0,0,.08);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
||||
.btn-danger {
|
||||
background-color: #fb6d77;
|
||||
border-color: #fb6d77;
|
||||
border-bottom-color: #e6636b;
|
||||
color: #fff;
|
||||
}
|
||||
.btn-danger:focus, .btn-danger:hover {
|
||||
background-color: #fa3b49;
|
||||
border-color: #fa3b49;
|
||||
color: #fff;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue