UNPKG

6.95 kBPlain TextView Raw
1#!/usr/bin/env node
2
3/**
4 * Module dependencies.
5 */
6
7try {
8 var stylus = require('stylus');
9} catch (err) {
10 var stylus = require('../lib/stylus');
11}
12
13/**
14 * Banner.
15 */
16
17var banner = '\n\
18 \n\
19 _ _ \n\
20 ___| |_ _ _| |_ _ ___ \n\
21 / __| __| | | | | | | / __| \n\
22 \\__ \\ |_| |_| | | |_| \\__ \\ \n\
23 |___/\\__|\\__, |_|\\__,_|___/ \n\
24 |___/ \n\
25 \n\
26';
27
28/**
29 * Steps.
30 */
31
32var steps = [];
33
34/**
35 * Clear the screen and move the cursor up.
36 */
37
38function clear() {
39 console.log('\x1b[1J\x1b[H');
40}
41
42/**
43 * Output "press enter" message.
44 */
45
46function enter() {
47 process.stdout.write('\x1b[90mpress enter to continue:\x1b[0m ');
48}
49
50/**
51 * Initialize a `Step` with the given data.
52 *
53 * @param {String} title
54 * @param {String} desc
55 * @param {String} src
56 * @param {Function} fn
57 */
58
59function Step(title, desc, src, fn) {
60 var self = this;
61 this.n = steps.length;
62 this.src = src;
63 desc = desc.replace(/\_([^_]+)\_/g, '\x1b[33m$1\x1b[90m');
64
65 this.next = function(){
66 var step = steps[self.n + 1];
67 if (step) {
68 step.display();
69 } else {
70 console.log(' THE END\n');
71 process.exit(0);
72 }
73 };
74
75 this.display = function(retry){
76 if (!retry) {
77 console.log(' %d) \x1b[1m%s\x1b[0m\n', self.n, title);
78 console.log(' \x1b[90m%s\x1b[0m', desc);
79 }
80 console.log('\n%s\n', src);
81 console.log('\x1b[90m--------------------\x1b[0m \n');
82 this.input();
83 };
84
85 this.input = function(){
86 stdin.resume();
87 var buf = '';
88 stdin.on('data', function callback(chunk){
89 if (0 == chunk.indexOf('quit')) process.exit(1);
90 var dot = '.' == chunk[0] && '\n' == chunk[1]
91 , equal = buf.trim() == self.src.trim();
92 if (dot || equal) {
93 stdin.pause();
94 stdin.removeListener('data', callback);
95 stylus.render(buf, { filename: 'stdin' }, function(err, css){
96 if (err) {
97 console.log('\n\x1b[31mError: ' + err.message + '\x1b[0m\n');
98 self.display(true);
99 return;
100 }
101 clear();
102 console.log('\x1b[90m-------------------- stylus\x1b[0m \n');
103 console.log(buf.replace(/^/gm, ' '));
104 console.log('\x1b[90m-------------------- css\x1b[0m \n');
105 console.log(css.replace(/^/gm, ' '));
106 console.log();
107 enter();
108 stdin.resume();
109 stdin.once('data', function(){
110 clear();
111 self.next();
112 });
113 });
114 return;
115 }
116 buf += chunk;
117 });
118 };
119}
120
121/**
122 * Step definitions.
123 */
124
125steps.push(new Step(
126 'Selector Properties'
127 , 'The Stylus grammar has indentation-based blocks,\n'
128 + ' meaning one does not surround selector properties\n'
129 + ' using braces _{_ _}_, but uses an indent of two \n'
130 + ' spaces, or a single tab.\n'
131 + '\n'
132 + ' To get started, type the stylus you see below\n'
133 + ' and then press return a few times or type _"."_ to render.'
134 , 'body\n color black'));
135
136steps.push(new Step(
137 'Multiple Selectors'
138 , 'Blocks can be applied to several selectors at once\n'
139 + ' by separating them via comma, or newline.\n'
140 + '\n'
141 + ' Both examples shown below are equivalent.'
142
143 , 'a.button, input[type=button]\n'
144 + ' border 1px solid #eee\n'
145 + ' padding 5px\n\n'
146 + 'a.button\n'
147 + 'input[type=button]\n'
148 + ' border 1px solid #eee\n'
149 + ' padding 5px'
150 ));
151
152steps.push(new Step(
153 'Nested Selectors'
154 , 'Selectors may also be nested.\n'
155
156 , 'ul\n'
157 + ' li\n'
158 + ' a\n'
159 + ' color black\n'
160 ));
161
162steps.push(new Step(
163 'Variables'
164 , 'Stylus allows you to define variables by utilizing\n'
165 + ' the _=_ operator, much like you would in any other language.\n'
166 + '\n'
167 + ' These variables may be assigned to _numbers_, _strings_, _booleans_,\n'
168 + ' and virtually everything else you see in css.'
169
170 , 'size = 14px\n\n'
171 + 'body\n'
172 + ' font size Arial, sans-serif'
173 ));
174
175steps.push(new Step(
176 'Conditional Assignment'
177 , 'The conditional assignment operator _?=_ may be used to\n'
178 + ' define a variable only when previously undefined.'
179
180 , 'size = 14px\n\n'
181 + 'body\n'
182 + ' size ?= 22px\n'
183 + ' font size Arial, sans-serif'
184 ));
185
186steps.push(new Step(
187 'Arithmetic'
188 , 'A variety of binary arithmetic operators are supported\n'
189 + ' as well as unary operators such as _-_, _+_, and _~_.'
190
191 , 'size = 14px\n'
192 + 'large-size = size * 2\n'
193 + '\n'
194 + 'body\n'
195 + ' font large-size\n'
196 + '\n'
197 + 'p\n'
198 + ' margin-left -(size - 2)'
199 ));
200
201steps.push(new Step(
202 'Coercion'
203 , 'Arithmetic operations coerce the right-hand operand when\n'
204 + ' applicable, for example converting _2s_ in _1000ms + 2s_\n'
205 + ' into _2000ms_ before evaluating the expression.\n'
206 + '\n'
207 + ' Examples:\n'
208 + ' _15px_ - _5_\n'
209 + ' _#000_ + _#eee_\n'
210 + ' _#fff_ - rgba(_0_,_0_,_0_,_.5_)\n'
211 + ' _#fff_ / _2_\n'
212 + ' _5in_ - _3cm_\n'
213
214 , 'duration = 2s\n\n'
215 + '.fade\n'
216 + ' -webkit-transition opacity duration - 1500ms linear'
217 ));
218
219steps.push(new Step(
220 'Functions'
221 , 'Stylus functions may act as mixins or have a return value.\n'
222 + 'For example here we use the unit() built-in function to.\n'
223 + 'forcing both unit\'s type to _px_, and then add them.\n'
224 + '\n'
225 + 'Note that we may also use the _return_ keyword, however it\n'
226 + 'is optional in most cases.'
227
228 , 'add(a, b)\n'
229 + ' a = unit(a, "px")\n'
230 + ' b = unit(b, "px")\n'
231 + ' a + b\n'
232 + '\n'
233 + 'body\n'
234 + ' padding add(5px, 10px)\n'
235 + ' margin add(5, 10)'
236 ));
237
238steps.push(new Step(
239 'Mixins'
240 , 'Mixins are defined in the same manner as functions\n'
241 + 'with return values, however they "mix in" their properties\n'
242 + 'and selectors into the caller.\n'
243 + '\n'
244 + 'Mixin parens are optional in most cases, so we may apply\n'
245 + 'the transparently.'
246
247 , 'border-radius(n)\n'
248 + ' -webkit-border-radius n\n'
249 + ' -moz-border-radius n\n'
250 + ' border-radius n\n'
251 + '\n'
252 + 'body\n'
253 + ' border-radius(5px)\n'
254 + '\n'
255 + 'form input\n'
256 + ' border-radius 5px'
257 ));
258
259/**
260 * Start tutorial.
261 */
262
263clear();
264console.log('\x1b[1m' + banner + '\x1b[0m');
265console.log('\n Welcome to the stylus interactive tutorial.\n');
266console.log(' - To quit at any time type \x1b[1mquit\x1b[0m.');
267console.log(' - To force rendering type "." and press enter,');
268console.log(' however source will be automatically rendered');
269console.log(' when it matches the step\'s source.');
270console.log();
271enter();
272
273var stdin = process.openStdin();
274stdin.setEncoding('utf8');
275
276stdin.once = function(event, fn){
277 this.on(event, function callback(chunk){
278 stdin.removeListener(event, callback);
279 fn(chunk);
280 });
281};
282
283stdin.once('data', function(chunk){
284 stdin.pause();
285 clear();
286 steps[0].display();
287});