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/app.js": "/public/js/app.js?id=3af721e60a47e6147d71c98308c2b6e1",
"/public/css/styles.css": "/public/css/styles.css?id=d8096bd2ff84ae29cb0ecf810064b218",
"/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"
"/public/js/app.js": "/public/js/app.js?id=1c9307a192e1817119e543e388f2a43b",
"/public/css/styles.css": "/public/css/styles.css?id=72a43d98017bdbcb83928c41f6289210"
}

13
package-lock.json generated

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

@ -5,6 +5,7 @@
"packages/*"
],
"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 AppTaskForm from './components/task-form.riot'
import AppNotification from './components/notification.riot'
// register components
riot.register('app-sidebar', AppSidebar)
riot.register('app-tasks', AppTasks)
riot.register('app-task-button', AppTaskButton)
riot.register('app-task-form', AppTaskForm)
riot.register('app-notification', AppNotification)
// mount components
riot.mount('app-sidebar')
riot.mount('app-tasks')
riot.mount('app-task-button')
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 class="bar__end">
<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>
</svg>
</button>
@ -19,17 +19,18 @@
<!-- body -->
<div class="sidebar__body">
<slot name="form" />
<app-loading loading={ props.loading }></app-loading>
</div>
<!-- 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
<svg class="icon fill-success p-left-3" aria-hidden="true">
<use xlink:href="/symbol-defs.svg#icon-check"></use>
</svg>
</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
<svg class="icon fill-success p-left-3" aria-hidden="true">
<use xlink:href="/symbol-defs.svg#icon-arrow-right"></use>
@ -42,6 +43,11 @@
<script>
import * as riot from 'riot'
import AppLoading from './loading.riot'
riot.register('app-loading', AppLoading)
/**
*
*

@ -1,6 +1,6 @@
<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 -->
<span slot="title">
@ -13,18 +13,18 @@
</span>
<!-- 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">
<label class="field-label">
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>
</label>
</div>
<div class="field-group">
<label class="field-label">
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>
</label>
</div>
@ -33,7 +33,7 @@
requestHandler
<select class="field-choice" name="requestHandler">
<option></option>
<option each={ handler in state.requestHandlers }></option>
<option value="{ handler }" each={ handler in state.requestHandlers } selected={ action === state.current.requestHandler }></option>
</select>
<field-error name="requestHandler"></field-error>
</label>
@ -43,11 +43,25 @@
action
<select class="field-choice" name="action">
<option></option>
<option each={ handler in state.actions }></option>
<option value="{ action }" each={ action in state.actions } selected={ action === state.current.action }></option>
</select>
<field-error name="action"></field-error>
</label>
</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>
</app-sidebar>
@ -58,7 +72,11 @@
import FormValidator from '@tiny-components/validator/src/formValidator.js'
// stores
import taskFormStore from './../stores/taskForm.js'
import notificationStore from './../stores/notification'
// mixins
import sidebar from './../mixins/sidebar.js'
import FieldError from '@tiny-components/validator/src/fieldError.riot'
@ -72,13 +90,20 @@
export default () => {
return {
...sidebar,
...sidebar, // adding basic funtion for sidebar
state: {
requestHandlers: [],
validator: undefined,
current: {
name: '',
url: '',
requestHandler: '',
action: '',
options: {
},
timer: ''
}
},
@ -98,6 +123,12 @@
},
'requestHandler': {
'presence': true
},
'action': {
'presence': true
},
'timer': {
'presence': true
}
})
@ -106,6 +137,14 @@
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) => {
this.state.isOpen = true
this.update()

@ -1,6 +1,6 @@
<app-task-button>
<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>
</svg>
{ state.text }
@ -11,8 +11,10 @@
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)
{

@ -7,7 +7,8 @@
export default {
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",
"version": "0.1.0",
"scripts": {
"build": "npx mix"
},
"dependencies": {
"@riotjs/observable": "^4.1.1",
"@tiny-components/plain-ui": "^0.5.0",
"@tiny-components/validator": "^0.1.0",
"got": "^12.0.1",
"riot": "^6.1.2"
"riot": "^6.1.2",
"uuid": "^8.3.2"
},
"devDependencies": {
"@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
'../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 %}
<script async src="/js/app.js"></script>
<script>
const actions = {{ requestHandlers | json }}
</script>
{% endblock %}

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

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

@ -24,7 +24,12 @@ export default async function(fastify, opts)
*/
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: 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