Compare commits
No commits in common. "f2ee06b1d72908f84258e4d626eb8e30fa4523f2" and "6c21d8c857e087c042fd23bf2b0f54e6250c04c9" have entirely different histories.
f2ee06b1d7
...
6c21d8c857
@ -119,13 +119,6 @@ extension Element {
|
|||||||
It can also be set to manually write a page.
|
It can also be set to manually write a page.
|
||||||
*/
|
*/
|
||||||
let externalUrl: String?
|
let externalUrl: String?
|
||||||
|
|
||||||
/**
|
|
||||||
The text to display for content related to the current page.
|
|
||||||
|
|
||||||
This property is mandatory at root level, and is propagated to child elements.
|
|
||||||
*/
|
|
||||||
let relatedContentText: String
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,8 +162,6 @@ extension Element.LocalizedMetadata {
|
|||||||
self.thumbnailSuffix = log.unused(data.thumbnailSuffix, "thumbnailSuffix", source: source)
|
self.thumbnailSuffix = log.unused(data.thumbnailSuffix, "thumbnailSuffix", source: source)
|
||||||
self.cornerText = log.unused(data.cornerText, "cornerText", source: source)
|
self.cornerText = log.unused(data.cornerText, "cornerText", source: source)
|
||||||
self.externalUrl = log.unexpected(data.externalUrl, name: "externalUrl", source: source)
|
self.externalUrl = log.unexpected(data.externalUrl, name: "externalUrl", source: source)
|
||||||
self.relatedContentText = log
|
|
||||||
.required(data.relatedContentText, name: "relatedContentText", source: source) ?? ""
|
|
||||||
|
|
||||||
guard isComplete else {
|
guard isComplete else {
|
||||||
return nil
|
return nil
|
||||||
@ -206,7 +197,6 @@ extension Element.LocalizedMetadata {
|
|||||||
self.thumbnailSuffix = data.thumbnailSuffix
|
self.thumbnailSuffix = data.thumbnailSuffix
|
||||||
self.cornerText = data.cornerText
|
self.cornerText = data.cornerText
|
||||||
self.externalUrl = data.externalUrl
|
self.externalUrl = data.externalUrl
|
||||||
self.relatedContentText = data.relatedContentText ?? parent.relatedContentText
|
|
||||||
|
|
||||||
guard isComplete else {
|
guard isComplete else {
|
||||||
return nil
|
return nil
|
||||||
|
@ -421,10 +421,6 @@ extension Element {
|
|||||||
return pathRelativeToRootForContainedInputFile(thumbnailFile)
|
return pathRelativeToRootForContainedInputFile(thumbnailFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
The full url (relative to root) for the localized page
|
|
||||||
- Parameter language: The language of the page where the url should point
|
|
||||||
*/
|
|
||||||
func fullPageUrl(for language: String) -> String {
|
func fullPageUrl(for language: String) -> String {
|
||||||
localized(for: language).externalUrl ?? localizedPath(for: language)
|
localized(for: language).externalUrl ?? localizedPath(for: language)
|
||||||
}
|
}
|
||||||
@ -598,59 +594,3 @@ extension Element {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Element {
|
|
||||||
|
|
||||||
/**
|
|
||||||
Find a page by its page ID within the tree of the element.
|
|
||||||
*/
|
|
||||||
func find(_ pageId: String) -> Element? {
|
|
||||||
if self.id == pageId {
|
|
||||||
return self
|
|
||||||
}
|
|
||||||
for child in elements {
|
|
||||||
if let found = child.find(pageId) {
|
|
||||||
return found
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var pathComponents: [String] {
|
|
||||||
path.components(separatedBy: "/")
|
|
||||||
}
|
|
||||||
|
|
||||||
var lastPathComponent: String {
|
|
||||||
pathComponents.last!
|
|
||||||
}
|
|
||||||
|
|
||||||
func find(elementWithFolder folder: String) -> Element? {
|
|
||||||
elements.first { $0.lastPathComponent == folder }
|
|
||||||
}
|
|
||||||
|
|
||||||
func makePath(language: String, from root: Element) -> [String] {
|
|
||||||
let parts = pathComponents.dropLast()
|
|
||||||
var result = [String]()
|
|
||||||
var node = root
|
|
||||||
for part in parts {
|
|
||||||
guard let child = node.find(elementWithFolder: part) else {
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
result.append(child.title(for: language))
|
|
||||||
node = child
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func findParent(from root: Element) -> Element? {
|
|
||||||
let parts = pathComponents.dropLast()
|
|
||||||
var node = root
|
|
||||||
for part in pathComponents.dropLast() {
|
|
||||||
guard let child = node.find(elementWithFolder: part) else {
|
|
||||||
return node
|
|
||||||
}
|
|
||||||
node = child
|
|
||||||
}
|
|
||||||
return node
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -112,13 +112,6 @@ extension GenericMetadata {
|
|||||||
It can also be set to manually write a page.
|
It can also be set to manually write a page.
|
||||||
*/
|
*/
|
||||||
let externalUrl: String?
|
let externalUrl: String?
|
||||||
|
|
||||||
/**
|
|
||||||
The text to display for content related to the current page.
|
|
||||||
|
|
||||||
This property is mandatory at root level, and is propagated to child elements.
|
|
||||||
*/
|
|
||||||
let relatedContentText: String?
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +134,6 @@ extension GenericMetadata.LocalizedMetadata: Codable {
|
|||||||
.thumbnailSuffix,
|
.thumbnailSuffix,
|
||||||
.cornerText,
|
.cornerText,
|
||||||
.externalUrl,
|
.externalUrl,
|
||||||
.relatedContentText,
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,8 +163,7 @@ extension GenericMetadata.LocalizedMetadata {
|
|||||||
titleSuffix: nil,
|
titleSuffix: nil,
|
||||||
thumbnailSuffix: nil,
|
thumbnailSuffix: nil,
|
||||||
cornerText: nil,
|
cornerText: nil,
|
||||||
externalUrl: nil,
|
externalUrl: nil)
|
||||||
relatedContentText: nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -193,8 +184,7 @@ extension GenericMetadata.LocalizedMetadata {
|
|||||||
titleSuffix: nil,
|
titleSuffix: nil,
|
||||||
thumbnailSuffix: nil,
|
thumbnailSuffix: nil,
|
||||||
cornerText: nil,
|
cornerText: nil,
|
||||||
externalUrl: nil,
|
externalUrl: nil)
|
||||||
relatedContentText: "")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static var full: GenericMetadata.LocalizedMetadata {
|
static var full: GenericMetadata.LocalizedMetadata {
|
||||||
@ -212,7 +202,6 @@ extension GenericMetadata.LocalizedMetadata {
|
|||||||
titleSuffix: "",
|
titleSuffix: "",
|
||||||
thumbnailSuffix: "",
|
thumbnailSuffix: "",
|
||||||
cornerText: "",
|
cornerText: "",
|
||||||
externalUrl: "",
|
externalUrl: "")
|
||||||
relatedContentText: "")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ struct PageContentGenerator {
|
|||||||
var hasCodeContent = false
|
var hasCodeContent = false
|
||||||
|
|
||||||
let imageModifier = Modifier(target: .images) { html, markdown in
|
let imageModifier = Modifier(target: .images) { html, markdown in
|
||||||
processMarkdownImage(markdown: markdown, html: html, page: page, language: language)
|
processMarkdownImage(markdown: markdown, html: html, page: page)
|
||||||
}
|
}
|
||||||
let codeModifier = Modifier(target: .codeBlocks) { html, markdown in
|
let codeModifier = Modifier(target: .codeBlocks) { html, markdown in
|
||||||
if markdown.starts(with: "```swift") {
|
if markdown.starts(with: "```swift") {
|
||||||
@ -70,7 +70,7 @@ struct PageContentGenerator {
|
|||||||
return html
|
return html
|
||||||
}
|
}
|
||||||
|
|
||||||
private func processMarkdownImage(markdown: Substring, html: String, page: Element, language: String) -> String {
|
private func processMarkdownImage(markdown: Substring, html: String, page: Element) -> String {
|
||||||
// Split the markdown ![alt](file title)
|
// Split the markdown ![alt](file title)
|
||||||
// There are several known shorthand commands
|
// There are several known shorthand commands
|
||||||
// For images: ![left_title](file right_title)
|
// For images: ![left_title](file right_title)
|
||||||
@ -78,12 +78,11 @@ struct PageContentGenerator {
|
|||||||
// For svg with custom area: ![x,y,width,height](file.svg)
|
// For svg with custom area: ![x,y,width,height](file.svg)
|
||||||
// For downloads: ![download](file1, text1; file2, text2, ...)
|
// For downloads: ![download](file1, text1; file2, text2, ...)
|
||||||
// For a simple boxes: ![box](title;body)
|
// For a simple boxes: ![box](title;body)
|
||||||
// A fancy page link: ![page](page_id)
|
|
||||||
// External pages: ![external](url1, text1; url2, text2, ...)
|
// External pages: ![external](url1, text1; url2, text2, ...)
|
||||||
let fileAndTitle = markdown.between("(", and: ")")
|
let fileAndTitle = markdown.between("(", and: ")")
|
||||||
let alt = markdown.between("[", and: "]").nonEmpty
|
let alt = markdown.between("[", and: "]").nonEmpty
|
||||||
if let alt = alt, let command = ShorthandMarkdownKey(rawValue: alt) {
|
if let alt = alt, let command = ShorthandMarkdownKey(rawValue: alt) {
|
||||||
return handleShortHandCommand(command, page: page, language: language, content: fileAndTitle)
|
return handleShortHandCommand(command, page: page, content: fileAndTitle)
|
||||||
}
|
}
|
||||||
|
|
||||||
let file = fileAndTitle.dropAfterFirst(" ")
|
let file = fileAndTitle.dropAfterFirst(" ")
|
||||||
@ -102,7 +101,7 @@ struct PageContentGenerator {
|
|||||||
return handleFile(page: page, file: file, fileExtension: fileExtension)
|
return handleFile(page: page, file: file, fileExtension: fileExtension)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handleShortHandCommand(_ command: ShorthandMarkdownKey, page: Element, language: String, content: String) -> String {
|
private func handleShortHandCommand(_ command: ShorthandMarkdownKey, page: Element, content: String) -> String {
|
||||||
switch command {
|
switch command {
|
||||||
case .downloadButtons:
|
case .downloadButtons:
|
||||||
return handleDownloadButtons(page: page, content: content)
|
return handleDownloadButtons(page: page, content: content)
|
||||||
@ -112,8 +111,6 @@ struct PageContentGenerator {
|
|||||||
return handleExternalHTML(page: page, file: content)
|
return handleExternalHTML(page: page, file: content)
|
||||||
case .box:
|
case .box:
|
||||||
return handleSimpleBox(page: page, content: content)
|
return handleSimpleBox(page: page, content: content)
|
||||||
case .pageLink:
|
|
||||||
return handlePageLink(page: page, language: language, pageId: content)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,45 +250,4 @@ struct PageContentGenerator {
|
|||||||
let text = parts.dropFirst().joined(separator: ";")
|
let text = parts.dropFirst().joined(separator: ";")
|
||||||
return factory.makePlaceholder(title: title, text: text)
|
return factory.makePlaceholder(title: title, text: text)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handlePageLink(page: Element, language: String, pageId: String) -> String {
|
|
||||||
guard let linkedPage = siteRoot.find(pageId) else {
|
|
||||||
log.add(warning: "Page id '\(pageId)' not found", source: page.path)
|
|
||||||
// Remove link since the page can't be found
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
var content = [PageLinkTemplate.Key: String]()
|
|
||||||
content[.url] = page.relativePathToOtherSiteElement(file: linkedPage.fullPageUrl(for: language))
|
|
||||||
|
|
||||||
content[.title] = linkedPage.title(for: language)
|
|
||||||
|
|
||||||
let fullThumbnailPath = linkedPage.thumbnailFilePath(for: language)
|
|
||||||
let relativeImageUrl = page.relativePathToOtherSiteElement(file: fullThumbnailPath)
|
|
||||||
let metadata = linkedPage.localized(for: language)
|
|
||||||
|
|
||||||
if linkedPage.state.hasThumbnailLink {
|
|
||||||
let fullPageUrl = linkedPage.fullPageUrl(for: language)
|
|
||||||
let relativePageUrl = page.relativePathToOtherSiteElement(file: fullPageUrl)
|
|
||||||
content[.url] = "href=\"\(relativePageUrl)\""
|
|
||||||
}
|
|
||||||
|
|
||||||
content[.image] = relativeImageUrl
|
|
||||||
if let suffix = metadata.thumbnailSuffix {
|
|
||||||
content[.title] = factory.html.make(title: metadata.title, suffix: suffix)
|
|
||||||
} else {
|
|
||||||
content[.title] = metadata.title
|
|
||||||
}
|
|
||||||
content[.image2x] = relativeImageUrl.insert("@2x", beforeLast: ".")
|
|
||||||
|
|
||||||
let path = linkedPage.makePath(language: language, from: siteRoot)
|
|
||||||
content[.path] = factory.pageLink.makePath(components: path)
|
|
||||||
|
|
||||||
content[.description] = metadata.relatedContentText
|
|
||||||
if let parent = linkedPage.findParent(from: siteRoot), parent.thumbnailStyle == .large {
|
|
||||||
content[.className] = " related-page-link-large"
|
|
||||||
}
|
|
||||||
|
|
||||||
// We assume that the thumbnail images are already required by overview pages.
|
|
||||||
return factory.pageLink.generate(content)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,4 @@ enum ShorthandMarkdownKey: String {
|
|||||||
A box with a heading and a text description
|
A box with a heading and a text description
|
||||||
*/
|
*/
|
||||||
case box = "box"
|
case box = "box"
|
||||||
|
|
||||||
/**
|
|
||||||
A pretty link to another page on the site.
|
|
||||||
*/
|
|
||||||
case pageLink = "page"
|
|
||||||
}
|
}
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
import Foundation
|
|
||||||
|
|
||||||
struct PageLinkTemplate: Template {
|
|
||||||
|
|
||||||
enum Key: String, CaseIterable {
|
|
||||||
case url = "URL"
|
|
||||||
case image = "IMAGE"
|
|
||||||
case image2x = "IMAGE_2X"
|
|
||||||
case title = "TITLE"
|
|
||||||
case path = "PATH"
|
|
||||||
case description = "DESCRIPTION"
|
|
||||||
case className = "CLASS"
|
|
||||||
}
|
|
||||||
|
|
||||||
static let templateName = "page-link.html"
|
|
||||||
|
|
||||||
let raw: String
|
|
||||||
|
|
||||||
func makePath(components: [String]) -> String {
|
|
||||||
components.joined(separator: " » ") //  » ")
|
|
||||||
}
|
|
||||||
}
|
|
@ -16,8 +16,6 @@ final class TemplateFactory {
|
|||||||
|
|
||||||
let overviewSectionClean: OverviewSectionCleanTemplate
|
let overviewSectionClean: OverviewSectionCleanTemplate
|
||||||
|
|
||||||
let pageLink: PageLinkTemplate
|
|
||||||
|
|
||||||
let box: BoxTemplate
|
let box: BoxTemplate
|
||||||
|
|
||||||
// MARK: Thumbnails
|
// MARK: Thumbnails
|
||||||
@ -67,7 +65,6 @@ final class TemplateFactory {
|
|||||||
self.overviewSection = try .init(in: templateFolder)
|
self.overviewSection = try .init(in: templateFolder)
|
||||||
self.overviewSectionClean = try .init(in: templateFolder)
|
self.overviewSectionClean = try .init(in: templateFolder)
|
||||||
self.box = try .init(in: templateFolder)
|
self.box = try .init(in: templateFolder)
|
||||||
self.pageLink = try .init(in: templateFolder)
|
|
||||||
self.largeThumbnail = try .init(in: templateFolder)
|
self.largeThumbnail = try .init(in: templateFolder)
|
||||||
self.squareThumbnail = try .init(in: templateFolder)
|
self.squareThumbnail = try .init(in: templateFolder)
|
||||||
self.smallThumbnail = try .init(in: templateFolder)
|
self.smallThumbnail = try .init(in: templateFolder)
|
||||||
|
@ -4,7 +4,6 @@ import ArgumentParser
|
|||||||
var configuration: Configuration!
|
var configuration: Configuration!
|
||||||
let log = ValidationLog()
|
let log = ValidationLog()
|
||||||
var files: FileSystem!
|
var files: FileSystem!
|
||||||
var siteRoot: Element!
|
|
||||||
|
|
||||||
@main
|
@main
|
||||||
struct CHGenerator: ParsableCommand {
|
struct CHGenerator: ParsableCommand {
|
||||||
@ -26,12 +25,11 @@ private func generate(configPath: String) throws {
|
|||||||
in: configuration.contentDirectory,
|
in: configuration.contentDirectory,
|
||||||
to: configuration.outputDirectory)
|
to: configuration.outputDirectory)
|
||||||
|
|
||||||
siteRoot = Element(atRoot: configuration.contentDirectory)
|
guard let siteData = Element(atRoot: configuration.contentDirectory) else {
|
||||||
guard siteRoot != nil else {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let siteGenerator = try SiteGenerator()
|
let siteGenerator = try SiteGenerator()
|
||||||
siteGenerator.generate(site: siteRoot)
|
siteGenerator.generate(site: siteData)
|
||||||
|
|
||||||
files.printGeneratedPages()
|
files.printGeneratedPages()
|
||||||
files.printEmptyPages()
|
files.printEmptyPages()
|
||||||
|
Loading…
Reference in New Issue
Block a user