Skip to content

Commit a4f6ded

Browse files
committed
Added a interactive code preview
1 parent f2ea63f commit a4f6ded

File tree

5 files changed

+331
-50
lines changed

5 files changed

+331
-50
lines changed
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
/*
2+
Usage:
3+
<ClientOnly>
4+
<MojsInteractive
5+
id="unique_id"
6+
:controller=true
7+
code=
8+
"new mojs.Shape({
9+
parent: '#unique_id',
10+
shape: 'circle',
11+
radius: {20: 80},
12+
})"
13+
>
14+
</MojsInteractive>
15+
</ClientOnly>
16+
*/
17+
<template>
18+
<div class="mojs-interactive">
19+
<div class="mojs-interactive__code">
20+
<prism-editor :code="code" language="js" @change="change"></prism-editor>
21+
<div class="buttons">
22+
<button class="button button--secondary" v-on:click="reset">Reset</button>
23+
<button class="button" v-on:click="updateCode">Update code</button>
24+
</div>
25+
</div>
26+
<div :id="this.id" class="mojs-interactive__result" :style="style">
27+
<button class="button button--icon" v-if="isPlaying && !controller" v-on:click="pause" aria-label="Pause animation">⑊</button>
28+
<button class="button button--icon" v-if="!isPlaying && !controller" v-on:click="play" aria-label="Play animation">▶︎</button>
29+
<div v-if="controller" :id="this.id + '_controller'" class="mojs-interactive__controller"></div>
30+
</div>
31+
</div>
32+
</template>
33+
34+
<script>
35+
import mojs from 'mo-js';
36+
import MojsPlayer from 'mojs-player';
37+
38+
import prism from 'prismjs';
39+
import PrismEditor from 'vue-prism-editor'
40+
41+
export default {
42+
components: {
43+
PrismEditor
44+
},
45+
46+
props: {
47+
id: { type: String, default: 'code_example' },
48+
controller: { type: [String, Boolean], default: false },
49+
height: { type: String, default: '300px' },
50+
code: { type: String, default: '' },
51+
},
52+
53+
data: function () {
54+
return {
55+
rawCode: this.code,
56+
isPlaying: false,
57+
}
58+
},
59+
60+
computed: {
61+
style () {
62+
return 'height: ' + this.height;
63+
}
64+
},
65+
66+
methods: {
67+
change: function(c) {
68+
this.rawCode = c;
69+
},
70+
71+
handleCode: function(code) {
72+
if (!window) return; // For SSR
73+
74+
// Do some cleaning
75+
if (window['demo_' + this.id]) { // the mojs animation element
76+
window['demo_' + this.id].stop();
77+
window['demo_' + this.id].el.remove(); // remove the DOM node
78+
delete window['demo_' + this.id];
79+
}
80+
if (window['mojsPlayer_' + this.id]) { // the mojs player element
81+
window['mojsPlayer_' + this.id].el.remove(); // remove the DOM node
82+
delete window['mojsPlayer_' + this.id];
83+
}
84+
// Creating a global window object from a provided mojs object (code), and play it.
85+
const func = new Function('window["demo_' + this.id + '"] = ' + code);
86+
try {
87+
func();
88+
if (!this.controller) {
89+
window['demo_' + this.id].play();
90+
this.isPlaying = true;
91+
}
92+
}
93+
catch(error) {
94+
console.error('Woops, please check your code for errors.', error)
95+
}
96+
97+
// Set the prop :controller=true to include a mojs player
98+
if (this.controller && window['demo_' + this.id]) {
99+
const parentDOM = document.getElementById(this.id + '_controller');
100+
101+
// Create a global mojs player instance
102+
window['mojsPlayer_' + this.id] = new MojsPlayer({
103+
add: window['demo_' + this.id],
104+
parent: parentDOM,
105+
className: 'controller',
106+
isSaveState: true,
107+
isPlaying: true,
108+
isRepeat: true,
109+
name: 'demo_' + this.id,
110+
});
111+
}
112+
},
113+
114+
updateCode: function() {
115+
this.handleCode(this.rawCode);
116+
},
117+
118+
reset: function() {
119+
this.handleCode(this.code);
120+
},
121+
122+
pause: function() {
123+
window['demo_' + this.id].pause();
124+
this.isPlaying = false;
125+
},
126+
127+
play: function() {
128+
window['demo_' + this.id].play();
129+
this.isPlaying = true;
130+
}
131+
},
132+
133+
mounted: function () {
134+
this.handleCode(this.code);
135+
}
136+
137+
}
138+
</script>
139+
140+
<style>
141+
.mojs-interactive__code {
142+
position: relative;
143+
padding-bottom: 1.2em;
144+
}
145+
.mojs-interactive__code .buttons {
146+
position: absolute;
147+
bottom: 1rem;
148+
right: 1rem;
149+
}
150+
.mojs-interactive__result {
151+
position: relative;
152+
}
153+
.mojs-interactive__result .button {
154+
position: absolute;
155+
bottom: 0;
156+
right: 0;
157+
}
158+
159+
.mojs-interactive__result {
160+
background: #f1e2d7;
161+
width: 100%;
162+
height: 400px;
163+
position: relative;
164+
overflow: hidden;
165+
}
166+
.mojs-interactive__result svg {
167+
overflow: visible
168+
}
169+
170+
.mojs-interactive__controller {
171+
position: absolute;
172+
bottom: 0;
173+
left: 0;
174+
right: 0;
175+
}
176+
.mojs-interactive__controller .controller {
177+
position: absolute;
178+
}
179+
</style>

docs/.vuepress/styles/index.styl

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,33 @@ hr
111111
overflow: visible // for overshoots animations
112112
}
113113
}
114+
115+
// Temp button. Use the "material design" button from the original site instead
116+
.button {
117+
background: $accentColor;
118+
color: $textColor;
119+
border: none;
120+
padding: 1em 2em;
121+
font-size: 0.7rem;
122+
font-family: inherit;
123+
font-weight: bold;
124+
border-radius: 4px;
125+
cursor: pointer;
126+
text-transform: uppercase;
127+
&--secondary {
128+
background: $c-purple;
129+
border: 1px solid $accentColor;
130+
color: $accentColor;
131+
}
132+
&--icon {
133+
background: transparent;
134+
font-size: 2rem;
135+
padding: 0.4em;
136+
line-height: 1;
137+
color: $accentColor;
138+
}
139+
}
140+
141+
.button + .button {
142+
margin-left: 0.5rem
143+
}

docs/tutorials/getting-started.md

Lines changed: 51 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -12,57 +12,63 @@
1212

1313
- Create your animations. What about a bouncy circle?
1414

15+
1516
<ClientOnly>
16-
<ExampleCircle>
17-
```js
18-
var circle = new mojs.Shape({
19-
parent: '#circle-anim',
20-
shape: 'circle',
21-
fill: {'#F64040': '#FC46AD'},
22-
radius: {20: 80},
23-
duration: 2000,
24-
isYoyo: true,
25-
easing: 'elastic.inout',
26-
repeat: 999,
27-
})
28-
.play();
29-
```
30-
</ExampleCircle>
17+
<MojsInteractive
18+
id="bouncy_circle"
19+
:controller=true
20+
code=
21+
"new mojs.Shape({
22+
parent: '#bouncy_circle',
23+
shape: 'circle',
24+
fill: {'#F64040': '#FC46AD'},
25+
radius: {20: 80},
26+
duration: 2000,
27+
isYoyo: true,
28+
isShowStart: true,
29+
easing: 'elastic.inout',
30+
repeat: 1,
31+
})"
32+
>
33+
</MojsInteractive>
3134
</ClientOnly>
3235
36+
---
37+
3338
Or maybe a loading animation?
3439

3540
<ClientOnly>
36-
<ExampleSpinner height="200px" id="spinner">
37-
```js
38-
var loader = new mojs.Shape({
39-
parent: '#spinner',
40-
shape: 'circle',
41-
stroke: '#FC46AD',
42-
strokeDasharray: '125, 125',
43-
strokeDashoffset: {'0': '-125'},
44-
strokeWidth: 4,
45-
fill: 'none',
46-
left: '50%',
47-
top: '50%',
48-
angle: {'-90': '270'},
49-
radius: 20,
50-
isShowStart: true,
51-
duration: 2000,
52-
easing: 'back.in',
53-
})
54-
.then({
55-
angle: {'-90': '270'},
56-
strokeDashoffset: {'-125': '-250'},
57-
duration: 3000,
58-
easing: 'cubic.out',
59-
onComplete () {
60-
loader.replay(0); // create an infinite loop
61-
}
62-
})
63-
.play();
64-
```
65-
</ExampleSpinner>
41+
<MojsInteractive
42+
id="spinner"
43+
height="200px"
44+
code=
45+
"new mojs.Shape({
46+
parent: '#spinner',
47+
shape: 'circle',
48+
stroke: '#FC46AD',
49+
strokeDasharray: '125, 125',
50+
strokeDashoffset: {'0': '-125'},
51+
strokeWidth: 4,
52+
fill: 'none',
53+
left: '50%',
54+
top: '50%',
55+
angle: {'-90': '270'},
56+
radius: 20,
57+
isShowStart: true,
58+
duration: 2000,
59+
easing: 'back.in',
60+
})
61+
.then({
62+
angle: {'-90': '270'},
63+
strokeDashoffset: {'-125': '-250'},
64+
duration: 3000,
65+
easing: 'cubic.out',
66+
onComplete () {
67+
this.replay(0); // create an infinite loop
68+
}
69+
})"
70+
>
71+
</MojsInteractive>
6672
</ClientOnly>
6773
6874
Go creative!

0 commit comments

Comments
 (0)