Browse Source

adding

master
Björn 3 years ago
parent
commit
dcfb2e673a
23 changed files with 7263 additions and 114 deletions
  1. +1
    -0
      mix-manifest.json
  2. +31
    -0
      public/css/index.css
  3. +6751
    -0
      public/js/bucket-single.js
  4. +6
    -6
      public/js/create-bucket.js
  5. +19
    -14
      public/js/dashboard.js
  6. +124
    -0
      resources/js/FormValidator.js
  7. +6
    -0
      resources/js/bucket-single.js
  8. +123
    -0
      resources/js/components/note-form.riot
  9. +49
    -0
      resources/js/components/note.riot
  10. +36
    -0
      resources/scss/components/_note-form.scss
  11. +1
    -0
      resources/scss/index.scss
  12. +9
    -1
      resources/views/bucket/single.html
  13. +1
    -1
      resources/views/layout.html
  14. +11
    -0
      resources/views/settings.html
  15. +5
    -0
      server.ts
  16. +69
    -5
      src/http/api/note.ts
  17. +17
    -0
      src/http/settings.ts
  18. +0
    -0
      src/resources/auth.ts
  19. +0
    -43
      src/resources/bucket.ts
  20. +0
    -24
      src/resources/bucketIndex.ts
  21. +0
    -18
      src/resources/index.ts
  22. +3
    -2
      src/stores/note.ts
  23. +1
    -0
      webpack.mix.js

+ 1
- 0
mix-manifest.json View File

@ -1,6 +1,7 @@
{ {
"/public/js/spritemap.js": "/public/js/spritemap.js", "/public/js/spritemap.js": "/public/js/spritemap.js",
"/public/js/critical.js": "/public/js/critical.js", "/public/js/critical.js": "/public/js/critical.js",
"/public/js/bucket-single.js": "/public/js/bucket-single.js",
"/public/js/create-bucket.js": "/public/js/create-bucket.js", "/public/js/create-bucket.js": "/public/js/create-bucket.js",
"/public/js/dashboard.js": "/public/js/dashboard.js", "/public/js/dashboard.js": "/public/js/dashboard.js",
"/public/css/index.css": "/public/css/index.css", "/public/css/index.css": "/public/css/index.css",


+ 31
- 0
public/css/index.css View File

@ -14919,6 +14919,37 @@ input[type=checkbox].field-choice:checked ~ .field-switch:after {
color: var(--text); color: var(--text);
} }
.note-form {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.note-form .panel {
position: relative;
z-index: 20;
max-width: 33%;
width: 100%;
height: 100%;
border-left: 0;
border-top: 0;
border-bottom: 0;
}
.note-form:before {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: transparent;
transition: background-color 0.5s;
z-index: 19;
content: "";
background: rgba(0, 0, 0, 0.87);
z-index: 0;
}
.field-error ul { .field-error ul {
list-style: none; list-style: none;
padding: 0; padding: 0;


+ 6751
- 0
public/js/bucket-single.js
File diff suppressed because it is too large
View File


+ 6
- 6
public/js/create-bucket.js View File

@ -107,7 +107,7 @@ __webpack_require__.r(__webpack_exports__);
getComponent getComponent
) { ) {
return template( return template(
'<div expr6="expr6" class="field-error"></div>',
'<div expr0="expr0" class="field-error"></div>',
[ [
{ {
'type': bindingTypes.IF, 'type': bindingTypes.IF,
@ -118,11 +118,11 @@ __webpack_require__.r(__webpack_exports__);
return _scope.state.errors.length > 0; return _scope.state.errors.length > 0;
}, },
'redundantAttribute': 'expr6',
'selector': '[expr6]',
'redundantAttribute': 'expr0',
'selector': '[expr0]',
'template': template( 'template': template(
'<ul><li expr7="expr7"></li></ul>',
'<ul><li expr1="expr1"></li></ul>',
[ [
{ {
'type': bindingTypes.EACH, 'type': bindingTypes.EACH,
@ -153,8 +153,8 @@ __webpack_require__.r(__webpack_exports__);
] ]
), ),
'redundantAttribute': 'expr7',
'selector': '[expr7]',
'redundantAttribute': 'expr1',
'selector': '[expr1]',
'itemName': 'error', 'itemName': 'error',
'indexName': null, 'indexName': null,


+ 19
- 14
public/js/dashboard.js View File

@ -50,6 +50,11 @@ __webpack_require__.r(__webpack_exports__);
}) })
}, },
/**
* getting all buckets
*
*
*/
fetch() { fetch() {
axios__WEBPACK_IMPORTED_MODULE_0___default().get('/api/bucket/', { axios__WEBPACK_IMPORTED_MODULE_0___default().get('/api/bucket/', {
params: { params: {
@ -69,7 +74,7 @@ __webpack_require__.r(__webpack_exports__);
getComponent getComponent
) { ) {
return template( return template(
'<div class="buckets"><div class="grid"><div expr0="expr0" class="col-12 col-md-4 col-xlg-3"></div></div><div class="grid"><div class="col-12"><div class="buckets__more"><button expr5="expr5" type="button" class="button">\n More\n <svg class="icon" aria-hidden="true"><use xlink:href="/symbol-defs.svg#icon-arrow-down"/></svg></button></div></div></div></div>',
'<div class="buckets"><div class="grid"><div expr2="expr2" class="col-12 col-md-4 col-xlg-3"></div></div><div class="grid"><div class="col-12"><div class="buckets__more"><button expr7="expr7" type="button" class="button">\n More\n <svg class="icon" aria-hidden="true"><use xlink:href="/symbol-defs.svg#icon-arrow-down"/></svg></button></div></div></div></div>',
[ [
{ {
'type': bindingTypes.EACH, 'type': bindingTypes.EACH,
@ -77,11 +82,11 @@ __webpack_require__.r(__webpack_exports__);
'condition': null, 'condition': null,
'template': template( 'template': template(
'<article class="panel buckets__item"><div class="bar"><div class="bar__end w-100"><button expr1="expr1" class="button button--transparent"><svg class="icon fill-text-contrast" aria-hidden="true"><use xlink:href="/symbol-defs.svg#icon-delete"/></svg></button></div></div><div class="panel__body"><a expr2="expr2"><h3 expr3="expr3" class="buckets__title"> </h3><div class="content"><p expr4="expr4"> </p></div></a></div></article>',
'<article class="panel buckets__item"><div class="bar"><div class="bar__end w-100"><button expr3="expr3" class="button button--transparent"><svg class="icon fill-text-contrast" aria-hidden="true"><use xlink:href="/symbol-defs.svg#icon-delete"/></svg></button></div></div><div class="panel__body"><a expr4="expr4"><h3 expr5="expr5" class="buckets__title"> </h3><div class="content"><p expr6="expr6"> </p></div></a></div></article>',
[ [
{ {
'redundantAttribute': 'expr1',
'selector': '[expr1]',
'redundantAttribute': 'expr3',
'selector': '[expr3]',
'expressions': [ 'expressions': [
{ {
@ -97,8 +102,8 @@ __webpack_require__.r(__webpack_exports__);
] ]
}, },
{ {
'redundantAttribute': 'expr2',
'selector': '[expr2]',
'redundantAttribute': 'expr4',
'selector': '[expr4]',
'expressions': [ 'expressions': [
{ {
@ -119,8 +124,8 @@ __webpack_require__.r(__webpack_exports__);
] ]
}, },
{ {
'redundantAttribute': 'expr3',
'selector': '[expr3]',
'redundantAttribute': 'expr5',
'selector': '[expr5]',
'expressions': [ 'expressions': [
{ {
@ -140,8 +145,8 @@ __webpack_require__.r(__webpack_exports__);
] ]
}, },
{ {
'redundantAttribute': 'expr4',
'selector': '[expr4]',
'redundantAttribute': 'expr6',
'selector': '[expr6]',
'expressions': [ 'expressions': [
{ {
@ -163,8 +168,8 @@ __webpack_require__.r(__webpack_exports__);
] ]
), ),
'redundantAttribute': 'expr0',
'selector': '[expr0]',
'redundantAttribute': 'expr2',
'selector': '[expr2]',
'itemName': 'bucket', 'itemName': 'bucket',
'indexName': null, 'indexName': null,
@ -175,8 +180,8 @@ __webpack_require__.r(__webpack_exports__);
} }
}, },
{ {
'redundantAttribute': 'expr5',
'selector': '[expr5]',
'redundantAttribute': 'expr7',
'selector': '[expr7]',
'expressions': [ 'expressions': [
{ {


+ 124
- 0
resources/js/FormValidator.js View File

@ -0,0 +1,124 @@
import validate from 'validate.js'
import serialize from 'form-serialize'
/**
* Form Validator with RiotJS Components
*
*
*
*
*/
class FormValidator
{
/**
*
* @param {[type]} formSelector [description]
* @param {[type]} constraits [description]
*/
constructor(formSelector, constraits, onSuccess)
{
// getting selector to find form-element
this.formSelector = formSelector
// constraits for validate.js
this.constraits = constraits
// get form and elements
this.form = document.querySelector(this.formSelector)
this.elements = this.form.querySelectorAll('field-error')
// adding submit event
this.form.addEventListener('submit', (event) => {
this.onSubmit(event)
})
// adding event if a element is updated
this.form.addEventListener('field-update', (event) => {
this.onFieldUpdate(event)
})
this.onSuccess = onSuccess
}
/**
*
* @param {[type]} event [description]
* @return {[type]} [description]
*/
onSubmit(event)
{
event.preventDefault()
let errors = validate(serialize(event.target, {
hash: true
}), this.constraits, {
fullMessages: false
})
if (errors) {
// send each element a event
this.elements.forEach((element) => {
let elementErrors = false
// check for errors by name
if (errors[element.attributes.name.nodeValue]) {
elementErrors = errors[element.attributes.name.nodeValue]
}
this.dispatchCustomEvent(elementErrors, element)
})
} else {
this.onSuccess(event, serialize(event.target, {
hash: true
}))
}
}
/**
*
*
* @param {Event} event
*
*/
onFieldUpdate(event)
{
// workaround, make sure that value for single is undefined if it is empty
if (event.detail.value == '') {
event.detail.value = undefined
}
let errors = validate.single(event.detail.value, this.constraits[event.detail.name])
// search for element by name and dispatch event
this.elements.forEach((element) => {
if (element.attributes.name.nodeValue == event.detail.name) {
this.dispatchCustomEvent(errors, element)
}
})
}
/**
* dispatch event to single element
*
* @param {Array} errors
* @param {Element} element
*
*/
dispatchCustomEvent(errors, element)
{
let detail = false
if (errors) {
detail = errors
}
const formValidationEvent = new CustomEvent('form-validation', {
'detail': detail
})
element.dispatchEvent(formValidationEvent)
}
}
export default FormValidator

+ 6
- 0
resources/js/bucket-single.js View File

@ -0,0 +1,6 @@
import * as riot from 'riot'
import NoteForm from './components/note-form.riot'
riot.register('note-form', NoteForm)
riot.mount('note-form')

+ 123
- 0
resources/js/components/note-form.riot View File

@ -0,0 +1,123 @@
<app-note-form>
<div class="note-form">
<div class="panel">
<div class="panel__body">
<form id="form" novalidate>
<input type="hidden" if={ state.note && state.note._id } name="_id" value="{ state.note._id }" />
<div class="field-group">
<label class="field-label">
title
<input type="text" class="field-text" name="title" />
</label>
</div>
<div class="field-group">
<label class="field-label">
content
<textarea name="content" class="field-text"></textarea>
</label>
</div>
<div class="">
<div class="tabs">
</div>
</div>
<div>
<button class="button" if={ !state.note || (state.note && !state.note._id) }>
Create
</button>
<button class="button" type="submit" if={ state.note && state.note._id }>
Save
</button>
</div>
</form>
</div>
</div>
</div>
<script>
import axios from 'axios'
import * as riot from 'riot'
import FormValidator from './../FormValidator'
import FieldError from './field-error.riot'
riot.register('field-error', FieldError)
riot.mount('field-error')
/**
*
*
*
* @author Björn Hase
*
*/
export default {
state: {
note: undefined
},
onBeforeMount() {
// show error if props is missing
if (!this.props.bucketId) {
console.error('ID of Bucket is Missing!')
}
},
/**
*
*
*/
onMounted(props, state) {
// create form validation
const formValidation = new FormValidator('form', {
'title': {
'length': {
'maximum': 255
}
},
'content': {
'length': {
'maximum': 10922
}
}
}, (event, data) => {
this.handleSubmit(event, data)
})
},
/**
*
*
*/
handleSubmit(event, data) {
let method = 'post'
if (this.state.note && this.state.note._id) {
method = 'put'
}
axios({
method: method,
url: '/api/note/' + this.props.bucketId,
data: data
}).then((response) => {
this.state.note = response.data.data
this.update()
})
}
}
</script>
</app-note-form>

+ 49
- 0
resources/js/components/note.riot View File

@ -0,0 +1,49 @@
<app-note>
<div class="note">
<div class="panel">
<div class="bar">
<div class="bar__end w-100">
<button class="button button--transparent" onclick={ (event) => { handleEdit(event, note) } }>
<svg class="icon fill-text-contrast" aria-hidden="true">
<use xlink:href="/symbol-defs.svg#icon-edit"></use>
</svg>
</button>
<button class="button button--transparent" onclick={ (event) => { handleDelete(event, note) } }>
<svg class="icon fill-text-contrast" aria-hidden="true">
<use xlink:href="/symbol-defs.svg#icon-delete"></use>
</svg>
</button>
</div>
</div>
<div class="note__title">
<h3>
{ state.note.title }
</h3>
</div>
<div class="panel__body">
{ state.note.content }
</div>
</div>
</div>
<script>
import axios from 'axios'
import remove from 'lodash.remove'
/**
*
*
*
* @author Björn Hase
*
*/
export default {
state: {
note: undefined
}
}
</script>
</app-note>

+ 36
- 0
resources/scss/components/_note-form.scss View File

@ -0,0 +1,36 @@
.note-form {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
.panel {
position: relative;
z-index: 20;
max-width: 33%;
width: 100%;
height: 100%;
border-left: 0;
border-top: 0;
border-bottom: 0;
}
&:before {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: transparent;
transition: background-color .5s;
z-index: 19;
content: "";
background: rgba(0,0,0,.87);
z-index: 0;
}
}

+ 1
- 0
resources/scss/index.scss View File

@ -2,6 +2,7 @@
'../../node_modules/@tentakelfabrik/plain-ui/src/scss/plain-ui', '../../node_modules/@tentakelfabrik/plain-ui/src/scss/plain-ui',
'components/buckets', 'components/buckets',
'components/note-form',
'components/field', 'components/field',
'container'; 'container';


+ 9
- 1
resources/views/bucket/single.html View File

@ -7,6 +7,14 @@
<span> <span>
<%= it.bucket.description %> <%= it.bucket.description %>
</span> </span>
<button id="note-form-toggle" class="button absolute">
<svg class="icon p-left-3 size-large" aria-hidden="true">
<use xlink:href="/symbol-defs.svg#icon-circle-add"></use>
</svg>
</button>
<note-form bucket-id="<%= it.bucket._id %>"></note-form>
</div> </div>
</div> </div>
</div>
</div>
<script type="text/javascript" src="/js/bucket-single.js" defer></script>

+ 1
- 1
resources/views/layout.html View File

@ -23,7 +23,7 @@
<a href="/" data-turbolinks="false" class="tabs__item tabs__item--selected"> <a href="/" data-turbolinks="false" class="tabs__item tabs__item--selected">
Dashboard Dashboard
</a> </a>
<a href="/" class="tabs__item">
<a href="/settings" class="tabs__item">
Settings Settings
</a> </a>
</div> </div>


+ 11
- 0
resources/views/settings.html View File

@ -0,0 +1,11 @@
<% layout('./layout.html') %>
<div class="container container--app">
<div class="grid">
<div class="col-12">
<h1 class="highlight">
Settings
</h1>
</div>
</div>
</div>

+ 5
- 0
server.ts View File

@ -11,7 +11,10 @@ import { renderFile } from 'https://deno.land/x/eta@v1.12.2/mod.ts'
// getting routes // getting routes
import index from './src/http/index.ts' import index from './src/http/index.ts'
import bucket from './src/http/bucket.ts' import bucket from './src/http/bucket.ts'
import settings from './src/http/settings.ts'
import bucketApi from './src/http/api/bucket.ts' import bucketApi from './src/http/api/bucket.ts'
import noteApi from './src/http/api/note.ts'
const app = opine() const app = opine()
const __dirname = dirname(import.meta.url) const __dirname = dirname(import.meta.url)
@ -33,7 +36,9 @@ app.set('view engine', 'html')
// adding http classes for routes // adding http classes for routes
app.use('/', index) app.use('/', index)
app.use('/bucket', bucket) app.use('/bucket', bucket)
app.use('/settings', settings)
app.use('/api/bucket', bucketApi) app.use('/api/bucket', bucketApi)
app.use('/api/note', noteApi)
app.use((request, response, next) => { app.use((request, response, next) => {
response.setStatus(404) response.setStatus(404)
response.render('errors/404') response.render('errors/404')


+ 69
- 5
src/http/api/note.ts View File

@ -1,3 +1,10 @@
import { v4 } from "https://deno.land/std@0.99.0/uuid/mod.ts";
import { validate, required, isIn, maxLength } from 'https://deno.land/x/validasaur@v0.15.0/mod.ts'
import { Database } from 'https://deno.land/x/aloedb@0.9.0/mod.ts'
import { BucketSchema } from './../../stores/bucket.ts'
import { NoteSchema } from './../../stores/note.ts'
import { Router } from 'https://deno.land/x/opine@1.5.3/mod.ts' import { Router } from 'https://deno.land/x/opine@1.5.3/mod.ts'
const router = Router() const router = Router()
@ -9,13 +16,39 @@ const router = Router()
* @param response * @param response
* @return * @return
*/ */
router.post('/:bucket_id', function(request, response)
router.post('/:bucket_id', async function(request, response)
{ {
const body = request.body
let note
// check if uuid is valid
if (!v4.validate(request.params.bucket_id)) {
response.setStatus(404)
}
// check if bucket exists
const db = new Database<BucketSchema>('./storage/database/buckets.json')
const bucket = await db.findOne({ _id: request.params.bucket_id })
if (!bucket) {
response.setStatus(404)
}
const [ valid, errors ] = await validate(body, { const [ valid, errors ] = await validate(body, {
title: [ maxLength(255) ], title: [ maxLength(255) ],
content: [ maxLength(10922) ],
tags: [ ],
url: isUrl
content: [ maxLength(10922) ]
})
if (valid && bucket) {
body._id = v4.generate()
// getting database and search by uuid
const db = new Database<NoteSchema>('./storage/database/' + bucket._id + '.json')
note = await db.insertOne(body)
}
response.json({
data: note
}) })
}) })
@ -26,9 +59,40 @@ router.post('/:bucket_id', function(request, response)
* @param response * @param response
* @return * @return
*/ */
router.put('/:bucket_id/:id', function(request, response, next)
router.put('/:bucket_id', async function(request, response, next)
{ {
const body = request.body
let note
// check if uuid is valid
if (!v4.validate(request.params.bucket_id)) {
response.setStatus(404)
}
// check if bucket exists
const bucketDb = new Database<BucketSchema>('./storage/database/buckets.json')
const bucket = await bucketDb.findOne({ _id: request.params.bucket_id })
if (!bucket) {
response.setStatus(404)
}
const [ valid, errors ] = await validate(body, {
title: [ maxLength(255) ],
content: [ maxLength(10922) ]
})
if (valid && bucket) {
// getting database and search by uuid
const db = new Database<NoteSchema>('./storage/database/' + bucket._id + '.json')
note = await db.updateOne({ _id: body._id }, body)
}
response.json({
data: note
})
}) })
/** /**


+ 17
- 0
src/http/settings.ts View File

@ -0,0 +1,17 @@
import { Router } from 'https://deno.land/x/opine@1.5.3/mod.ts'
const router = Router()
/**
* render template for settings
*
* @param request
* @param response
* @return
*/
router.get('/', function(request, response, next)
{
response.render('settings')
})
export default router

+ 0
- 0
src/resources/auth.ts View File


+ 0
- 43
src/resources/bucket.ts View File

@ -1,43 +0,0 @@
import { Drash } from 'https://deno.land/x/drash@v1.4.4/mod.ts'
import { v4 } from 'https://deno.land/std@0.99.0/uuid/mod.ts'
import { Bucket as BucketSchema } from './src/schemas/bucket.ts'
import Schema, { Type, string, number, array } from 'https://denoporter.sirjosh.workers.dev/v1/deno.land/x/computed_types/src/index.ts'
/**
*
*
*/
export class BucketResource extends Drash.Http.Resource
{
// route
static paths = ['/bucket/[:id?]']
/**
* [GET description]
* @param id [description]
* @return [description]
*/
public GET(id)
{
const db = new Database<BucketSchema>()
const buckets = await db.findOne({
'_id': id
})
this.response.body = bucket
return this.response
}
/**
*
*
*/
public POST()
{
const db = new Database<BucketSchema>()
this.response.body = bucket
return this.response
}
}

+ 0
- 24
src/resources/bucketIndex.ts View File

@ -1,24 +0,0 @@
import { Drash } from 'https://deno.land/x/drash@v1.4.4/mod.ts'
import { v4 } from 'https://deno.land/std@0.99.0/uuid/mod.ts'
import { Bucket as BucketSchema } from './src/schemas/bucket.ts'
/**
*
*
*/
export class BucketResource extends Drash.Http.Resource
{
// route
static paths = ['/buckets']
//
public GET()
{
const db = new Database<BucketSchema>()
const buckets = await db.findMany()
this.response.body = buckets
return this.response
}
}

+ 0
- 18
src/resources/index.ts View File

@ -1,18 +0,0 @@
import { Drash } from 'https://deno.land/x/drash@v1.4.4/mod.ts'
/**
*
*
*/
export class IndexResource extends Drash.Http.Resource
{
// route
static paths = ['/']
//
public GET()
{
this.response.body = 'Hallo'
return this.response
}
}

+ 3
- 2
src/stores/note.ts View File

@ -1,8 +1,9 @@
export interface Note {
export interface NoteSchema {
_id: string; _id: string;
title: string; title: string;
type: string; type: string;
content: string; content: string;
attachment: array;
attachment: any[];
authors: string[];
tags: string[]; tags: string[];
} }

+ 1
- 0
webpack.mix.js View File

@ -59,6 +59,7 @@ mix.options({
mix mix
.js('resources/js/critical.js', 'public/js') .js('resources/js/critical.js', 'public/js')
.js('resources/js/bucket-single.js', 'public/js')
.js('resources/js/create-bucket.js', 'public/js') .js('resources/js/create-bucket.js', 'public/js')
.js('resources/js/dashboard.js', 'public/js') .js('resources/js/dashboard.js', 'public/js')
.sass('resources/scss/index.scss', 'public/css') .sass('resources/scss/index.scss', 'public/css')


Loading…
Cancel
Save