From 657e6263edadddea92e7338c5c87f83a855e025d Mon Sep 17 00:00:00 2001 From: Luke Chu <37006668+lukechu10@users.noreply.github.com> Date: Tue, 29 Jun 2021 18:46:30 -0700 Subject: [PATCH 1/6] Get outline from markdown parser --- docs/markdown/basics/reactivity.md | 4 +-- docs/src/content.rs | 39 ++++++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/docs/markdown/basics/reactivity.md b/docs/markdown/basics/reactivity.md index dd6bb8232..d2f221152 100644 --- a/docs/markdown/basics/reactivity.md +++ b/docs/markdown/basics/reactivity.md @@ -43,7 +43,7 @@ How does the `create_effect(...)` function know to execute the closure every tim Calling `create_effect` creates a new _"reactivity scope"_ and calling `state.get()` inside this scope adds itself as a _dependency_. Now, when `state.set(...)` is called, it automatically calls all its _dependents_, in this case, `state` as it was called inside the closure. -> #### What's that `cloned!` macro doing? +> ## What's that `cloned!` macro doing? > > The `cloned!` macro is an utility macro for cloning the variables into the following expression. The previous `create_effect` function call could very well have been written as: > @@ -74,7 +74,7 @@ assert_eq!(*double.get(), 2); Now that you understand `sycamore`'s reactivity system, we can look at how to use this to update the DOM. -### Using reactivity with DOM updates +## Using reactivity with DOM updates Reactivity is automatically built-in into the `template!` macro. Say we have the following code: diff --git a/docs/src/content.rs b/docs/src/content.rs index 17e60540f..43cca4da4 100644 --- a/docs/src/content.rs +++ b/docs/src/content.rs @@ -1,4 +1,4 @@ -use pulldown_cmark::{html, Options, Parser}; +use pulldown_cmark::{html, Event, Options, Parser, Tag}; use sycamore::prelude::*; use wasm_bindgen::prelude::*; use web_sys::HtmlElement; @@ -11,6 +11,12 @@ extern "C" { async fn fetch_md(url: &str) -> JsValue; } +#[derive(Debug)] +struct Outline { + name: String, + children: Vec, +} + #[component(Content)] pub fn content(pathname: String) -> Template { let location = web_sys::window() @@ -26,8 +32,37 @@ pub fn content(pathname: String) -> Template { let html = create_memo(cloned!((markdown) => move || { let markdown = markdown.get(); + let mut outline = Vec::new(); + let mut current = None; + let options = Options::all(); - let parser = Parser::new_ext(markdown.as_ref(), options); + let parser = Parser::new_ext(markdown.as_ref(), options) + .map(|event| { + match event { + Event::Start(Tag::Heading(_level)) => { + current = Some(Outline{ + name:String::new(), + children:Vec::new(), + }); + }, + Event::End(Tag::Heading(level)) => { + if level == 1 {} // Do nothing for level 1 heading + else if level == 2 { + outline.push(current.take().unwrap()); + } else { + let l = outline.last_mut().expect("cannot have non level 2 heading at root"); + l.children.push(current.take().unwrap()); + } + }, + Event::Text(ref text) | Event::Code(ref text) => { + if current.is_some() { + current.as_mut().unwrap().name += text; + } + } + _ => {}, + }; + event + }); let mut output = String::new(); html::push_html(&mut output, parser); From 809004977e1c7f5c488baaf0e0789b7b9c6d20b6 Mon Sep 17 00:00:00 2001 From: Luke Chu <37006668+lukechu10@users.noreply.github.com> Date: Tue, 29 Jun 2021 18:55:57 -0700 Subject: [PATCH 2/6] Extract outline from markdown --- docs/src/content.rs | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/docs/src/content.rs b/docs/src/content.rs index 43cca4da4..1bb54b591 100644 --- a/docs/src/content.rs +++ b/docs/src/content.rs @@ -29,18 +29,18 @@ pub fn content(pathname: String) -> Template { let docs_container_ref = NodeRef::::new(); let markdown = Signal::new(String::new()); - let html = create_memo(cloned!((markdown) => move || { + let content = create_memo(cloned!((markdown) => move || { let markdown = markdown.get(); let mut outline = Vec::new(); - let mut current = None; + let mut tmp = None; let options = Options::all(); let parser = Parser::new_ext(markdown.as_ref(), options) .map(|event| { match event { Event::Start(Tag::Heading(_level)) => { - current = Some(Outline{ + tmp = Some(Outline{ name:String::new(), children:Vec::new(), }); @@ -48,15 +48,15 @@ pub fn content(pathname: String) -> Template { Event::End(Tag::Heading(level)) => { if level == 1 {} // Do nothing for level 1 heading else if level == 2 { - outline.push(current.take().unwrap()); + outline.push(tmp.take().unwrap()); } else { let l = outline.last_mut().expect("cannot have non level 2 heading at root"); - l.children.push(current.take().unwrap()); + l.children.push(tmp.take().unwrap()); } }, Event::Text(ref text) | Event::Code(ref text) => { - if current.is_some() { - current.as_mut().unwrap().name += text; + if tmp.is_some() { + tmp.as_mut().unwrap().name += text; } } _ => {}, @@ -64,15 +64,18 @@ pub fn content(pathname: String) -> Template { event }); - let mut output = String::new(); - html::push_html(&mut output, parser); + let mut html = String::new(); + html::push_html(&mut html, parser); - output + (html, outline) })); - create_effect(cloned!((docs_container_ref) => move || { - if !html.get().is_empty() { - docs_container_ref.get::().unchecked_into::().set_inner_html(html.get().as_ref()); + create_effect(cloned!((content, docs_container_ref) => move || { + if !content.get().0.is_empty() { + docs_container_ref + .get::() + .unchecked_into::() + .set_inner_html(content.get().0.as_ref()); highlight_all(); } })); @@ -93,6 +96,9 @@ pub fn content(pathname: String) -> Template { div(ref=docs_container_ref, class="content flex-1 min-w-0 pr-4 mb-2") { "Loading..." } + div(class="outline flex-none hidden lg:block lg:w-44") { + (format!("{:#?}", content.get().1)) + } } } } From cae006e606bb8b97968bc1c54ee15a1a314c2ad5 Mon Sep 17 00:00:00 2001 From: Luke Chu <37006668+lukechu10@users.noreply.github.com> Date: Tue, 29 Jun 2021 20:04:23 -0700 Subject: [PATCH 3/6] OutlineView --- docs/src/content.rs | 55 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/docs/src/content.rs b/docs/src/content.rs index 1bb54b591..c8a5d1543 100644 --- a/docs/src/content.rs +++ b/docs/src/content.rs @@ -11,12 +11,42 @@ extern "C" { async fn fetch_md(url: &str) -> JsValue; } -#[derive(Debug)] -struct Outline { +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Outline { name: String, children: Vec, } +#[component(OutlineView)] +pub fn outline_view(outline: StateHandle>) -> Template { + template! { + ul { + Indexed(IndexedProps { + iterable: outline, + template: |item| { + let Outline { name, children } = item; + let nested = children.iter().map(|x| { + let name = x.name.clone(); + template! { + li { (name) } + } + }).collect(); + let nested = Template::new_fragment(nested); + + template! { + li { + (name) + ul(class="ml-3") { + (nested) + } + } + } + } + }) + } + } +} + #[component(Content)] pub fn content(pathname: String) -> Template { let location = web_sys::window() @@ -29,10 +59,11 @@ pub fn content(pathname: String) -> Template { let docs_container_ref = NodeRef::::new(); let markdown = Signal::new(String::new()); - let content = create_memo(cloned!((markdown) => move || { + let outline = Signal::new(Vec::new()); + let html = create_memo(cloned!((markdown, outline) => move || { let markdown = markdown.get(); - let mut outline = Vec::new(); + let mut outline_tmp = Vec::new(); let mut tmp = None; let options = Options::all(); @@ -48,9 +79,9 @@ pub fn content(pathname: String) -> Template { Event::End(Tag::Heading(level)) => { if level == 1 {} // Do nothing for level 1 heading else if level == 2 { - outline.push(tmp.take().unwrap()); + outline_tmp.push(tmp.take().unwrap()); } else { - let l = outline.last_mut().expect("cannot have non level 2 heading at root"); + let l = outline_tmp.last_mut().expect("cannot have non level 2 heading at root"); l.children.push(tmp.take().unwrap()); } }, @@ -67,15 +98,17 @@ pub fn content(pathname: String) -> Template { let mut html = String::new(); html::push_html(&mut html, parser); - (html, outline) + outline.set(outline_tmp); + + html })); - create_effect(cloned!((content, docs_container_ref) => move || { - if !content.get().0.is_empty() { + create_effect(cloned!((html, docs_container_ref) => move || { + if !html.get().is_empty() { docs_container_ref .get::() .unchecked_into::() - .set_inner_html(content.get().0.as_ref()); + .set_inner_html(html.get().as_ref()); highlight_all(); } })); @@ -97,7 +130,7 @@ pub fn content(pathname: String) -> Template { "Loading..." } div(class="outline flex-none hidden lg:block lg:w-44") { - (format!("{:#?}", content.get().1)) + OutlineView(outline.handle()) } } } From 471d72338b254443b7de55b46b7755512e8ef518 Mon Sep 17 00:00:00 2001 From: Luke Chu <37006668+lukechu10@users.noreply.github.com> Date: Tue, 29 Jun 2021 21:23:53 -0700 Subject: [PATCH 4/6] Add sidebar --- docs/index.css | 12 + docs/package-lock.json | 357 ------------------------- docs/package.json | 2 - docs/src/content.rs | 64 +++-- docs/src/main.rs | 2 +- packages/sycamore-router/src/router.rs | 31 ++- 6 files changed, 75 insertions(+), 393 deletions(-) diff --git a/docs/index.css b/docs/index.css index 03ee68be7..ee6209ea3 100644 --- a/docs/index.css +++ b/docs/index.css @@ -24,15 +24,23 @@ .content h1 { @apply text-2xl font-bold; + padding-top: 48px; + margin-top: -48px; } .content h2 { @apply text-xl font-bold; + padding-top: 48px; + margin-top: -48px; } .content h3 { @apply text-lg font-bold; + padding-top: 48px; + margin-top: -48px; } .content h4 { @apply text-base font-bold; + padding-top: 48px; + margin-top: -48px; } .content a { @@ -47,3 +55,7 @@ padding-inline-start: 30px; @apply list-disc; } + +.outline a { + @apply text-gray-600 hover:text-yellow-400 mb-1 inline-block transition-colors; +} diff --git a/docs/package-lock.json b/docs/package-lock.json index a7d778dee..610d3a3f3 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -11,8 +11,6 @@ "autoprefixer": "^10.2.6", "concurrently": "^6.2.0", "cross-env": "^7.0.3", - "postcss": "^8.3.1", - "postcss-cli": "^8.3.1", "tailwindcss": "^2.1.4" } }, @@ -247,24 +245,6 @@ "integrity": "sha512-4P8Zm2H+BRS+c/xX1LrHw0qKpEhdlZjLCgWy+d78T9vqa2Z2SiD2wMrYuWIAFy5IZUD7nnNXroRttz+0RzlrzQ==", "dev": true }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/autoprefixer": { "version": "10.2.6", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.2.6.tgz", @@ -631,15 +611,6 @@ "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", "dev": true }, - "node_modules/dependency-graph": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.9.0.tgz", - "integrity": "sha512-9YLIBURXj4DJMFALxXw9K3Y3rwb5Fk0X5/8ipCzaN84+gKxoHK43tVKRNakCQbiEx07E8Uwhuq21BpUagFhZ8w==", - "dev": true, - "engines": { - "node": ">= 0.6.0" - } - }, "node_modules/detective": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", @@ -663,18 +634,6 @@ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", "dev": true }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", @@ -770,21 +729,6 @@ "url": "https://www.patreon.com/infusion" } }, - "node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -820,18 +764,6 @@ "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/get-stdin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", - "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/glob": { "version": "7.1.7", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", @@ -864,26 +796,6 @@ "node": ">= 6" } }, - "node_modules/globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/graceful-fs": { "version": "4.2.6", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", @@ -926,15 +838,6 @@ "node": ">=8" } }, - "node_modules/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, "node_modules/import-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-3.0.0.tgz", @@ -1120,36 +1023,6 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "node_modules/lodash.difference": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=", - "dev": true - }, - "node_modules/lodash.forown": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.forown/-/lodash.forown-4.4.0.tgz", - "integrity": "sha1-hRFc8E9z75ZuztUlEdOJPMRmg68=", - "dev": true - }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", - "dev": true - }, - "node_modules/lodash.groupby": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", - "integrity": "sha1-Cwih3PaDl8OXhVwyOXg4Mt90A9E=", - "dev": true - }, - "node_modules/lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true - }, "node_modules/lodash.toarray": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", @@ -1364,15 +1237,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/postcss": { "version": "8.3.5", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.5.tgz", @@ -1391,35 +1255,6 @@ "url": "https://opencollective.com/postcss/" } }, - "node_modules/postcss-cli": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-8.3.1.tgz", - "integrity": "sha512-leHXsQRq89S3JC9zw/tKyiVV2jAhnfQe0J8VI4eQQbUjwIe0XxVqLrR+7UsahF1s9wi4GlqP6SJ8ydf44cgF2Q==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "chokidar": "^3.3.0", - "dependency-graph": "^0.9.0", - "fs-extra": "^9.0.0", - "get-stdin": "^8.0.0", - "globby": "^11.0.0", - "postcss-load-config": "^3.0.0", - "postcss-reporter": "^7.0.0", - "pretty-hrtime": "^1.0.3", - "read-cache": "^1.0.0", - "slash": "^3.0.0", - "yargs": "^16.0.0" - }, - "bin": { - "postcss": "bin/postcss" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, "node_modules/postcss-js": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-3.0.3.tgz", @@ -1482,30 +1317,6 @@ "postcss": "^8.1.13" } }, - "node_modules/postcss-reporter": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-7.0.2.tgz", - "integrity": "sha512-JyQ96NTQQsso42y6L1H1RqHfWH1C3Jr0pt91mVv5IdYddZAE9DUZxuferNgk6q0o6vBVOrfVJb10X1FgDzjmDw==", - "dev": true, - "dependencies": { - "colorette": "^1.2.1", - "lodash.difference": "^4.5.0", - "lodash.forown": "^4.4.0", - "lodash.get": "^4.4.2", - "lodash.groupby": "^4.6.0", - "lodash.sortby": "^4.7.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, "node_modules/postcss-selector-parser": { "version": "6.0.6", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz", @@ -1581,15 +1392,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=", - "dev": true, - "dependencies": { - "pify": "^2.3.0" - } - }, "node_modules/read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -1769,15 +1571,6 @@ "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", "dev": true }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/source-map-js": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz", @@ -2288,18 +2081,6 @@ "integrity": "sha512-4P8Zm2H+BRS+c/xX1LrHw0qKpEhdlZjLCgWy+d78T9vqa2Z2SiD2wMrYuWIAFy5IZUD7nnNXroRttz+0RzlrzQ==", "dev": true }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true - }, "autoprefixer": { "version": "10.2.6", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.2.6.tgz", @@ -2574,12 +2355,6 @@ "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", "dev": true }, - "dependency-graph": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.9.0.tgz", - "integrity": "sha512-9YLIBURXj4DJMFALxXw9K3Y3rwb5Fk0X5/8ipCzaN84+gKxoHK43tVKRNakCQbiEx07E8Uwhuq21BpUagFhZ8w==", - "dev": true - }, "detective": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", @@ -2597,15 +2372,6 @@ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", "dev": true }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, "dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", @@ -2682,18 +2448,6 @@ "integrity": "sha512-MHOhvvxHTfRFpF1geTK9czMIZ6xclsEor2wkIGYYq+PxcQqT7vStJqjhe6S1TenZrMZzo+wlqOufBDVepUEgPg==", "dev": true }, - "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2719,12 +2473,6 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, - "get-stdin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", - "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", - "dev": true - }, "glob": { "version": "7.1.7", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", @@ -2748,20 +2496,6 @@ "is-glob": "^4.0.1" } }, - "globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - } - }, "graceful-fs": { "version": "4.2.6", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", @@ -2795,12 +2529,6 @@ "integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==", "dev": true }, - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true - }, "import-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-3.0.0.tgz", @@ -2950,36 +2678,6 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "lodash.difference": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=", - "dev": true - }, - "lodash.forown": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.forown/-/lodash.forown-4.4.0.tgz", - "integrity": "sha1-hRFc8E9z75ZuztUlEdOJPMRmg68=", - "dev": true - }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", - "dev": true - }, - "lodash.groupby": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", - "integrity": "sha1-Cwih3PaDl8OXhVwyOXg4Mt90A9E=", - "dev": true - }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true - }, "lodash.toarray": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", @@ -3140,12 +2838,6 @@ "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", "dev": true }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, "postcss": { "version": "8.3.5", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.5.tgz", @@ -3157,26 +2849,6 @@ "source-map-js": "^0.6.2" } }, - "postcss-cli": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-8.3.1.tgz", - "integrity": "sha512-leHXsQRq89S3JC9zw/tKyiVV2jAhnfQe0J8VI4eQQbUjwIe0XxVqLrR+7UsahF1s9wi4GlqP6SJ8ydf44cgF2Q==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "chokidar": "^3.3.0", - "dependency-graph": "^0.9.0", - "fs-extra": "^9.0.0", - "get-stdin": "^8.0.0", - "globby": "^11.0.0", - "postcss-load-config": "^3.0.0", - "postcss-reporter": "^7.0.0", - "pretty-hrtime": "^1.0.3", - "read-cache": "^1.0.0", - "slash": "^3.0.0", - "yargs": "^16.0.0" - } - }, "postcss-js": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-3.0.3.tgz", @@ -3207,20 +2879,6 @@ "postcss-selector-parser": "^6.0.4" } }, - "postcss-reporter": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-7.0.2.tgz", - "integrity": "sha512-JyQ96NTQQsso42y6L1H1RqHfWH1C3Jr0pt91mVv5IdYddZAE9DUZxuferNgk6q0o6vBVOrfVJb10X1FgDzjmDw==", - "dev": true, - "requires": { - "colorette": "^1.2.1", - "lodash.difference": "^4.5.0", - "lodash.forown": "^4.4.0", - "lodash.get": "^4.4.2", - "lodash.groupby": "^4.6.0", - "lodash.sortby": "^4.7.0" - } - }, "postcss-selector-parser": { "version": "6.0.6", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz", @@ -3267,15 +2925,6 @@ "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", "dev": true }, - "read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=", - "dev": true, - "requires": { - "pify": "^2.3.0" - } - }, "read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -3408,12 +3057,6 @@ } } }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, "source-map-js": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz", diff --git a/docs/package.json b/docs/package.json index 0cfd6b463..fc38156dd 100644 --- a/docs/package.json +++ b/docs/package.json @@ -10,8 +10,6 @@ "autoprefixer": "^10.2.6", "concurrently": "^6.2.0", "cross-env": "^7.0.3", - "postcss": "^8.3.1", - "postcss-cli": "^8.3.1", "tailwindcss": "^2.1.4" }, "private": true diff --git a/docs/src/content.rs b/docs/src/content.rs index c8a5d1543..d05472b2d 100644 --- a/docs/src/content.rs +++ b/docs/src/content.rs @@ -1,4 +1,4 @@ -use pulldown_cmark::{html, Event, Options, Parser, Tag}; +use pulldown_cmark::{html, CowStr, Event, Options, Parser, Tag}; use sycamore::prelude::*; use wasm_bindgen::prelude::*; use web_sys::HtmlElement; @@ -20,22 +20,31 @@ pub struct Outline { #[component(OutlineView)] pub fn outline_view(outline: StateHandle>) -> Template { template! { - ul { + ul(class="mt-4 text-sm pl-2 border-l border-gray-400") { Indexed(IndexedProps { iterable: outline, template: |item| { let Outline { name, children } = item; let nested = children.iter().map(|x| { let name = x.name.clone(); + let href = format!("#{}", x.name.trim().to_lowercase().replace(" ", "-")); template! { - li { (name) } + li { + a(href=href) { + (name) + } + } } }).collect(); let nested = Template::new_fragment(nested); + let href = format!("#{}", name.trim().to_lowercase().replace(" ", "-")); + template! { li { - (name) + a(href=href) { + (name) + } ul(class="ml-3") { (nested) } @@ -68,31 +77,46 @@ pub fn content(pathname: String) -> Template { let options = Options::all(); let parser = Parser::new_ext(markdown.as_ref(), options) - .map(|event| { + .filter_map(|event| { match event { - Event::Start(Tag::Heading(_level)) => { - tmp = Some(Outline{ - name:String::new(), - children:Vec::new(), - }); + Event::Start(Tag::Heading(level)) => { + if level == 1 { + Some(event) + } else { + tmp = Some(Outline{ + name: String::new(), + children: Vec::new(), + }); + None + } }, Event::End(Tag::Heading(level)) => { - if level == 1 {} // Do nothing for level 1 heading - else if level == 2 { - outline_tmp.push(tmp.take().unwrap()); + if level == 1 { + Some(event) } else { - let l = outline_tmp.last_mut().expect("cannot have non level 2 heading at root"); - l.children.push(tmp.take().unwrap()); + let tmp = tmp.take().unwrap(); + let anchor = tmp.name.trim().to_lowercase().replace(" ", "-"); + let name = tmp.name.clone(); + if level == 2 { + outline_tmp.push(tmp); + } else { + let l = outline_tmp.last_mut().expect("cannot have non level 2 heading at root"); + l.children.push(tmp); + } + Some(Event::Html(CowStr::from(format!("{}", level, anchor, name, level)))) } }, Event::Text(ref text) | Event::Code(ref text) => { if tmp.is_some() { tmp.as_mut().unwrap().name += text; + // Some(event) + None + } else { + Some(event) } } - _ => {}, - }; - event + _ => Some(event), + } }); let mut html = String::new(); @@ -126,10 +150,10 @@ pub fn content(pathname: String) -> Template { div(class="flex-none") { crate::sidebar::Sidebar() } - div(ref=docs_container_ref, class="content flex-1 min-w-0 pr-4 mb-2") { + div(ref=docs_container_ref, class="content flex-1 min-w-0 pr-4 mb-2 mr-44") { "Loading..." } - div(class="outline flex-none hidden lg:block lg:w-44") { + div(class="outline flex-none hidden lg:block lg:w-44 fixed right-0") { OutlineView(outline.handle()) } } diff --git a/docs/src/main.rs b/docs/src/main.rs index dff87f093..55d2bb389 100644 --- a/docs/src/main.rs +++ b/docs/src/main.rs @@ -6,7 +6,7 @@ mod sidebar; use sycamore::prelude::*; use sycamore_router::{BrowserRouter, Route}; -#[derive(Route)] +#[derive(Debug, Route)] enum Routes { #[to("/")] Index, diff --git a/packages/sycamore-router/src/router.rs b/packages/sycamore-router/src/router.rs index 790b0d00e..1e914a8a1 100644 --- a/packages/sycamore-router/src/router.rs +++ b/packages/sycamore-router/src/router.rs @@ -39,7 +39,7 @@ pub fn browser_router(render: impl Fn(R) -> Template + 'static) -> }); let pathname = PATHNAME.with(|p| p.borrow().clone().unwrap()); - // Listen to onpopstate. + // Listen to popstate event. let closure = Closure::wrap(Box::new(cloned!((pathname) => move || { pathname.set(web_sys::window().unwrap().location().pathname().unwrap()); })) as Box); @@ -49,7 +49,7 @@ pub fn browser_router(render: impl Fn(R) -> Template + 'static) -> .unwrap(); closure.forget(); - let path = create_memo(move || { + let path = create_selector(move || { pathname .get() .split('/') @@ -83,25 +83,30 @@ pub fn browser_router(render: impl Fn(R) -> Template + 'static) -> let a = a.unchecked_into::(); let origin = a.origin(); - let href = a.href(); let path = a.pathname(); - if origin == location.origin().unwrap() { - ev.prevent_default(); - if href != location.href().unwrap() { + let hash = a.hash(); + if Ok(origin) == location.origin() { + if Ok(&path) != location.pathname().as_ref() { + // Same origin, different path. + ev.prevent_default(); PATHNAME.with(|pathname| { let pathname = pathname.borrow().clone().unwrap(); pathname.set(path.to_string()); - + // Update History API. let history = web_sys::window().unwrap().history().unwrap(); history - .push_state_with_url( - &JsValue::UNDEFINED, - "", - Some(pathname.get().as_str()), - ) - .unwrap(); + .push_state_with_url( + &JsValue::UNDEFINED, + "", + Some(pathname.get().as_str()), + ) + .unwrap(); }); + } else if Ok(&hash) != location.hash().as_ref() { + // Same origin, same path, different anchor. + // Use default browser behavior. + return; } } } From dc39c6edbf5da612920a9f6e94ecd98ed189087e Mon Sep 17 00:00:00 2001 From: Luke Chu <37006668+lukechu10@users.noreply.github.com> Date: Tue, 29 Jun 2021 22:03:03 -0700 Subject: [PATCH 5/6] Update docs website --- docs/src/content.rs | 2 +- docs/src/header.rs | 15 +++++++----- docs/src/index.rs | 34 ++++++++++++++++++++++++-- docs/tailwind.config.js | 12 +++++++++ packages/sycamore-router/src/router.rs | 4 ++- 5 files changed, 57 insertions(+), 10 deletions(-) diff --git a/docs/src/content.rs b/docs/src/content.rs index d05472b2d..41ec1c259 100644 --- a/docs/src/content.rs +++ b/docs/src/content.rs @@ -150,7 +150,7 @@ pub fn content(pathname: String) -> Template { div(class="flex-none") { crate::sidebar::Sidebar() } - div(ref=docs_container_ref, class="content flex-1 min-w-0 pr-4 mb-2 mr-44") { + div(ref=docs_container_ref, class="content flex-1 min-w-0 pr-4 mb-2 lg:mr-44") { "Loading..." } div(class="outline flex-none hidden lg:block lg:w-44 fixed right-0") { diff --git a/docs/src/header.rs b/docs/src/header.rs index 424847c8f..d84fa25bd 100644 --- a/docs/src/header.rs +++ b/docs/src/header.rs @@ -9,26 +9,29 @@ fn nav() -> Template { div(class="flex flex-row justify-between items-center h-12") { // Brand section div(class="flex-initial") { - div(class="flex space-x-4 text-white") { - a(href="/#", class="py-2 px-3 text-sm font-medium \ + div(class="flex space-x-4") { + a(href="/#", class="py-2 px-3 text-sm text-white font-medium \ bg-gray-500 hover:bg-gray-600 transition-colors rounded") { "Sycamore" } + span(class="text-gray-600 self-center") { + "v0.5.0-beta.1" + } } } // Links section - div(class="flex flex-row ml-2 space-x-4 text-white") { - a(class="py-2 px-3 text-sm text-gray-600 hover:text-gray-800 hover:underline transition", + div(class="flex flex-row ml-2 space-x-4 text-gray-600") { + a(class="py-2 px-3 text-sm hover:text-gray-800 hover:underline transition", href="/getting_started/installation", ) { "Book" } - a(class="py-2 px-3 text-sm text-gray-600 hover:text-gray-800 hover:underline transition", + a(class="py-2 px-3 text-sm hover:text-gray-800 hover:underline transition", href="https://docs.rs/sycamore", ) { "API" } - a(class="py-2 px-3 text-sm text-gray-600 hover:text-gray-800 hover:underline transition", + a(class="py-2 px-3 text-sm hover:text-gray-800 hover:underline transition", href="https://github.com/sycamore-rs/sycamore", ) { "Repository" diff --git a/docs/src/index.rs b/docs/src/index.rs index 38f71557d..71a00ea7e 100644 --- a/docs/src/index.rs +++ b/docs/src/index.rs @@ -3,13 +3,13 @@ use sycamore::prelude::*; #[component(Index)] pub fn index() -> Template { template! { - div(class="flex flex-col items-center w-full") { + div(class="flex flex-col items-center w-full mb-10") { h1(class="text-5xl font-bold mt-20 mb-5") { "Sycamore" } p(class="mb-10") { - "Pure Rust + WASM web-apps" + "Fast isomorphic web apps in Rust + WASM" } a( href="/getting_started/installation", @@ -19,5 +19,35 @@ pub fn index() -> Template { "Read the Book" } } + div(class="text-white flex flex-col w-full md:flex-row space-y-4 md:space-y-0 md:space-x-4") { + div(class="bg-red-500 md:flex-1 rounded-md p-6") { + h1(class="text-lg text-center font-semibold mb-3") { "Lightning speed" } + p { + "Sycamore harnesses the full power of " + a(href="https://www.rust-lang.org/", class="underline", target="_blank") { "Rust" } + " via " + a(href="https://webassembly.org/", class="underline", target="_blank") { "WebAssembly" } + ", giving you full \ + control over performance." + } + } + div(class="bg-amber-600 md:flex-1 rounded-md p-6") { + h1(class="text-lg text-center font-semibold mb-3") { "Ergonomic and intuitive" } + p { + "Write code that feels natural. Everything is built on " + a(href="/basics/reactivity", class="underline") { "reactive primitives" } + " without a cumbersome virtual DOM." + } + } + div(class="bg-yellow-600 md:flex-1 rounded-md p-6") { + h1(class="text-lg text-center font-semibold mb-3") { "No JavaScript" } + p(class="mb-2") { + "Had enough of JavaScript? So do we." + } + p { + "Create apps using Sycamore without touching a single line of JS." + } + } + } } } diff --git a/docs/tailwind.config.js b/docs/tailwind.config.js index 57b35bdcc..cc3435bfb 100644 --- a/docs/tailwind.config.js +++ b/docs/tailwind.config.js @@ -1,3 +1,5 @@ +const colors = require('tailwindcss/colors') + module.exports = { jit: true, purge: [ @@ -6,6 +8,16 @@ module.exports = { darkMode: false, // or 'media' or 'class' theme: { extend: {}, + colors: { + transparent: 'transparent', + current: 'currentColor', + red: colors.red, + gray: colors.gray, + orange: colors.orange, + amber: colors.amber, + yellow: colors.yellow, + white: colors.white, + } }, variants: { extend: {}, diff --git a/packages/sycamore-router/src/router.rs b/packages/sycamore-router/src/router.rs index 1e914a8a1..09d148b82 100644 --- a/packages/sycamore-router/src/router.rs +++ b/packages/sycamore-router/src/router.rs @@ -106,7 +106,9 @@ pub fn browser_router(render: impl Fn(R) -> Template + 'static) -> } else if Ok(&hash) != location.hash().as_ref() { // Same origin, same path, different anchor. // Use default browser behavior. - return; + } else { + // Same page. Do nothing. + ev.prevent_default(); } } } From 7fbf253d0f229ea58302ba74ccf329822bf89eae Mon Sep 17 00:00:00 2001 From: Luke Chu <37006668+lukechu10@users.noreply.github.com> Date: Tue, 29 Jun 2021 22:09:56 -0700 Subject: [PATCH 6/6] Add discord link to header --- docs/src/header.rs | 11 ++++++++++- docs/src/index.rs | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/docs/src/header.rs b/docs/src/header.rs index d84fa25bd..7f39925fc 100644 --- a/docs/src/header.rs +++ b/docs/src/header.rs @@ -14,7 +14,11 @@ fn nav() -> Template { bg-gray-500 hover:bg-gray-600 transition-colors rounded") { "Sycamore" } - span(class="text-gray-600 self-center") { + a( + href="https://crates.io/crates/sycamore", + class="text-gray-600 self-center", + target="_blank", + ) { "v0.5.0-beta.1" } } @@ -36,6 +40,11 @@ fn nav() -> Template { ) { "Repository" } + a(class="py-2 px-3 text-sm hover:text-gray-800 hover:underline transition", + href="https://discord.gg/vDwFUmm6mU", + ) { + "Discord" + } } } } diff --git a/docs/src/index.rs b/docs/src/index.rs index 71a00ea7e..594f22b40 100644 --- a/docs/src/index.rs +++ b/docs/src/index.rs @@ -19,7 +19,7 @@ pub fn index() -> Template { "Read the Book" } } - div(class="text-white flex flex-col w-full md:flex-row space-y-4 md:space-y-0 md:space-x-4") { + div(class="text-white flex flex-col w-full md:flex-row space-y-4 md:space-y-0 md:space-x-4 mb-10") { div(class="bg-red-500 md:flex-1 rounded-md p-6") { h1(class="text-lg text-center font-semibold mb-3") { "Lightning speed" } p {