Compare commits

..

7 commits

Author SHA1 Message Date
zyl
855d29d9c4
update install command on site
Some checks are pending
Build Site / build (push) Waiting to run
Build Site / deploy (push) Blocked by required conditions
2025-01-15 01:50:04 -08:00
zyl
8685e51d0d
fix license 2025-01-15 01:46:56 -08:00
zyl
3d20c3721c
prepare webdog for first release 2025-01-15 01:38:53 -08:00
zyl
727e68c817
add default tab size to code blocks 2025-01-15 01:20:54 -08:00
zyl
c27ac9c6d9
fix code blocks not rendering in resources 2025-01-15 01:20:12 -08:00
zyl
e44b219335
fix default styles making code scrollbars always visible on chrome 2025-01-14 23:12:57 -08:00
zyl
cb0c4e7391
remove zyl.gay blog-image helper 2025-01-14 23:05:01 -08:00
8 changed files with 109 additions and 99 deletions

View file

@ -1,6 +1,11 @@
[package]
description = "static site generator fit for a dog"
edition = "2021"
homepage = "https://webdog.zyl.gay"
license = "AGPL-3.0-or-later"
name = "webdog"
readme = "README.md"
repository = "https://github.com/zyllian/webdog"
version = "0.1.0"
[dependencies]

View file

@ -1,3 +1,21 @@
# webdog
Source for webdog, the static site generator fit for a dog. See our website at https://webdog.zyl.gay for more details.
webdog, the static site generator fit for a dog :3
```sh
cargo install webdog
```
after installing, you can create your first site:
```sh
webdog create https://example.com "My First Site!" --site my-site
cd my-site
webdog serve # your site is now running at http://127.0.0.1:8080 🥳
```
from there, you can start editing your site and adding pages or [more advanced things](https://webdog.zyl.gay/docs/)
```sh
webdog page new my-first-page "My First Page"
```

View file

@ -5,7 +5,7 @@ welcome to webdog, the static site generator fit for a dog :3
if you have [rust](https://rust-lang.org) installed, all you need to do to install webdog is run the following command:
```sh
cargo install webdog --git https://github.com/zyllian/webdog
cargo install webdog
```
then you can make your first webdog site!

View file

@ -183,6 +183,7 @@ abbr {
.wd-codeblock {
position: relative;
tab-size: 2;
.copy {
display: none;
@ -206,6 +207,6 @@ abbr {
& > pre {
padding: 8px;
overflow: scroll;
overflow: auto;
}
}

View file

@ -4,7 +4,6 @@ use std::{collections::HashMap, path::PathBuf};
use eyre::{eyre, Context, OptionExt};
use lol_html::{element, html_content::ContentType, HtmlRewriter, Settings};
use pulldown_cmark::{Options, Parser};
use rayon::prelude::*;
use serde::Serialize;
use syntect::{highlighting::ThemeSet, parsing::SyntaxSet};
@ -261,10 +260,28 @@ impl SiteBuilder {
Ok(())
}),
element!("img", |el| {
if let Some(mut src) = el.get_attribute("src") {
if let Some((command, new_src)) = src.split_once('$') {
let mut new_src = new_src.to_string();
#[allow(clippy::single_match)]
match command {
"cdn" => {
new_src = self.site.config.cdn_url(&new_src)?.to_string();
}
_ => new_src = src,
}
src = new_src;
el.set_attribute("src", &src)?;
}
}
Ok(())
}),
element!("a", |el| {
if let Some(mut href) = el.get_attribute("href") {
if let Some((command, mut new_href)) = href.split_once('$') {
#[allow(clippy::single_match)]
if let Some((command, new_href)) = href.split_once('$') {
let mut new_href = new_href.to_string();
match command {
"me" => {
el.set_attribute(
@ -273,11 +290,14 @@ impl SiteBuilder {
+ " me"),
)?;
}
"cdn" => {
new_href = self.site.config.cdn_url(&new_href)?.to_string();
}
_ => {
new_href = &href;
new_href = href;
}
}
href = new_href.to_string();
href = new_href;
el.set_attribute("href", &href)?;
}
if let Ok(url) = Url::parse(&href) {
@ -294,47 +314,6 @@ impl SiteBuilder {
}
}
Ok(())
}),
element!("md", |el| {
el.remove();
let class = el.get_attribute("class");
let md_type = el
.get_attribute("type")
.ok_or_eyre("missing type attribute on markdown tag")?;
if md_type == "blog-image" {
let mut src = el
.get_attribute("src")
.ok_or_eyre("missing src attribute")?;
if src.starts_with("cdn$") {
src = self.site.config.cdn_url(&src[4..])?.to_string();
}
let class = format!("image {}", class.unwrap_or_default());
let content = el
.get_attribute("content")
.ok_or_eyre("missing content attribute")?;
el.replace(
&format!(
r#"
<div class="{class}">
<a href="{src}">
<img src="{src}">
</a>
<span>{content}</span>
</div>
"#
),
ContentType::Html,
);
} else {
return Err(eyre!("unknown markdown tag type: {md_type}").into());
}
Ok(())
}),
],
@ -419,49 +398,7 @@ impl SiteBuilder {
.with_context(|| format!("Failed to read page at {}", page_path.display()))?;
let page = crate::frontmatter::FrontMatter::parse(input)?;
let mut language = None;
let parser = Parser::new_ext(&page.content, Options::all()).filter_map(|event| {
// syntax highlighting for code blocks
match event {
pulldown_cmark::Event::Start(pulldown_cmark::Tag::CodeBlock(
pulldown_cmark::CodeBlockKind::Fenced(name),
)) => {
language = Some(name);
None
}
pulldown_cmark::Event::Text(code) => {
if let Some(language) = language.take() {
let syntax_reference = self
.syntax_set
.find_syntax_by_token(&language)
.unwrap_or_else(|| self.syntax_set.find_syntax_plain_text());
let html = format!(
r#"<div class="wd-codeblock">
<button class="copy">Copy</button>
{}
</div>"#,
syntect::html::highlighted_html_for_string(
&code,
&self.syntax_set,
syntax_reference,
self.theme_set
.themes
.get(&self.site.config.code_theme)
.as_ref()
.expect("should never fail"),
)
.expect("failed to highlight syntax")
);
Some(pulldown_cmark::Event::Html(html.into()))
} else {
Some(pulldown_cmark::Event::Text(code))
}
}
_ => Some(event),
}
});
let mut page_html = String::new();
pulldown_cmark::html::push_html(&mut page_html, parser);
let page_html = util::render_markdown(self, &page.content)?;
let out = self.build_page_raw(page.data.unwrap_or_default(), &page_html, ())?;

View file

@ -5,6 +5,7 @@
.wd-codeblock {
position: relative;
tab-size: 2;
.copy {
display: none;
@ -28,6 +29,6 @@
& > pre {
padding: 8px;
overflow: scroll;
overflow: auto;
}
}

View file

@ -5,14 +5,13 @@ use std::{
use eyre::Context;
use itertools::Itertools;
use pulldown_cmark::{Options, Parser};
use rss::{validation::Validate, ChannelBuilder, ItemBuilder};
use serde::{Deserialize, Serialize};
use time::{format_description::well_known::Rfc2822, OffsetDateTime};
use crate::{
builder::SiteBuilder, frontmatter::FrontMatterRequired, link_list::Link,
util::format_timestamp, PageMetadata,
util::{self, format_timestamp}, PageMetadata,
};
/// Metadata for resources.
@ -182,10 +181,7 @@ impl ResourceBuilder {
let mut page = FrontMatterRequired::<ResourceMetadata>::parse(input)
.wrap_err_with(|| eyre::eyre!("Failed to parse resource front matter"))?;
let parser = Parser::new_ext(&page.content, Options::all());
let mut html = String::new();
pulldown_cmark::html::push_html(&mut html, parser);
*page.content_mut() = html;
*page.content_mut() = util::render_markdown(builder, &page.content)?;
let data = page.data_mut();
if let Some(cdn_file) = &data.cdn_file {

View file

@ -2,8 +2,11 @@
use std::path::Path;
use pulldown_cmark::{Options, Parser};
use time::OffsetDateTime;
use crate::builder::SiteBuilder;
/// Simple helper to remove the contents of a directory without removing the directory itself.
pub fn remove_dir_contents(path: &Path) -> eyre::Result<()> {
for entry in path.read_dir()? {
@ -24,3 +27,52 @@ pub fn format_timestamp(ts: OffsetDateTime, format: &str) -> eyre::Result<String
let fmt = time::format_description::parse_borrowed::<2>(format)?;
Ok(ts.format(&fmt)?)
}
/// Helper to render markdown.
pub fn render_markdown(builder: &SiteBuilder, input: &str) -> eyre::Result<String> {
let mut language = None;
let parser = Parser::new_ext(input, Options::all()).filter_map(|event| {
// syntax highlighting for code blocks
match event {
pulldown_cmark::Event::Start(pulldown_cmark::Tag::CodeBlock(
pulldown_cmark::CodeBlockKind::Fenced(name),
)) => {
language = Some(name);
None
}
pulldown_cmark::Event::Text(code) => {
if let Some(language) = language.take() {
let syntax_reference = builder
.syntax_set
.find_syntax_by_token(&language)
.unwrap_or_else(|| builder.syntax_set.find_syntax_plain_text());
let html = format!(
r#"<div class="wd-codeblock">
<button class="copy">Copy</button>
{}
</div>"#,
syntect::html::highlighted_html_for_string(
&code,
&builder.syntax_set,
syntax_reference,
builder.theme_set
.themes
.get(&builder.site.config.code_theme)
.as_ref()
.expect("should never fail"),
)
.expect("failed to highlight syntax")
);
Some(pulldown_cmark::Event::Html(html.into()))
} else {
Some(pulldown_cmark::Event::Text(code))
}
}
_ => Some(event),
}
});
let mut page_html = String::new();
pulldown_cmark::html::push_html(&mut page_html, parser);
Ok(page_html)
}