feat: related-tags atlas in Explore view

Hovering a tag in Explore now loads and displays co-occurring tags as a
weighted cloud. New `get_related_tags` SQL self-join (db.rs/commands.rs),
`loadRelatedTags` store action with per-folder keyed cache, and TagCloud
atlas UI with ResizeObserver-driven layout and RAF animation. Explore tag
limit raised to 180; tag cloud auto-refreshes 700ms after new AI tagging
completes.
This commit is contained in:
2026-06-29 13:21:43 +01:00
parent e4a63c8bb0
commit 949382f28c
7 changed files with 608 additions and 104 deletions
+35 -1
View File
@@ -180,6 +180,19 @@ pub struct GetExploreTagsParams {
pub limit: Option<usize>,
}
#[derive(Deserialize)]
pub struct GetRelatedTagsParams {
pub tag: String,
pub folder_id: Option<i64>,
pub limit: Option<usize>,
}
#[derive(Serialize)]
pub struct RelatedTagEntry {
pub tag: String,
pub shared_count: i64,
}
#[derive(Deserialize)]
pub struct SearchTagsAutocompleteParams {
pub query: String,
@@ -1277,7 +1290,28 @@ pub async fn get_explore_tags(
params: GetExploreTagsParams,
) -> Result<Vec<ExploreTagEntry>, String> {
let conn = db.get().map_err(|e| e.to_string())?;
db::get_explore_tags(&conn, params.folder_id, params.limit.unwrap_or(48))
db::get_explore_tags(&conn, params.folder_id, params.limit.unwrap_or(180))
.map_err(|e| e.to_string())
}
#[tauri::command]
pub async fn get_related_tags(
db: State<'_, DbState>,
params: GetRelatedTagsParams,
) -> Result<Vec<RelatedTagEntry>, String> {
let tag = params.tag.trim();
if tag.is_empty() {
return Ok(vec![]);
}
let conn = db.get().map_err(|e| e.to_string())?;
db::get_related_tags(&conn, tag, params.folder_id, params.limit.unwrap_or(16))
.map(|entries| {
entries
.into_iter()
.map(|(tag, shared_count)| RelatedTagEntry { tag, shared_count })
.collect()
})
.map_err(|e| e.to_string())
}