WIP: Initial pdf generation and download, needs improvement and put somewhere different.

This commit is contained in:
2026-01-27 12:53:55 -05:00
parent 69e8acc5d8
commit 6064b5267a
6 changed files with 47 additions and 12 deletions

View File

@@ -8548,6 +8548,10 @@
.italic { .italic {
font-style: italic; font-style: italic;
} }
.lining-nums {
--tw-numeric-figure: lining-nums;
font-variant-numeric: var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,);
}
.tabular-nums { .tabular-nums {
--tw-numeric-spacing: tabular-nums; --tw-numeric-spacing: tabular-nums;
font-variant-numeric: var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,); font-variant-numeric: var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,);

View File

@@ -14,10 +14,11 @@ private let viewRouteMiddleware: [any Middleware] = [
extension SiteRoute.View { extension SiteRoute.View {
var middleware: [any Middleware]? { var middleware: [any Middleware]? {
switch self { switch self {
// TODO: Should pdf require authentication, just here now for testing.
case .project(.detail(_, .pdf)), .login, .signup, .test:
return nil
case .project, .user: case .project, .user:
return viewRouteMiddleware return viewRouteMiddleware
case .login, .signup, .test:
return nil
} }
} }
} }

View File

@@ -114,6 +114,39 @@ extension SiteRoute {
extension DuctSizes: Content {} extension DuctSizes: Content {}
// FIX: Move
func handlePdf(_ projectID: Project.ID, on request: Request) async throws -> Response {
@Dependency(\.projectClient) var projectClient
let html = try await projectClient.toHTML(projectID)
let url = "/tmp/\(projectID)"
try await request.fileio.writeFile(.init(string: html.renderFormatted()), at: "\(url).html")
let process = Process()
let standardInput = Pipe()
let standardOutput = Pipe()
process.standardInput = standardInput
process.standardOutput = standardOutput
process.executableURL = URL(fileURLWithPath: "/bin/pandoc")
process.arguments = [
"\(url).html", "--pdf-engine=weasyprint", "-f", "html",
"--css=Public/css/pdf.css",
"-o", "\(url).pdf",
]
try process.run()
process.waitUntilExit()
var headers = HTTPHeaders()
headers.add(name: .contentType, value: "application/octet-stream")
headers.add(name: .contentDisposition, value: "attachment")
let response = try await request.fileio.asyncStreamFile(at: "\(url).pdf", mediaType: .pdf)
response.headers.replaceOrAdd(name: .contentType, value: "application/octet-stream")
response.headers.replaceOrAdd(
name: .contentDisposition, value: "attachment; filename=Duct-Calc.pdf")
return response
}
@Sendable @Sendable
private func siteHandler( private func siteHandler(
request: Request, request: Request,
@@ -128,6 +161,9 @@ private func siteHandler(
return try await apiController.respond(route, request: request) return try await apiController.respond(route, request: request)
case .health: case .health:
return HTTPStatus.ok return HTTPStatus.ok
// FIX: Move
case .view(.project(.detail(let projectID, .pdf))):
return try await handlePdf(projectID, on: request)
case .view(let route): case .view(let route):
return try await viewController.respond(route: route, request: request) return try await viewController.respond(route: route, request: request)
} }

View File

@@ -20,7 +20,7 @@ struct PdfDocument: HTMLDocument {
var body: some HTML { var body: some HTML {
div { div {
h1(.class("headline")) { "Duct Calc" } // h1(.class("headline")) { "Duct Calc" }
h2 { "Project" } h2 { "Project" }

View File

@@ -69,7 +69,7 @@ public struct ErrorView: HTML, Sendable {
div { div {
h1(.class("text-xl font-bold text-error")) { "Oops: Error" } h1(.class("text-xl font-bold text-error")) { "Oops: Error" }
p { p {
"\(error)" "\(error.localizedDescription)"
} }
} }
} }

View File

@@ -193,15 +193,9 @@ extension SiteRoute.View.ProjectRoute {
case .frictionRate(let route): case .frictionRate(let route):
return await route.renderView(on: request, projectID: projectID) return await route.renderView(on: request, projectID: projectID)
case .pdf: case .pdf:
// return await ResultView2 { // FIX: This should return a pdf to download or be wrapped in a
// try await projectClient.toHTML(projectID) // result view.
// } onError: {
// ErrorView2(error: $0)
// }
// return await ResultView {
return try! await projectClient.toHTML(projectID) return try! await projectClient.toHTML(projectID)
// }
// fatalError()
case .rooms(let route): case .rooms(let route):
return await route.renderView(on: request, projectID: projectID) return await route.renderView(on: request, projectID: projectID)
} }