use export::http::{Path, Query, Response, State}; use maud::html; use crate::handler::html::{HtmlRepoPath, archived_class, resolve_view, response_html}; use crate::service::GitService; use crate::share::access::BasicAuth; #[derive(Debug, Clone, serde::Deserialize, utoipa::IntoParams)] pub struct BlobHeaderQuery { #[serde(default)] pub revision: Option, #[serde(default)] pub path: Option, } #[utoipa::path( get, path = "/repos/{space_name}/{repo_name}/html/blob-header", tag = "html", description = "渲染文件页头的 Raw、Blame 和 History 操作链接。", operation_id = "render_blob_header", params(HtmlRepoPath, BlobHeaderQuery), responses( (status = 200, description = "blob header html fragment", content_type = "text/html"), (status = 404, description = "repo, ref or blob not found") ) )] pub async fn render_blob_header( State(service): State, Path(path): Path, Query(q): Query, auth: BasicAuth, ) -> Response { let view = match resolve_view(service.clone(), path, auth, q.revision, q.path, true).await { Ok(v) => v, Err(resp) => return resp, }; let ctx = view.ctx; let revision = view.revision; let clean_path = view.clean_path; let base = "git-blob-header flex items-center justify-between border-b border-zinc-200 px-3 py-2"; let cls = archived_class(&ctx.dto, base); let filename = clean_path.rsplit('/').next().unwrap_or(&clean_path); let space = ctx.space_name.clone(); let repo = ctx.repo_name.clone(); let raw_url = format!("/{space}/{repo}/blob/raw/{revision}/{clean_path}"); let blame_url = format!("/{space}/{repo}/blame/{revision}/{clean_path}"); let history_url = format!("/{space}/{repo}/commits/{revision}/{clean_path}"); let markup = html! { div class=(cls) data-component="git-blob-header" data-space=(space) data-repo=(repo) data-revision=(revision) data-path=(clean_path.as_str()) data-archived=(if ctx.dto.is_archived { "true" } else { "false" }) { div class="flex items-center gap-2" { svg class="h-4 w-4 text-zinc-500" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg" { path d="M2 2.5A2.5 2.5 0 014.5 0h8.75a.75.75 0 01.75.75v12.5a.75.75 0 01-.75.75h-2.5a.75.75 0 110-1.5h1.75v-2h-8a1 1 0 00-.714 1.7.75.75 0 01-1.072 1.05A2.495 2.495 0 012 11.5zm10.5-1V9h-8c-.356 0-.694.074-1 .208V2.5a1 1 0 011-1h8z" {} } span class="font-mono text-sm font-medium text-zinc-700" { (filename) } } div class="flex items-center gap-1.5" { a class="rounded border border-zinc-200 bg-white px-2 py-0.5 text-xs text-zinc-700 hover:bg-zinc-50" href=(raw_url) target="_blank" rel="noopener noreferrer" { "Raw" } a class="rounded border border-zinc-200 bg-white px-2 py-0.5 text-xs text-zinc-700 hover:bg-zinc-50" href=(blame_url) { "Blame" } a class="rounded border border-zinc-200 bg-white px-2 py-0.5 text-xs text-zinc-700 hover:bg-zinc-50" href=(history_url) { "History" } } } }; response_html(markup, 30) }