Skip to content

Commit 48a67dd

Browse files
committed
feat: add light package
1 parent 185e1ec commit 48a67dd

File tree

13 files changed

+410
-2
lines changed

13 files changed

+410
-2
lines changed

light/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.vscode
2+
node_modules
3+
dist

light/.npmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
access = "public"

light/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Vue.js Cron Vuetify
2+
3+
lightweight vue.js cron editor
4+
5+
This component is inspired by [react-js-cron](https://github.com/xrutayisire/react-js-cron) and [jqcron](https://github.com/arnapou/jqcron)
6+
7+
## Usage
8+
9+
**Demo** and **getting started guide** at [https://abichinger.github.io/vue-js-cron/guide/getting-started.html#quick-start-cronlight](https://abichinger.github.io/vue-js-cron/guide/getting-started.html#quick-start-vuetify)

light/build/rollup.config.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import commonjs from '@rollup/plugin-commonjs'; // Convert CommonJS modules to ES6
2+
import vue from 'rollup-plugin-vue'; // Handle .vue SFC files
3+
import buble from '@rollup/plugin-buble'; // Transpile/polyfill with reasonable browser support
4+
import css from 'rollup-plugin-css-only'
5+
export default {
6+
input: 'src/index.js', // Path relative to package.json
7+
output: {
8+
name: 'light',
9+
exports: 'named',
10+
},
11+
plugins: [
12+
css({
13+
output: 'light.css',
14+
}),
15+
vue({
16+
css: false, // Dynamically inject css as a <style> tag
17+
compileTemplate: true, // Explicitly convert template to render function
18+
}),
19+
commonjs(),
20+
/*buble({
21+
objectAssign: 'Object.assign',
22+
transforms: {
23+
forOf: false
24+
}
25+
}), // Transpile to ES5*/
26+
],
27+
};

light/dev/example-usage.vue

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<template>
2+
<VueCronEditor v-model="value">
3+
4+
</VueCronEditor>
5+
</template>
6+
7+
<script>
8+
import VueCronEditor from '../src/CronEditor'
9+
10+
export default {
11+
name: 'Editor',
12+
components:{
13+
VueCronEditor
14+
},
15+
16+
data:() => {
17+
return {
18+
value: '* * * * *'
19+
}
20+
}
21+
}
22+
</script>
23+
24+
<style>
25+
.vcron-editor{
26+
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
27+
}
28+
</style>

light/dev/serve.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import Vue from 'vue'
2+
import example from './example-usage.vue'
3+
4+
Vue.config.productionTip = false
5+
6+
new Vue({
7+
render: h => h(example),
8+
}).$mount('#app')

light/package.json

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"name": "@vue-js-cron/light",
3+
"version": "1.0.0",
4+
"description": "lightweight vue.js cron editor",
5+
"main": "dist/light.umd.js",
6+
"module": "dist/light.esm.js",
7+
"unpkg": "dist/light.min.js",
8+
"browser": {
9+
"./sfc": "src/CronEditor.vue"
10+
},
11+
"repository": "https://github.com/abichinger/vue-js-cron",
12+
"author": "Andreas Bichinger",
13+
"license": "MIT",
14+
"private": false,
15+
"scripts": {
16+
"test": "jest",
17+
"serve": "vue-cli-service serve dev/serve.js",
18+
"build": "yarn build:umd & yarn run build:es & yarn run build:unpkg",
19+
"build:umd": "yarn rollup --config build/rollup.config.js --format umd --file dist/light.umd.js",
20+
"build:es": "yarn rollup --config build/rollup.config.js --format es --file dist/light.esm.js",
21+
"build:unpkg": "yarn rollup --config build/rollup.config.js --format iife --file dist/light.min.js"
22+
},
23+
"dependencies": {
24+
"@vue-js-cron/core": "1.0.1"
25+
},
26+
"devDependencies": {
27+
"@vue/cli-service": "^4.5.15",
28+
"rollup-plugin-css-only": "^3.1.0"
29+
},
30+
"files": [
31+
"package.json",
32+
"dist",
33+
"README.md"
34+
],
35+
"keywords": [
36+
"vue",
37+
"vue.js",
38+
"vue component",
39+
"cron",
40+
"cron expression",
41+
"cron editor",
42+
"light"
43+
]
44+
}

light/src/CronEditor.vue

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
2+
<template>
3+
<CronCore v-bind="$attrs" @input="$emit('input', $event)" @error="$emit('error', $event)">
4+
<template #default="{fields, period}">
5+
6+
<span class="vcron-editor">
7+
<span>{{period.prefix}}</span>
8+
<custom-select v-bind="period.attrs" v-on="period.events" :items="period.items" item-value="id" :cols="cols('period')" :width="width('period')" />
9+
<span>{{period.suffix}}</span>
10+
11+
12+
<template v-for="f in fields">
13+
<span :key="f.id+'prefix'">{{f.prefix}}</span>
14+
<custom-select v-bind="f.attrs" v-on="f.events" :items="f.items" :key="f.id" :cols="cols(f.id)" :width="width(f.id)" multiple>{{f.selectedStr}}</custom-select>
15+
<span :key="f.id+'suffix'">{{f.suffix}}</span>
16+
</template>
17+
18+
</span>
19+
20+
</template>
21+
</CronCore>
22+
23+
</template>
24+
25+
<script>
26+
import CronCore from '@vue-js-cron/core'
27+
import CustomSelect from './components/CustomSelect.vue'
28+
29+
export default {
30+
name: "VueCronEditor",
31+
components:{
32+
'CronCore': CronCore.component,
33+
CustomSelect
34+
},
35+
props:{
36+
cols: {
37+
type: Function,
38+
default: (fieldId) => {
39+
40+
if(fieldId == 'minute') return 5
41+
else if (fieldId == 'hour') return 4
42+
else if (fieldId == 'day') return 4
43+
else return 1
44+
45+
}
46+
},
47+
width: {
48+
type: Function,
49+
default: (fieldId) => {
50+
if(fieldId == 'minute') return '10em'
51+
else if (fieldId == 'hour') return '8em'
52+
else if (fieldId == 'day') return '8em'
53+
else return 'unset'
54+
}
55+
}
56+
}
57+
}
58+
</script>

light/src/components/CustomSelect.vue

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
<template>
2+
<div class="vcron-select-container">
3+
<span class="vcron-select-input" @click="toggleMenu">
4+
<slot>{{selectedStr}}</slot>
5+
</span>
6+
<span class="vcron-select-list" :style="listStyle">
7+
<span v-for="item in items"
8+
:key="item[itemValue]+''"
9+
class="vcron-select-list-item"
10+
:class="{'vcron-select-list-item-selected': selectedItems.includes(item)}"
11+
:style="listItemStyle"
12+
@click="select(item)"
13+
@click.stop="multiple ? () => {} : toggleMenu()">
14+
15+
{{item[itemText]}}
16+
</span>
17+
</span>
18+
</div>
19+
</template>
20+
21+
<script>
22+
import multiple from '@vue-js-cron/core/src/fields/multiple'
23+
24+
export default {
25+
inheritAttrs: false,
26+
name: 'CustomSelect',
27+
props:{
28+
multiple: {
29+
type: Boolean,
30+
default: false
31+
},
32+
value: {
33+
type: String | Array | Object,
34+
default(){
35+
return this.multiple ? [] : null
36+
},
37+
},
38+
items: {
39+
type: Array,
40+
default: () => []
41+
},
42+
returnObject: {
43+
type: Boolean,
44+
default: false
45+
},
46+
itemText: {
47+
type: String,
48+
default: 'text'
49+
},
50+
itemValue: {
51+
type: String,
52+
default: 'value'
53+
},
54+
cols: {
55+
type: Number,
56+
default: 1
57+
},
58+
width: {
59+
type: String,
60+
default: 'unset'
61+
}
62+
},
63+
data(){
64+
return {
65+
menu: false
66+
}
67+
},
68+
computed: {
69+
listStyle() {
70+
return {
71+
display: (this.menu) ? 'inline-block' : 'none',
72+
minWidth: '5em',
73+
width: this.width
74+
}
75+
},
76+
listItemStyle() {
77+
return {
78+
width: 100/this.cols + '%'
79+
}
80+
},
81+
_value(){
82+
return (this.multiple) ? this.value : [this.value]
83+
},
84+
selectedItems(){
85+
return this.items.filter((item) => {
86+
for(let value of this._value){
87+
if(this.returnObject){
88+
if (value == item) return true
89+
}
90+
else{
91+
if (value == item[this.itemValue]) return true
92+
}
93+
}
94+
return false
95+
})
96+
},
97+
selectedStr(){
98+
return this.selectedItems.map((item) => item[this.itemText]).join(',')
99+
}
100+
},
101+
methods: {
102+
menuEvtListener(evt){
103+
this.menu = false
104+
document.removeEventListener('click', this.menuEvtListener)
105+
},
106+
toggleMenu(){
107+
this.menu = !this.menu
108+
109+
if(this.menu){
110+
setTimeout(() => {
111+
document.addEventListener('click', this.menuEvtListener)
112+
}, 1)
113+
}
114+
else {
115+
document.removeEventListener('click', this.menuEvtListener)
116+
}
117+
},
118+
select(item){
119+
if(this.multiple){
120+
let value = this.selectedItems.slice()
121+
let i = this.selectedItems.indexOf(item)
122+
//deselect
123+
if(i >= 0){
124+
value.splice(i,1)
125+
}
126+
//select
127+
else{
128+
value.push(item)
129+
}
130+
this.$emit('input', (this.returnObject) ? value : value.map((item) => item[this.itemValue]))
131+
}
132+
else {
133+
this.$emit('input', (this.returnObject) ? item : item[this.itemValue])
134+
}
135+
}
136+
}
137+
}
138+
</script>
139+
140+
<style>
141+
142+
.vcron-select-container {
143+
display: inline-block;
144+
position: relative;
145+
margin: 0 0.2em;
146+
}
147+
148+
.vcron-select-input {
149+
display: inline-block;
150+
border-radius: 3px;
151+
border: 1px solid #eee;
152+
background-color: #ddd;
153+
user-select: none;
154+
padding: 0 0.5em;
155+
}
156+
157+
.vcron-select-list {
158+
position: absolute;
159+
top: 1.8em;
160+
left: 0px;
161+
margin: 0;
162+
padding: 0;
163+
box-shadow: 2px 2px 3px rgba(0,0,0,0.5);
164+
border: 1px solid #aaa;
165+
background-color: #eee;
166+
list-style: none;
167+
z-index: 100;
168+
}
169+
170+
.vcron-select-list-item {
171+
display: inline-block;
172+
box-sizing: border-box;
173+
user-select: none;
174+
width: 100%;
175+
padding: 0.2em 0.5em;
176+
text-align: center;
177+
}
178+
179+
.vcron-select-list-item:hover {
180+
background-color: rgb(52, 147, 190);
181+
color: white;
182+
}
183+
184+
.vcron-select-list-item-selected {
185+
background-color: rgb(43, 108, 138);
186+
color: white;
187+
}
188+
189+
</style>

0 commit comments

Comments
 (0)