1 | #!/usr/bin/env node
|
2 |
|
3 | /**
|
4 | * Module dependencies.
|
5 | */
|
6 |
|
7 | try {
|
8 | var stylus = require('stylus');
|
9 | } catch (err) {
|
10 | var stylus = require('../lib/stylus');
|
11 | }
|
12 |
|
13 | /**
|
14 | * Banner.
|
15 | */
|
16 |
|
17 | var 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 |
|
32 | var steps = [];
|
33 |
|
34 | /**
|
35 | * Clear the screen and move the cursor up.
|
36 | */
|
37 |
|
38 | function clear() {
|
39 | console.log('\x1b[1J\x1b[H');
|
40 | }
|
41 |
|
42 | /**
|
43 | * Output "press enter" message.
|
44 | */
|
45 |
|
46 | function 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 |
|
59 | function 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 |
|
125 | steps.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 |
|
136 | steps.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 |
|
152 | steps.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 |
|
162 | steps.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 |
|
175 | steps.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 |
|
186 | steps.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 |
|
201 | steps.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 |
|
219 | steps.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 |
|
238 | steps.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 |
|
263 | clear();
|
264 | console.log('\x1b[1m' + banner + '\x1b[0m');
|
265 | console.log('\n Welcome to the stylus interactive tutorial.\n');
|
266 | console.log(' - To quit at any time type \x1b[1mquit\x1b[0m.');
|
267 | console.log(' - To force rendering type "." and press enter,');
|
268 | console.log(' however source will be automatically rendered');
|
269 | console.log(' when it matches the step\'s source.');
|
270 | console.log();
|
271 | enter();
|
272 |
|
273 | var stdin = process.openStdin();
|
274 | stdin.setEncoding('utf8');
|
275 |
|
276 | stdin.once = function(event, fn){
|
277 | this.on(event, function callback(chunk){
|
278 | stdin.removeListener(event, callback);
|
279 | fn(chunk);
|
280 | });
|
281 | };
|
282 |
|
283 | stdin.once('data', function(chunk){
|
284 | stdin.pause();
|
285 | clear();
|
286 | steps[0].display();
|
287 | });
|