release/0.1.0
HerrHase 3 years ago
parent dbf67b3e27
commit f3cc6f3e90

@ -1,16 +1,5 @@
{ {
"/public/js/spritemap.js": "/public/js/spritemap.js?id=2dda73ecee3bb668b395026efda6524c", "/public/js/spritemap.js": "/public/js/spritemap.js?id=2dda73ecee3bb668b395026efda6524c",
"/public/js/app.js": "/public/js/app.js?id=3af721e60a47e6147d71c98308c2b6e1", "/public/js/app.js": "/public/js/app.js?id=1c9307a192e1817119e543e388f2a43b",
"/public/css/styles.css": "/public/css/styles.css?id=d8096bd2ff84ae29cb0ecf810064b218", "/public/css/styles.css": "/public/css/styles.css?id=72a43d98017bdbcb83928c41f6289210"
"/public/css/demo.html": "/public/css/demo.html?id=a54a5d205e3152fb64b33dda63ffa555",
"/public/css/IBMPlexMono-Bold.eot": "/public/css/IBMPlexMono-Bold.eot?id=ef1fadf711db80a00542b202ab14f7ee",
"/public/css/IBMPlexMono-Bold.ttf": "/public/css/IBMPlexMono-Bold.ttf?id=e46cace25a93f48a2ec32800717827cb",
"/public/css/IBMPlexMono-Bold.woff": "/public/css/IBMPlexMono-Bold.woff?id=8864bd7cb954c4646045e3fc0bdec90c",
"/public/css/IBMPlexMono-Bold.woff2": "/public/css/IBMPlexMono-Bold.woff2?id=c6d3f08fe7a9fecab40d748b98c87cc5",
"/public/css/IBMPlexMono.eot": "/public/css/IBMPlexMono.eot?id=d68f064d6b86ff47b38ad486a3362d82",
"/public/css/IBMPlexMono.ttf": "/public/css/IBMPlexMono.ttf?id=60d8ae961dba3289c1d2d54e0b85c9b7",
"/public/css/IBMPlexMono.woff": "/public/css/IBMPlexMono.woff?id=18a7a5a76b4176759e2e1b3e674a7f82",
"/public/css/IBMPlexMono.woff2": "/public/css/IBMPlexMono.woff2?id=428bd06c5eb0362494016994c26188b4",
"/public/css/OFL.txt": "/public/css/OFL.txt?id=5c7bb1d9d37e52d30b53224261c955b2",
"/public/css/stylesheet.css": "/public/css/stylesheet.css?id=a3e561da46246c3c582cddec544ad25f"
} }

13
package-lock.json generated

@ -2054,7 +2054,8 @@
"@tiny-components/plain-ui": "^0.5.0", "@tiny-components/plain-ui": "^0.5.0",
"@tiny-components/validator": "^0.1.0", "@tiny-components/validator": "^0.1.0",
"got": "^12.0.1", "got": "^12.0.1",
"riot": "^6.1.2" "riot": "^6.1.2",
"uuid": "^8.3.2"
}, },
"devDependencies": { "devDependencies": {
"@riotjs/webpack-loader": "^6.0.0", "@riotjs/webpack-loader": "^6.0.0",
@ -12125,8 +12126,6 @@
"version": "8.3.2", "version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"dev": true,
"license": "MIT",
"bin": { "bin": {
"uuid": "dist/bin/uuid" "uuid": "dist/bin/uuid"
} }
@ -14423,7 +14422,7 @@
"frontend": { "frontend": {
"version": "file:packages/frontend", "version": "file:packages/frontend",
"requires": { "requires": {
"@riotjs/observable": "*", "@riotjs/observable": "^4.1.1",
"@riotjs/webpack-loader": "^6.0.0", "@riotjs/webpack-loader": "^6.0.0",
"@tiny-components/plain-ui": "^0.5.0", "@tiny-components/plain-ui": "^0.5.0",
"@tiny-components/validator": "^0.1.0", "@tiny-components/validator": "^0.1.0",
@ -14433,7 +14432,8 @@
"riot": "^6.1.2", "riot": "^6.1.2",
"sass": "^1.49.9", "sass": "^1.49.9",
"sass-loader": "^12.6.0", "sass-loader": "^12.6.0",
"svg-spritemap-webpack-plugin": "^4.4.0" "svg-spritemap-webpack-plugin": "^4.4.0",
"uuid": "^8.3.2"
}, },
"dependencies": { "dependencies": {
"@ampproject/remapping": { "@ampproject/remapping": {
@ -21489,8 +21489,7 @@
"uuid": { "uuid": {
"version": "8.3.2", "version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
"dev": true
}, },
"vary": { "vary": {
"version": "1.1.2", "version": "1.1.2",

@ -5,6 +5,7 @@
"packages/*" "packages/*"
], ],
"scripts": { "scripts": {
"start": "yarn workspace runner run start" "start": "yarn workspace server start",
"build": "yarn workspace frontend build"
} }
} }

@ -6,14 +6,20 @@ import AppTasks from './components/tasks.riot'
import AppTaskButton from './components/task-new.riot' import AppTaskButton from './components/task-new.riot'
import AppTaskForm from './components/task-form.riot' import AppTaskForm from './components/task-form.riot'
import AppNotification from './components/notification.riot'
// register components // register components
riot.register('app-sidebar', AppSidebar) riot.register('app-sidebar', AppSidebar)
riot.register('app-tasks', AppTasks) riot.register('app-tasks', AppTasks)
riot.register('app-task-button', AppTaskButton) riot.register('app-task-button', AppTaskButton)
riot.register('app-task-form', AppTaskForm) riot.register('app-task-form', AppTaskForm)
riot.register('app-notification', AppNotification)
// mount components // mount components
riot.mount('app-sidebar') riot.mount('app-sidebar')
riot.mount('app-tasks') riot.mount('app-tasks')
riot.mount('app-task-button') riot.mount('app-task-button')
riot.mount('app-task-form') riot.mount('app-task-form')
riot.mount('app-notification')

@ -0,0 +1,15 @@
<app-loading>
<div class="loading-wrapper" if={ props.loading }>
<div class="loading">
<span></span>
<span></span>
<span></span>
</div>
</div>
<script>
export default {
}
</script>
</app-loading>

@ -0,0 +1,115 @@
<app-notification>
<div class="toast-wrapper toast-wrapper--right" if={ state.items.length > 0 }>
<div
id={ item.id } class={ item.classes.join(' ') }
each={ item in state.items }
onclick={ (event) => { this.handleClick(event, item) } }>
<div class="toast__body">
{ item.message }
</div>
</div>
</div>
<script>
import { v4 as uuidv4 } from 'uuid'
import notificationStore from './../stores/notification'
/**
* notification
*
*
* @author Björn Hase
* @license http://opensource.org/licenses/MIT The MIT License
* @link https://gitea.tentakelfabrik.de/herrhase/shiny-dashboard
*
*/
export default {
state: {
items: [],
timeout: 2500
},
/**
* on mounted
*
* @param {object} props
* @param {object} state
*
*/
onMounted(props, state)
{
// adding service for notifications and listen to "update"
notificationStore.on('update', (item) => {
// adding attributes
item.id = 'toast-' + uuidv4()
item.classes = [
'toast',
'toast--' + item.type
]
// create timeout to remove notification
item.timeout = setTimeout(() => {
this.removeItem(item)
}, this.state.timeout)
this.state.items.push(item)
this.update()
// add animation
requestAnimationFrame(() => {
this.$('#' + item.id).classList.add('toast--animation')
})
})
},
/**
* remove single item
*
*
* @param {object} item
*
*/
removeItem(item)
{
// adding event if animationend remove html element
this.$('#' + item.id).addEventListener('transitionend', () => {
// find item in state and remove it
for (let i = 0; i < this.state.items.length; i++) {
if (this.state.items[i].id === item.id) {
clearTimeout(this.state.items[i].timeout)
this.state.items.splice(i, 1)
break;
}
}
this.update()
})
// add animation
requestAnimationFrame(() => {
this.$('#' + item.id).classList.remove('toast--animation')
})
},
/**
* remove item by clicked on it
*
* @param {[type]} event
* @param {[type]} item
*
*/
handleClick(event, item)
{
this.removeItem(item)
}
}
</script>
</app-notification>

@ -9,7 +9,7 @@
</div> </div>
<div class="bar__end"> <div class="bar__end">
<button class="button button--transparent" type="button" onclick={ (event) => { handleClose(event) } }> <button class="button button--transparent" type="button" onclick={ (event) => { handleClose(event) } }>
<svg class="icon fill-text-contrast" aria-hidden="true"> <svg class="icon fill-danger fill-text-hover" aria-hidden="true">
<use xlink:href="/symbol-defs.svg#icon-close"></use> <use xlink:href="/symbol-defs.svg#icon-close"></use>
</svg> </svg>
</button> </button>
@ -19,17 +19,18 @@
<!-- body --> <!-- body -->
<div class="sidebar__body"> <div class="sidebar__body">
<slot name="form" /> <slot name="form" />
<app-loading loading={ props.loading }></app-loading>
</div> </div>
<!-- footer --> <!-- footer -->
<div class="sidebar__footer"> <div class="sidebar__footer">
<button class="button m-bottom-0" type="submit" form="{ props.formId }"> <button class="button m-bottom-0" type="submit" form="{ props.formId }" disabled={ props.loading }>
Save Save
<svg class="icon fill-success p-left-3" aria-hidden="true"> <svg class="icon fill-success p-left-3" aria-hidden="true">
<use xlink:href="/symbol-defs.svg#icon-check"></use> <use xlink:href="/symbol-defs.svg#icon-check"></use>
</svg> </svg>
</button> </button>
<button class="button m-bottom-0" type="submit" form="{ props.formId }" close> <button class="button m-bottom-0" type="submit" form="{ props.formId }" disabled={ props.loading } close>
Save and Close Save and Close
<svg class="icon fill-success p-left-3" aria-hidden="true"> <svg class="icon fill-success p-left-3" aria-hidden="true">
<use xlink:href="/symbol-defs.svg#icon-arrow-right"></use> <use xlink:href="/symbol-defs.svg#icon-arrow-right"></use>
@ -42,6 +43,11 @@
<script> <script>
import * as riot from 'riot'
import AppLoading from './loading.riot'
riot.register('app-loading', AppLoading)
/** /**
* *
* *

@ -1,6 +1,6 @@
<app-task-form> <app-task-form>
<app-sidebar form-id="app-task-form" open={ state.isOpen } close={ () => { handleClose() } }> <app-sidebar form-id="app-task-form" open={ state.isOpen } close={ () => { handleClose() } } loading={ state.isLoading }>
<!-- slot:title --> <!-- slot:title -->
<span slot="title"> <span slot="title">
@ -13,18 +13,18 @@
</span> </span>
<!-- slot:header --> <!-- slot:header -->
<form id="app-task-form" class="form" slot="form" onsubmit={ (event) => { state.validator.submit(event) } }> <form id="app-task-form" class="form" slot="form" onsubmit={ (event) => { state.isLoading = true; update(); state.validator.submit(event) } }>
<div class="field-group"> <div class="field-group">
<label class="field-label"> <label class="field-label">
name name
<input class="field-text" name="name" type="text" /> <input class="field-text" name="name" type="text" value="{ state.current.name }" />
<field-error name="name"></field-error> <field-error name="name"></field-error>
</label> </label>
</div> </div>
<div class="field-group"> <div class="field-group">
<label class="field-label"> <label class="field-label">
url url
<input class="field-text" name="url" type="text" /> <input class="field-text" name="url" type="text" value="{ state.current.url }" />
<field-error name="url"></field-error> <field-error name="url"></field-error>
</label> </label>
</div> </div>
@ -33,7 +33,7 @@
requestHandler requestHandler
<select class="field-choice" name="requestHandler"> <select class="field-choice" name="requestHandler">
<option></option> <option></option>
<option each={ handler in state.requestHandlers }></option> <option value="{ handler }" each={ handler in state.requestHandlers } selected={ action === state.current.requestHandler }></option>
</select> </select>
<field-error name="requestHandler"></field-error> <field-error name="requestHandler"></field-error>
</label> </label>
@ -43,11 +43,25 @@
action action
<select class="field-choice" name="action"> <select class="field-choice" name="action">
<option></option> <option></option>
<option each={ handler in state.actions }></option> <option value="{ action }" each={ action in state.actions } selected={ action === state.current.action }></option>
</select> </select>
<field-error name="action"></field-error> <field-error name="action"></field-error>
</label> </label>
</div> </div>
<div class="field-group">
<label class="field-label">
options
<input type="text" name="options" class="field-text" value="{ JSON.stringify(state.current.options) }" />
<field-error name="options"></field-error>
</label>
</div>
<div class="field-group">
<label class="field-label">
timer
<input type="text" name="timer" class="field-text" value="{ state.current.timer }" />
<field-error name="timer"></field-error>
</label>
</div>
</form> </form>
</app-sidebar> </app-sidebar>
@ -58,7 +72,11 @@
import FormValidator from '@tiny-components/validator/src/formValidator.js' import FormValidator from '@tiny-components/validator/src/formValidator.js'
// stores
import taskFormStore from './../stores/taskForm.js' import taskFormStore from './../stores/taskForm.js'
import notificationStore from './../stores/notification'
// mixins
import sidebar from './../mixins/sidebar.js' import sidebar from './../mixins/sidebar.js'
import FieldError from '@tiny-components/validator/src/fieldError.riot' import FieldError from '@tiny-components/validator/src/fieldError.riot'
@ -72,13 +90,20 @@
export default () => { export default () => {
return { return {
...sidebar, ...sidebar, // adding basic funtion for sidebar
state: { state: {
requestHandlers: [], requestHandlers: [],
validator: undefined, validator: undefined,
current: { current: {
name: '',
url: '',
requestHandler: '',
action: '',
options: {
},
timer: ''
} }
}, },
@ -98,6 +123,12 @@
}, },
'requestHandler': { 'requestHandler': {
'presence': true 'presence': true
},
'action': {
'presence': true
},
'timer': {
'presence': true
} }
}) })
@ -106,6 +137,14 @@
this.handleSuccess(event, data) this.handleSuccess(event, data)
}) })
// adding on success
this.state.validator.onError((event, data) => {
this.state.isLoading = false
notificationStore.danger('Error! Check your input!')
this.update()
})
taskFormStore.on('open', (data) => { taskFormStore.on('open', (data) => {
this.state.isOpen = true this.state.isOpen = true
this.update() this.update()

@ -1,6 +1,6 @@
<app-task-button> <app-task-button>
<button class="button m-bottom-0 m-top-5" onclick={ (event) => { handleOpen(event) } }> <button class="button m-bottom-0 m-top-5" onclick={ (event) => { handleOpen(event) } }>
<svg class="icon fill-text-contrast" aria-hidden="true"> <svg class="icon fill-text fill-text-contrast-hover m-top-1 p-right-2" aria-hidden="true">
<use xlink:href="/symbol-defs.svg#icon-close"></use> <use xlink:href="/symbol-defs.svg#icon-close"></use>
</svg> </svg>
{ state.text } { state.text }
@ -11,8 +11,10 @@
import taskFormStore from './../stores/taskForm.js' import taskFormStore from './../stores/taskForm.js'
/** /**
* handle open and close of form for tasks
* *
* *
* @author Björn Hase, <me@herr-hase.wtf>
* *
*/ */
@ -35,9 +37,11 @@
}, },
/** /**
* trigger open in storage
*
*
* @param {object} event
* *
* @param {[type]} event
* @return {[type]}
*/ */
handleOpen(event, data = undefined) handleOpen(event, data = undefined)
{ {

@ -7,7 +7,8 @@
export default { export default {
state: { state: {
isOpen: false isOpen: false,
isLoading: false
}, },
/** /**

@ -0,0 +1,49 @@
import observable from '@riotjs/observable'
/**
* NotificationService
*
*
*/
export default observable({
SUCCESS: 'success',
DANGER: 'danger',
INFO: 'info',
/**
*
*
*/
success(message) {
this._add(message, this.SUCCESS)
},
/**
*
*
*/
danger(message) {
this._add(message, this.DANGER)
},
/**
*
*
*/
info(message) {
this._add(message, this.INFO)
},
/**
*
* @param {[type]} message [description]
* @param {[type]} type [description]
*/
_add(message, type) {
this.trigger('update', {
message: message,
type: type
})
}
})

@ -1,21 +0,0 @@
import observable from '@riotjs/observable'
/**
*
*
*
*/
const sidebarDispatcher = {
/**
*
*
*/
onAfterSuccess(data)
{
this.trigger('sidebar-success', data)
}
}
export default observable(sidebarDispatcher)

@ -1,12 +1,16 @@
{ {
"name": "frontend", "name": "frontend",
"version": "0.1.0", "version": "0.1.0",
"scripts": {
"build": "npx mix"
},
"dependencies": { "dependencies": {
"@riotjs/observable": "^4.1.1", "@riotjs/observable": "^4.1.1",
"@tiny-components/plain-ui": "^0.5.0", "@tiny-components/plain-ui": "^0.5.0",
"@tiny-components/validator": "^0.1.0", "@tiny-components/validator": "^0.1.0",
"got": "^12.0.1", "got": "^12.0.1",
"riot": "^6.1.2" "riot": "^6.1.2",
"uuid": "^8.3.2"
}, },
"devDependencies": { "devDependencies": {
"@riotjs/webpack-loader": "^6.0.0", "@riotjs/webpack-loader": "^6.0.0",

@ -0,0 +1,7 @@
// format list of errors
.field-error {
ul {
margin: 0;
padding: 0 0 0 1em;
}
}

@ -0,0 +1,22 @@
.loading-wrapper {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
display: flex;
.loading {
align-self: center;
}
&:before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #ffffff45;
}
}

@ -1,2 +1,6 @@
@import @import
'../node_modules/@tiny-components/plain-ui/src/scss/plain-ui';
'@tiny-components/plain-ui/src/scss/plain-ui',
'components/field-error',
'components/loading';

@ -19,4 +19,7 @@
{% block script %} {% block script %}
<script async src="/js/app.js"></script> <script async src="/js/app.js"></script>
<script>
const actions = {{ requestHandlers | json }}
</script>
{% endblock %} {% endblock %}

@ -40,6 +40,7 @@
</noscript> </noscript>
{% block app_main %}{% endblock %} {% block app_main %}{% endblock %}
<app-notification></app-notification>
</main> </main>
<footer> <footer>

@ -36,6 +36,20 @@ mix.webpackConfig({
filename: 'public/symbol-defs.svg', filename: 'public/symbol-defs.svg',
chunk: { chunk: {
keep: true keep: true
},
svgo: {
plugins: [{
name: 'convertStyleToAttrs',
active: true
},{
name: 'removeStyleElement',
active: true
}, {
name: 'removeAttrs',
params: {
attrs: 'fill'
}
}]
} }
}, },
sprite: { sprite: {
@ -52,8 +66,8 @@ mix
.purgeCss({ .purgeCss({
extend: { extend: {
content: [ content: [
path.join(__dirname, '**/*.riot'), path.join(__dirname, 'js/**/*.riot'),
path.join(__dirname, '../server/views/**/*.liquid') path.join(__dirname, 'views/*.liquid')
] ]
} }
}) })

@ -24,7 +24,12 @@ export default async function(fastify, opts)
*/ */
fastify.get('/', (request, response) => fastify.get('/', (request, response) =>
{ {
response.view('../frontend/views/index') response.view('../frontend/views/index', {
'responseHandlers': [{
test: 1
}],
'actions': []
})
}) })
/** /**

@ -14970,3 +14970,29 @@ svg.field-choice__checked {
.opacity-10 { .opacity-10 {
opacity: 1; opacity: 1;
} }
.field-error ul {
margin: 0;
padding: 0 0 0 1em;
}
.loading-wrapper {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
display: flex;
}
.loading-wrapper .loading {
align-self: center;
}
.loading-wrapper:before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.2705882353);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 66 KiB

11681
yarn.lock

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