Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
289 changes: 289 additions & 0 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ members = [
"packages/search/search",
"packages/search/search-macro",
"packages/search/search-shared",
"packages/docsrs-search",

# Utilities
"packages/notion-to-blog",
Expand Down
2 changes: 2 additions & 0 deletions packages/docsite/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ automod = "1.0.13"
stork-lib = { workspace = true, features = [
"build-v3",
], default-features = false }
docsrs-search = { version = "0.1.0", path = "../docsrs-search", optional = true }

[features]
default = []
Expand All @@ -79,6 +80,7 @@ server = [
"dioxus/ssr",
"dioxus-docs-examples/server",
"dep:askama_escape",
"dep:docsrs-search"
]
production = [
"dioxus-docs-examples/production",
Expand Down
2 changes: 2 additions & 0 deletions packages/docsite/src/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ pub mod notfound;
pub use notfound::*;
// pub mod playground;
// pub use playground::*;
#[cfg(feature = "server")]
pub mod search;
#[cfg(feature = "server")]
pub use search::*;
pub mod component_demo;
pub use component_demo::*;
Expand Down
124 changes: 79 additions & 45 deletions packages/docsite/src/components/nav.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,32 @@ fn LinkList() -> Element {
}
}

type Results = Result<Vec<dioxus_search::SearchResult<Route>>, stork_lib::SearchError>;
struct MergedSearchIndex {
docsrs: dioxus_search::SearchIndex<String>,
dioxus: dioxus_search::SearchIndex<Route>,
}

impl MergedSearchIndex {
fn search(
&self,
query: &str,
) -> Result<Vec<dioxus_search::SearchResult<String>>, stork_lib::SearchError> {
let docsrs_results = self.docsrs.search(query)?;
let dioxus_results = self.dioxus.search(query)?;

// Take the first 5 results from dioxus and then append up to 5 results from docsrs
let merged_results = dioxus_results
.into_iter()
.take(5)
.map(|result| result.map(|route| route.to_string()))
.chain(docsrs_results.into_iter().take(5))
.collect();

Ok(merged_results)
}
}

type SearchItems = Result<Vec<dioxus_search::SearchResult<String>>, stork_lib::SearchError>;

fn SearchModal() -> Element {
let mut search_text = use_signal(String::new);
Expand All @@ -198,28 +223,35 @@ fn SearchModal() -> Element {
_ => "0_7",
};

let url = format!("{url_base}/index_searchable_{docs_index_version}.bin");
let docsrs_url = format!("{url_base}/index_docsrs_{docs_index_version}.bin");
let data = reqwest::get(docsrs_url).await.ok()?.bytes().await.ok()?;

let data = reqwest::get(url).await.ok()?.bytes().await.ok()?;
let (bytes, _) =
dioxus_search::yazi::decompress(&data, dioxus_search::yazi::Format::Zlib).ok()?;

let docsrs: dioxus_search::SearchIndex<String> =
dioxus_search::SearchIndex::from_bytes(format!("docsrs_{docs_index_version}"), bytes);

let dioxus_url = format!("{url_base}/index_searchable_{docs_index_version}.bin");

let data = reqwest::get(dioxus_url).await.ok()?.bytes().await.ok()?;

let (bytes, _) =
dioxus_search::yazi::decompress(&data, dioxus_search::yazi::Format::Zlib).ok()?;

let index: dioxus_search::SearchIndex<Route> =
let dioxus: dioxus_search::SearchIndex<Route> =
dioxus_search::SearchIndex::from_bytes("search", bytes);

Some(index)
Some(MergedSearchIndex { docsrs, dioxus })
});

let search = move || {
let query = &search_text.read();
let mut results = search_index
search_index
.value()
.as_ref()
.and_then(|search| search.as_ref().map(|s| s.search(query)))
.unwrap_or_else(|| Ok(vec![]));

results
.unwrap_or_else(|| Ok(vec![]))
};

let mut results = use_signal(search);
Expand Down Expand Up @@ -301,7 +333,7 @@ fn SearchModal() -> Element {
}

#[component]
fn SearchResults(results: Signal<Results>, search_text: Signal<String>) -> Element {
fn SearchResults(results: Signal<SearchItems>, search_text: Signal<String>) -> Element {
if let Err(err) = results.read().as_ref() {
return rsx! {
div { class: "text-red-500", "{err}" }
Expand All @@ -310,59 +342,53 @@ fn SearchResults(results: Signal<Results>, search_text: Signal<String>) -> Eleme

let _results = results.read();
let results = _results.deref().as_ref().unwrap();
let cur_route = use_route::<Route>();
let results = results
.iter()
.filter(|route| match route.route {
Route::Docs03 { .. } => matches!(cur_route, Route::Docs03 { .. }),
Route::Docs04 { .. } => matches!(cur_route, Route::Docs04 { .. }),
Route::Docs05 { .. } => matches!(cur_route, Route::Docs05 { .. }),
Route::Docs06 { .. } => matches!(cur_route, Route::Docs06 { .. }),
_ => {
!matches!(cur_route, Route::Docs03 { .. })
&& !matches!(cur_route, Route::Docs04 { .. })
&& !matches!(cur_route, Route::Docs05 { .. })
&& !matches!(cur_route, Route::Docs06 { .. })
}
})
.collect::<Vec<_>>();

use crate::docs::router_06::BookRoute;
// let cur_route = use_route::<Route>();
// let results = results
// .iter()
// .filter(|route| match route.route {
// Route::Docs03 { .. } => matches!(cur_route, Route::Docs03 { .. }),
// Route::Docs04 { .. } => matches!(cur_route, Route::Docs04 { .. }),
// Route::Docs05 { .. } => matches!(cur_route, Route::Docs05 { .. }),
// Route::Docs06 { .. } => matches!(cur_route, Route::Docs06 { .. }),
// _ => {
// !matches!(cur_route, Route::Docs03 { .. })
// && !matches!(cur_route, Route::Docs04 { .. })
// && !matches!(cur_route, Route::Docs05 { .. })
// && !matches!(cur_route, Route::Docs06 { .. })
// }
// })
// .collect::<Vec<_>>();

use crate::docs::router_07::BookRoute;

let default_searches = [
(
"Tutorial",
BookRoute::GuideIndex {
BookRoute::Index {
section: Default::default(),
},
),
(
"Web",
BookRoute::GuidesWebIndex {
BookRoute::GuidesPlatformsWeb {
section: Default::default(),
},
),
(
"Desktop",
BookRoute::GuidesDesktopIndex {
section: Default::default(),
},
),
(
"Mobile",
BookRoute::GuidesMobileIndex {
"Fullstack",
BookRoute::EssentialsFullstackIndex {
section: Default::default(),
},
),
(
"Fullstack",
BookRoute::GuidesFullstackIndex {
"Desktop",
BookRoute::GuidesPlatformsDesktop {
section: Default::default(),
},
),
(
"Typesafe Routing",
BookRoute::RouterReferenceIndex {
"Mobile",
BookRoute::GuidesPlatformsMobile {
section: Default::default(),
},
),
Expand All @@ -385,7 +411,7 @@ fn SearchResults(results: Signal<Results>, search_text: Signal<String>) -> Eleme
title: result.title.clone(),
route: result.route.clone(),
span { class: "mt-1",
for segment in result.excerpts.first().unwrap().text.iter() {
for segment in result.excerpts.iter().take(1).flat_map(|excerpt| excerpt.text.iter()) {
if segment.highlighted {
span { class: "text-blue-500", "{segment.text}" }
} else {
Expand All @@ -401,7 +427,8 @@ fn SearchResults(results: Signal<Results>, search_text: Signal<String>) -> Eleme
}

#[component]
fn SearchResultItem(title: String, route: Route, children: Element) -> Element {
fn SearchResultItem(title: String, route: String, children: Element) -> Element {
let docs_rs_route = route.starts_with("https://docs.rs/");
rsx! {
li { class: "w-full rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors duration-200 ease-in-out",
Link {
Expand All @@ -412,8 +439,15 @@ fn SearchResultItem(title: String, route: Route, children: Element) -> Element {
class: "flex flex-row items-center gap-x-2 p-2",
div { class: "flex flex-col mt-1 mb-1",
span { class: "flex flex-row items-center gap-x-1",
icons::DocumentIcon {}
if docs_rs_route {
icons::CratesIOIcon {}
} else {
icons::DocumentIcon {}
}
h2 { class: "dark:text-white ml-1", "{title}" }
if docs_rs_route {
icons::ExternalLinkIcon2 {}
}
}
{children}
}
Expand Down
51 changes: 26 additions & 25 deletions packages/docsite/src/components/search.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
pub fn generate_search_index() {
#[cfg(not(target_arch = "wasm32"))]
{
use crate::{static_dir, Route};
use crate::{static_dir, Route};

std::env::set_var("CARGO_MANIFEST_DIR", static_dir().join("assets"));
let version_filter: [(&str, fn(&Route) -> bool); 5] = [
("0_3", |route| matches!(route, Route::Docs03 { .. })),
("0_4", |route| matches!(route, Route::Docs04 { .. })),
("0_5", |route| matches!(route, Route::Docs05 { .. })),
("0_6", |route| matches!(route, Route::Docs06 { .. })),
("0_7", |route| matches!(route, Route::Docs07 { .. })),
];
for (version, filter) in version_filter {
dioxus_search::SearchIndex::<Route>::create(
format!("searchable_{version}"),
dioxus_search::BaseDirectoryMapping::new(static_dir()).map(|route| {
filter(&route).then(|| {
let route = route.to_string();
println!("route: {route}");
let (route, _) = route.split_once('#').unwrap_or((&route, ""));
let (route, _) = route.split_once('?').unwrap_or((&route, ""));
std::path::PathBuf::from(route).join("index.html")
})
}),
);
}
let out_dir = static_dir().join("assets");
// Build the docsrs search index
docsrs_search::build_into(&out_dir);

std::env::set_var("CARGO_MANIFEST_DIR", &out_dir);
let version_filter: &[(&str, fn(&Route) -> bool)] = &[
("0_3", |route| matches!(route, Route::Docs03 { .. })),
("0_4", |route| matches!(route, Route::Docs04 { .. })),
("0_5", |route| matches!(route, Route::Docs05 { .. })),
("0_6", |route| matches!(route, Route::Docs06 { .. })),
("0_7", |route| matches!(route, Route::Docs07 { .. })),
];
for (version, filter) in version_filter.iter().copied() {
dioxus_search::SearchIndex::<Route>::create(
format!("searchable_{version}"),
dioxus_search::BaseDirectoryMapping::new(static_dir()).map(|route| {
filter(&route).then(|| {
let route = route.to_string();
println!("route: {route}");
let (route, _) = route.split_once('#').unwrap_or((&route, ""));
let (route, _) = route.split_once('?').unwrap_or((&route, ""));
std::path::PathBuf::from(route).join("index.html")
})
}),
);
}
}
16 changes: 16 additions & 0 deletions packages/docsite/src/icons.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,22 @@ pub(crate) fn DocumentIcon() -> Element {
}
}

pub(crate) fn CratesIOIcon() -> Element {
rsx! {
svg {
"viewBox": "0 0 576 512",
xmlns: "http://www.w3.org/2000/svg",
width: "24",
height: "24",
path {
d: "M290.8 48.6l78.4 29.7L288 109.5 206.8 78.3l78.4-29.7c1.8-.7 3.8-.7 5.7 0zM136 92.5l0 112.2c-1.3 .4-2.6 .8-3.9 1.3l-96 36.4C14.4 250.6 0 271.5 0 294.7L0 413.9c0 22.2 13.1 42.3 33.5 51.3l96 42.2c14.4 6.3 30.7 6.3 45.1 0L288 457.5l113.5 49.9c14.4 6.3 30.7 6.3 45.1 0l96-42.2c20.3-8.9 33.5-29.1 33.5-51.3l0-119.1c0-23.3-14.4-44.1-36.1-52.4l-96-36.4c-1.3-.5-2.6-.9-3.9-1.3l0-112.2c0-23.3-14.4-44.1-36.1-52.4l-96-36.4c-12.8-4.8-26.9-4.8-39.7 0l-96 36.4C150.4 48.4 136 69.3 136 92.5zM392 210.6l-82.4 31.2 0-89.2L392 121l0 89.6zM154.8 250.9l78.4 29.7L152 311.7 70.8 280.6l78.4-29.7c1.8-.7 3.8-.7 5.7 0zm18.8 204.4l0-100.5L256 323.2l0 95.9-82.4 36.2zM421.2 250.9c1.8-.7 3.8-.7 5.7 0l78.4 29.7L424 311.7l-81.2-31.1 78.4-29.7zM523.2 421.2l-77.6 34.1 0-100.5L528 323.2l0 90.7c0 3.2-1.9 6-4.8 7.3z",
fill: "currentColor",
fill_rule: "nonzero",
}
}
}
}

pub(crate) fn ExternalLinkIcon2() -> Element {
rsx! {
svg {
Expand Down
11 changes: 11 additions & 0 deletions packages/docsrs-search/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "docsrs-search"
version = "0.1.0"
edition = "2024"

[dependencies]
dioxus-search.workspace = true
reqwest = { workspace = true, features = ["blocking"] }
zip = "4.3.0"
walkdir = "2"
tempdir = "0.3.7"
Loading
Loading