Skip to content

Commit c09a3fa

Browse files
authored
Refactor components and display warning/error information (#219)
* Restructure directories * Extract Repl and Guide * Put rollup into a store * Put examples into a store * Put options and modules into store * Extract query updates * Extract selected example modules * Extract output generation * Move selected example handling to header component * Keep guide position when navigating * Change route name to avoid a caching issue * Keep REPL contents when switching back from guide * Display extended information for warnings and errors * Highlight warnings and errors in editor * Improve colors
1 parent 01ec495 commit c09a3fa

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1373
-1149
lines changed

rollup.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ export default {
8787
load(id) {
8888
// Prevent caching the guide so that it updates by refreshing the browser
8989
if (dev && id === path.join(__dirname, 'src/routes/guide/[lang]/_data.js')) {
90-
return "export { default } from './_createGuide.js';";
90+
return "export { default } from '../../../helpers/createGuide.js';";
9191
}
9292
}
9393
},

src/components/Guide.svelte

Lines changed: 346 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,346 @@
1+
<script>
2+
import { onMount, onDestroy } from 'svelte';
3+
import GuideContents from './GuideContents.svelte';
4+
import drawerOpen from '../stores/drawerOpen';
5+
import currentSection from '../stores/currentSection';
6+
7+
export let sections = [];
8+
export let lang;
9+
let container;
10+
let params;
11+
let anchors = [];
12+
let positions = [];
13+
let timeouts = [];
14+
let lastId = '';
15+
16+
function updateAnchorPositions() {
17+
const { top } = container.getBoundingClientRect();
18+
positions = anchors.map(anchor => anchor.getBoundingClientRect().top - top);
19+
}
20+
21+
// This performs a binary search to not block scrolling too much
22+
function getCurrentSection() {
23+
const top = -window.scrollY;
24+
let first = 0;
25+
let last = positions.length - 1;
26+
27+
while (first <= last) {
28+
const middle = Math.floor((first + last) / 2);
29+
if (positions[middle] + top < 40) {
30+
if (middle === last || positions[middle + 1] + top >= 40) {
31+
return middle;
32+
}
33+
first = middle + 1;
34+
} else {
35+
last = middle - 1;
36+
}
37+
}
38+
return 0;
39+
}
40+
41+
function updateCurrentSection() {
42+
const anchor = anchors[getCurrentSection()];
43+
const { id } = anchor;
44+
if (id !== $currentSection) {
45+
$currentSection = id;
46+
}
47+
}
48+
49+
function scrollOnHashChange() {
50+
const id = window.location.hash.slice(1) || $currentSection;
51+
if (id) {
52+
const element = document.getElementById(id);
53+
if (element) {
54+
window.scrollBy({ left: -Infinity, top: element.getBoundingClientRect().top });
55+
}
56+
}
57+
}
58+
59+
onMount(() => {
60+
anchors = Array.from(container.querySelectorAll('section[id]'))
61+
.concat(Array.from(container.querySelectorAll('h3[id]')))
62+
.sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top);
63+
64+
window.addEventListener('scroll', updateCurrentSection, true);
65+
window.addEventListener('resize', updateAnchorPositions, true);
66+
window.addEventListener('hashchange', scrollOnHashChange, true);
67+
68+
// wait for fonts to load...
69+
timeouts = [setTimeout(updateAnchorPositions, 1000), setTimeout(updateAnchorPositions, 5000)];
70+
71+
scrollOnHashChange();
72+
updateAnchorPositions();
73+
updateCurrentSection();
74+
});
75+
76+
onDestroy(() => {
77+
if (typeof window !== 'undefined') {
78+
window.removeEventListener('scroll', updateCurrentSection, true);
79+
window.removeEventListener('resize', updateAnchorPositions, true);
80+
window.removeEventListener('hashchange', scrollOnHashChange, true);
81+
}
82+
83+
timeouts.forEach(timeout => clearTimeout(timeout));
84+
});
85+
</script>
86+
87+
<div bind:this="{container}" class="content">
88+
<div class="hero">
89+
<strong>rollup.js</strong>
90+
</div>
91+
92+
{#each sections as section}
93+
<section id="{section.slug}">
94+
<h2>
95+
<a class="anchor" href="guide/en/#{section.slug}">
96+
<img src="/images/anchor.svg" alt="" />
97+
</a>
98+
{section.metadata.title}
99+
</h2>
100+
{@html section.html}
101+
</section>
102+
{/each}
103+
</div>
104+
105+
<div class="mousecatcher" on:click="{drawerOpen.close}" class:visible="{$drawerOpen}"></div>
106+
<div class="sidebar" class:open="{$drawerOpen}">
107+
<GuideContents sections="{sections}" lang="{lang}" />
108+
</div>
109+
110+
<style>
111+
.mousecatcher {
112+
position: fixed;
113+
left: 0;
114+
top: 0;
115+
width: 100vw;
116+
height: 100vh;
117+
background-color: black;
118+
pointer-events: none;
119+
opacity: 0;
120+
transition: opacity 0.3s;
121+
z-index: 3;
122+
}
123+
124+
.mousecatcher.visible {
125+
pointer-events: all;
126+
opacity: 0.3;
127+
touch-action: none;
128+
overscroll-behavior: none;
129+
}
130+
131+
.sidebar {
132+
position: fixed;
133+
left: 0;
134+
top: 3em;
135+
width: 16em;
136+
height: calc(100vh - 3em);
137+
display: block;
138+
background: white;
139+
z-index: 3;
140+
overflow-y: auto;
141+
padding: 1em;
142+
border-right: 1px solid #eee;
143+
transform: translateX(-16em);
144+
transition: transform 0.3s;
145+
overscroll-behavior: contain;
146+
}
147+
148+
.sidebar.open {
149+
transform: translateX(0);
150+
}
151+
152+
.content {
153+
width: 100%;
154+
padding: 1em 1em 1em 1.5em;
155+
word-break: break-word;
156+
}
157+
158+
.hero {
159+
max-width: 64em;
160+
margin: 0 auto 2em auto;
161+
border-bottom: 2px solid rgba(239, 51, 53, 0.4);
162+
display: none;
163+
}
164+
165+
.hero strong {
166+
position: relative;
167+
font-weight: 400;
168+
left: -0.03em;
169+
}
170+
171+
h2 {
172+
margin: 3rem 0 1rem -1rem;
173+
font-size: 1.8em;
174+
font-weight: 700;
175+
color: #333;
176+
z-index: 2;
177+
}
178+
179+
.content :global(h3) {
180+
margin: 4rem 0 1rem -1rem;
181+
font-size: 1.2em;
182+
font-weight: 700;
183+
color: #333;
184+
z-index: 1;
185+
}
186+
187+
.content :global(h3) :global(code) {
188+
font-weight: 700;
189+
}
190+
191+
.content :global(h4) {
192+
margin: 2em 0 0.5em 0;
193+
font-size: 1em;
194+
font-weight: 700;
195+
color: #333;
196+
}
197+
198+
.content :global(h2):before,
199+
.content :global(h3):before,
200+
.content :global(h4):before {
201+
display: block;
202+
content: ' ';
203+
margin-top: -75px;
204+
height: 75px;
205+
visibility: hidden;
206+
pointer-events: none;
207+
}
208+
209+
.content :global(h4) :global(code) {
210+
font-weight: 700;
211+
}
212+
213+
.content :global(h4) :global(em) {
214+
font-weight: 400;
215+
font-style: normal;
216+
font-size: 14px;
217+
color: #666;
218+
position: relative;
219+
top: -0.1em;
220+
}
221+
222+
.content :global(p),
223+
.content :global(ol) {
224+
margin: 0 0 1em 0;
225+
color: #181818;
226+
line-height: 1.5;
227+
z-index: 3;
228+
}
229+
230+
.content :global(a) {
231+
border-bottom: 1px solid #e3d9d9;
232+
}
233+
234+
.content :global(a.anchor) {
235+
border-bottom: 0;
236+
position: absolute;
237+
left: -18px;
238+
padding-right: 2px;
239+
visibility: hidden;
240+
line-height: 28px;
241+
}
242+
243+
.content :global(*:hover) > :global(a.anchor) {
244+
visibility: visible;
245+
}
246+
247+
.content :global(strong) {
248+
font-weight: 500;
249+
}
250+
251+
.content :global(code) {
252+
background-color: #f9f9f9;
253+
border-radius: 3px;
254+
}
255+
256+
section:first-child :global(h3) {
257+
border: none;
258+
}
259+
260+
section {
261+
border-bottom: 1px solid #eee;
262+
max-width: 64em;
263+
margin: 0 auto 2em auto;
264+
padding: 0 0 4em 1em;
265+
}
266+
267+
section:last-child {
268+
border: none;
269+
}
270+
271+
.content :global(pre) {
272+
background-color: #f9f9f9;
273+
border-left: 2px solid #eee;
274+
margin: 0 0 1em 0;
275+
padding: 12px 8px 12px 12px;
276+
border-radius: 3px;
277+
word-break: normal;
278+
}
279+
280+
.content :global(p),
281+
.content :global(ul),
282+
.content :global(ol) {
283+
max-width: 48em;
284+
}
285+
286+
.content :global(li) {
287+
margin: 0;
288+
}
289+
290+
.content :global(blockquote) {
291+
position: relative;
292+
color: #999;
293+
margin: 1em 0;
294+
padding: 0.5em 0 0.5em 2em;
295+
max-width: 48em;
296+
border-top: 1px solid #eee;
297+
border-bottom: 1px solid #eee;
298+
}
299+
300+
.content :global(blockquote) :global(p) {
301+
color: #666;
302+
}
303+
304+
.content :global(blockquote) :global(p):last-child {
305+
margin: 0;
306+
}
307+
308+
.content :global(blockquote)::before {
309+
content: '!';
310+
position: absolute;
311+
left: 0.5em;
312+
top: 0.8em;
313+
color: rgba(170, 0, 0, 0.7);
314+
font-size: 0.8em;
315+
font-weight: 800;
316+
width: 1em;
317+
height: 1em;
318+
text-align: center;
319+
line-height: 1;
320+
padding: 0.15em 0.1em 0.1em 0.1em;
321+
border-radius: 50%;
322+
border: 2px solid rgba(170, 30, 30, 0.7);
323+
}
324+
325+
@media (min-width: 768px) {
326+
.sidebar {
327+
transform: translateX(0);
328+
}
329+
330+
.content {
331+
padding: 0 1em 2em 17.5em;
332+
}
333+
334+
.hero {
335+
display: block;
336+
}
337+
338+
.hero strong {
339+
font-size: 8em;
340+
}
341+
342+
.mousecatcher.visible {
343+
display: none;
344+
}
345+
}
346+
</style>

0 commit comments

Comments
 (0)