Git Product home page Git Product logo

ignite's People

Contributors

0xtim avatar bryant-24 avatar compufox avatar daveverwer avatar dl-alexandre avatar gavineadie avatar henrikac avatar jessielinden avatar jobearrr avatar markstamer avatar mcrich23 avatar mfreiwald avatar mikaoj avatar nigelgee avatar pd95 avatar steve-h avatar thearchitectlabs avatar toastersocks avatar twostraws avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ignite's Issues

Question: supporting alternative css frameworks, such as tailwindcss

Love the principles behind Ignite and excited to start using + hopefully contributing to it in some form.

My existing site is built using tailwindcss, which I've been really enjoying as an alternative to bootstrap for its point-of-use simplicity. In some ways I feel it's similar to SwiftUI, in that you're encouraged to attach styles to elements inline rather than building a centralized stylesheet.

The reason I want to start using Ignite is that I have a lot of content that I'd like to share between my application and my website, e.g. the app's Shorcuts documentation, and I'd love for my site to build in the same toolchain as my app so that I can be sure that my site's documentation always reflects the latest app state.

Before I dive too deep into the rabbit hole though, I wanted to pose the question here in case there's some guidance I can follow for exploring use of tailwindcss with Ignite? Am I holding the tool wrong to think that I should try to incorporate tailwindcss or ideas from it?

Feature Request: Deferred Rendering

Purpose

Sometimes you want data to be fetched from a remote server at publish time

Proposed Solution

A. Add an AsyncElement protocol / ElementType

protocol AsyncElement {
   func render(context: PublishingContext) async -> String
}

A benefit of this option is that it's pretty intuitive to the consumer. They should just block/await until their data is ready.

B. Provide a special API to register async queries

struct SomeExampleData: AsyncData {
/// fields from a public REST resources
}
public struct SomeExample: InlineElement {
  func loadData(context: PublishingContext) async throws -> any AsyncData {
    // Can access other member variables
    // Can access URLRequest
    return SomeExampleData()
  }
  func render(context: PublishingContext, runtimeData: any AsyncData?) -> String {
   guard let data = runtimeData else {
     return "SomeExampleData Missing"
   }
   // ...
  }
}

Alternatives Considered

A downside of providing any Async APIs is that poor implementation could lead to slow rendering. Each time an Async Component is Encountered the whole subtree of components that are children of that node might be invalidated. Additionally, peer or parent components could be invalidated if their rendering depends on how many children they have. Think how you would implement an Outline component that automatically handles all the headers, but is physically located at the top of the page?
Additionally, we probably would want a timeout at some-level to finish rendering despite in-progress async requests.

  • Not allowing async-data load, for consumers with this need, they'd have to pre-fetch their data to disk before executing Ignite's build, but this is a bit clunky, particularly if you want the dynamic data to be selected based on the Content in your pages
  • I thought about a special element DataLoader that generically had an async method to fetch the data, but this didn't seem to be better than Option A above.

Additional Special Edge Case

If you wanted to build an AutomaticOutline component, you need a way for this component to depend on being run after other Async components have finished running. With either of the options above, we can ensure the data could be provided via an appropriate environment hook (see #2), but it doesn't have something to await against since new outline entries could be discovered when previous async components are rendered.

One way to modify the Option A would be:

protocol AsyncElement {
   // (…other things as before)
   
   public(get) var asyncRenderGroup: AsyncRenderGroup
   public(get) var asyncRenderRank: Int
}
enum AsyncRenderGroup {
  case `default`
  /// after other async elements in the `default` group
  case last
}
protocol DefaultAsyncElement: AsyncElement {}
extension DefaultAsyncElement {
  let asyncRenderGroup: AsyncRenderGroup = .default
  let asyncRenderRank: Int = 0
}

Obviously, if we go with Option B or some other solution, then a different technique might be needed for this edge case.

Various Build Issues

Running IgniteStarter from within Xcode doesn't appear to replace the Build folder after the first run. If I do a simple change to the 'Hello World' text on the Home page and rebuild the site the resulting index page doesn't reflect the change. I also get a “.DS_Store” couldn’t be copied to “Build” because an item with the same name already exists message.

I also downloaded and installed ignite as a CLI. It installed fine and creates a website but fails to build it. After a longish delay where the dependencies are downloaded and compiled I get a build failed message. Second run is faster but I get another error:

% ignite build
⚙️ Building your site...
warning: could not determine XCTest paths: terminated(1): /usr/bin/xcrun --sdk macosx --show-sdk-platform-path output:
xcrun: error: unable to lookup item 'PlatformPath' from command line tools installation
xcrun: error: unable to lookup item 'PlatformPath' in SDK '/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk'

[0/1] Planning build
Building for debugging...
[0/3] Write swift-version--1AB21518FC5DEDBE.txt
Build complete! (0.14s)

❌ Failed to build.

Is there something I am missing? Thanks!

Feature Request: Component Dependencies should be added on first use

Some Components depend on specific assets like CSS, JS, or other resources. It’d be great if there was a way for components to dynamically register those assets only if they’re used by the page they’re rendering into.

As an example, there’s some Ignite code that tries to figure out which languages are in use in order to add the correct prism code for that language to the page. This relies currently on users configuring the languages at the page level.

With an appropriate API, the Prism CodeBlock component could instead inspect the language it’s provided as an attribute, and request that Ignite ensures the dependency for that language was included.

Proposal

  1. Macro for Simple Dependencies — some components always need specific CSS/JS, so this could be a macro tagged on the component as a whole. @depends(on: […])
  2. Some components need finer grained dependencies, potentially contingent on instance-specific data attributes, this could be resolved with a RenderContext method registerDependency

under the hood, these could be implemented using the willRender method proposed elsewhere

An advantage of this approach is that Ignite’s core could be agnostic of what JS/CSS is in your page, and the Bootstrap-specific components would only pull in bootstrap if they’re used. The majority of Ignite’s components/Elements seem agnostic of Bootstrap.

newline ("\n") characters dropped from Markdown in Content files

I just noticed that the newline character treatment in Content (*md) files isn't what I expected. Specifically, a "\n" character within a Markdown paragraph is removed (and, by the way, so is any preceding space " " character). I noticed this because the last word of line n and the first word of line n+1 were being concatenated, viz:

.. the sunspot that was pictured in yesterday’s
animation isn’t the reappearance ..

renders as ".. the sunspot that was pictured in yesterday’sanimation isn’t the reappearance .."

I understand that, in Markdown, paragraphs are separated by two newlines (and I noticed @twostraws Markdown files are like that: one long line per para, with no 'hard folds'), but I thought single newlines were treated as whitespace. Other Markdown rendering software I use (including BBEdit and Xcode) behaves as I expect [though what I'm typing right now onto the GitHub issues page is a third variation of different]. I spent rather a frighting number of hours stepping through cmark-gfm with the debugger to no avail, and am left with the uncomfortable feeling I've missed something obvious. [cmark-gfm seems to have a plethora of typographic options (-- to —, etc), I did I miss such an option?]

Obviously, I can reformat my Markdown to resolve this very simply.


"The good thing about standards is that there as so many to choose from!" .. the Markdown quote above renders as:

".. the sunspot that was pictured in yesterday’sanimation isn’t the reappearance .." -- Ignite
".. the sunspot that was pictured in yesterday’s animation isn’t the reappearance .." -- BBEdit/Xcode
".. the sunspot that was pictured in yesterday’s
animation isn’t the reappearance .." -- GitHub

How do I show a 404 page?

When an unknown url is passed in, it instead shows the home page. How do I show a 404 page instead?

Feature Request: @BlockElementBuilder func body() -> some BlockElement {

Property wrappers to aid in code extractions and organization.
Internally Ignite has several ElementBuilder typealias, it would be useful to have public facing property wrappers for them:

//ElementBuilder.swift
typealias BlockElementBuilder = ElementBuilder<BlockElement>
typealias HeadElementBuilder = ElementBuilder<HeadElement>
typealias HTMLRootElementBuilder = ElementBuilder<HTMLRootElement>
typealias InlineElementBuilder = ElementBuilder<InlineElement>
typealias PageElementBuilder = ElementBuilder<PageElement>
typealias StaticPageBuilder = ElementBuilder<any StaticPage>
typealias ContentPageBuilder = ElementBuilder<any ContentPage>

✅ These compile

func bottomInfoSection()->BlockElement{
    Text("Thank you for reading this page")
        .font(.title6)
        .id("bottom-info")
}
func bottomInfoSection()->BlockElement{
    Group{
        let id:String = "bottom-info"
        Text("Thank you for reading this page")
            .font(.title6)
            .id(id)
        Script(code:"document.getElementById('\(id)').addEventListener('contextmenu',e=>alert(e.target.innerText))")
    }
}

❌ But these don't

//Error: Missing return in instance method expected to return 'any BlockElement'

func bottomInfoSection()->BlockElement{
    let id:String = "bottom-info"
    Text("Thank you for reading this page")
        .font(.title6)
        .id(id)
}
func bottomInfoSection()->BlockElement{
    let id:String = "bottom-info"
    Text("Thank you for reading this page")
        .font(.title6)
        .id(id)
    Script(code:"document.getElementById('\(id)').addEventListener('contextmenu',e=>alert(e.target.innerText))")
}

Something like:

@BlockElementBuilder
func bottomInfoSection()->some BlockElement{ ... }
@ElementBuilder 
func bottomInfoSection()->some BlockElement{ ... }

Feature Request: Card Content Text Positions

At the moment it can put the text .bottom, .top, .overlay (plus recent added .overlayCenter).

Could it have the text .trailing and .leading (which would snap to .bottom if .trailing and .top if .leading when size get too small).

This could also have alignment for the text to be in the top, center, or bottom of the image.

Card(imageName: "/images/rug.jpg") {
    Text(placeholderLength: 100)
}
.contentPosition(.trailing(alignment: .top)

server-side code - is it possible with Ignite?

Hello!
First of all, thanks Paul for this great work. I watched his video and I'm studying the framework code to better understand Swift and SwiftUI programming. It is valuable for studying but as Swift enthusiast I'm also want to use it in my real projects as well (I got a hammer, so everything should be nails ;) ). SSG is a very thin niche for me, so if I could leave it out a little it would be more practical. Also I think the framework could have more real use cases.
I'm sorry for this may be silly question. Can you advice me whether I can use this framework to run server-side code as well?
What needs to be changed for this? Or what needs to be added?
What would an architecture look like for generating HTML pages during the processing of each request?
What difficulties do you see?
Thank you!

Support custom install locations in Makefile

Currently the Makefile is hardcoded to only install to /usr/local/bin which is not always possible or desired.

It would be nice to have location controlled via shell variable or some other command line invocation

Question: Dynamic rendering of content using Server Side Swift / Ignite / Vapor ?

Hi

Im playing a bit of catch up here with Ignite but its an exciting project!

I am curious - is there a potential world where Vapor could serve dynamic web content using Ignite as the HTML rendering on the back end? So rather than serving statically rendered HTML, a Vapor end point could serve dynamically rendered Ignite HTML using its syntax?

Just curious, and there isnt a discussion tab here, so apologies for making an issue.

Run command does not work

Ignite run command gives the following error:
ignite run --preview
❌ This site specifies a custom subfolder, so it can't be previewed locally.

I was able to run my project but suddenly got the above error. After a while it got fixed automatically and then again it returned. There is not much in the project and everything is mostly in the default state

Adding Ignite as a Package Dependency fails

I tried to add Ignite to a new Swift Command Line project and importing Ignite gives me a Package Resolution Failed error:

Ignite could not be resolved.

...Ignite
Updating from http://github.com/twostraws/Ignite
Failed to resolve dependencies Dependencies could not be resolved because root depend on 'ignite' 0.2.1..<1.0.0

I have very recent MacOS and Xcode and the IgniteStarter project work fine. Selecting the Add Anyway button gives me a single Ignite package but none of the other packages load and the Ignite package can't be opened.

Feature Request: Markdown Parser via Plugin? Alternative, a block that takes a "HTMLRepresentable"

It would be nice to have the Markdown parsed via a "MarkdownParserService" or some patches of HTML provided by an "HTMLProvider" protocol?

Perhaps that could even not be a site wide call? My "Recipes" Content folder could use the RecipeoParser package and "BandReviews" could use the MetalMarkerExtreme package...

Maybe the simplest would be a Block Element that would take in any "HTMLRepresentable", not just an already rendered include.

I currently use hugo (partially to keep myself from fussing), but I really miss the plugin architecture of WordPress. hugo's lack of plugins is why I'll probably move on. Maybe to Ignite! Thank you!

Feature Request: Would it be possible to add built in support for JQuery or possibly a way of accessing DOM elements?

I'm not sure how feasible this could be, but it would be a great addition to be able to access jquery methods directly on any BlockElement and PageElement.

I make a lot of web extensions and userscripts, and whenever it comes to UI styling and layouts, I always include JQuery. It provides a lot of SwiftUI like simplicity and straight forwardness to quickly applying changes and styling to any element.

Some problem common in Ignite and especially in traditional html/css/javascript flow:

  • Implementing a ZStack layout is always a challenge, being able to dive into jquery directly on a BlockElement/PageElement could make this easier.
  • dynamically style an element relative to another (e.g. sibling, parent, or child elements).
  • Animations
  • SwiftUI-like onAppear, onDisappear, onChange methods (jquery event listeners with ease access to itself)

To my surprise, it wasn't too difficult to get jquery loaded externally and available for use to dynamically style the page using the Script Element.
As quick example, I got the code below working in Ignite. It checks for jQuery, and creates a new element, styles it, clicking on it appends to itself, animates in, and fades out.

Script(file: "https://code.jquery.com/jquery-3.7.1.min.js")

<script type="text/javascript">
if(!jQuery){
        alert("❌DEBUG: JQuery not loaded")
    }else{
        alert("✅DEBUG: JQuery successfully loaded");
        let userAnswers = $(".questions-answered").has(".correctly-answered");
        let correctAnswers = userAnswers.length;
        let presentSuccessMsg = correctAnswers >= 10;
        if(presentSuccessMsg){
            $(document.createElement("div"))
                .addClass("successMsg")
                .css("opacity", 0.9)
                .css("border-radius", "10px")
                .css({
                      fontSize:"larger", fontWeight:"bolder",
                      zIndex: 9999, position: "fixed",
                      left:"calc(50% - 200px)", top: "calc(50% - 150px)",
                      filter: "blur(0.5px)",  display: "inline-block",
                      height: "300px",  width: "400px",
                      backgroundColor: "green", whiteSpace: "pre-line",
                      padding: 10,  overflow: "scroll"
                 })
                .text(`🎉Congrats! You've successfully answered ${ userAnswers.length } questions! 🎉`)
                .click(function(e){
                       $(this).append(`\nYou've Clicked Me ${$(this).text().split("\n").length} Times!`);
                 })
                .slideDown(1000 * 2)
                .delay(1000 * 5)
                .fadeOut(1000 * 2)
                .appendTo(document.body)
        }
    }
</script>

Other than jquery, a much larger target would be, being able to reference/access the DOM element on a BlockElement. This will enable writing logic javascript logic that cannot be done using swift.
I've managed to get some decent results by using an Id tag to each BlockElement, and accessing them inside in a Script element on the page Head, but it's very un-SwiftUI.

Otherwise, Ignite has been pretty incredible and has high potential.

Feature Request: `.environment(…)` modifier or similar hierarchical information passing

Please let me know if there's a way to do this already and I just missed it!

Purpose

I'd like to build components that render differently depending on their position in the Element Hierarchy.

Some concrete examples:

Example 1: Dynamic Header (Rank)

(Virtual HTML-style DOM tree)

<SectionWithHeader title="Outer" >
  <SectionWithHeader title="1.1" />
  <SectionWithHeader title="1.2">
    <SectionWithHeader title="1.2.1" />
    <SectionWithHeader title="1.2.2" />
   </SectionWithHeader> 
</SectionWithHeader>

In this example, the hypothetical SectionWithHeader component would use the .environment()-context to help generate the following html:

<div>
  <h1>Outer</h1>
  <div>
    <h2>1.1</h2>
  </div>
  <div>
    <h2>1.2</h2>
    <div>
      <h3>1.2.1</h3>
    </div>
    <div>
      <h3>1.2.2</h3>
    </div>
</div>

… but only if it can keep track of how deep the component is within the tree.

Notice: you could implement this component to automatically provide data for a statically generated Outline, with automatic anchor-links to each heading

Example 2: Dynamic Environmental Overrides

In various past projects, I've found it useful to be able to preview a component, but rendered side-by-side with different contexts. One example is simultaneously viewing light/dark themes of the same component.

<ThemeTester>
 …my content here.
</ThemeTester>

Output:

<div>
 <b>Light Mode:</b> 
  …my content here.
</div>
<div>
 <b>Dark Mode:</b>
  …my content here.
</div>

Related use-cases:

  • viewing the same page, while swapping the theme out entirely.
  • previewing lots of elements at different dynamic-type sizes.
  • forcing layout at different breakpoints (to compare portrait vs landscape).
  • Changing the layout of a Card from a row to a grid a column to a hand-tuned layout to a text-string depending on how deeply nested a component is in the hierarchy.

Some browsers have some of these as a tools at the browser/debugger level, but I've found those to be pretty inconvenient.

Suggested Solution

If we implement something like the SwiftUI's Environment modifier or React's Context then we can provide necessary data for implementing these use cases above, and plenty of others not listed.

Alternatives Considered

  • Some of these could be implemented in pure CSS, albeit in a clunky way where a lot of explicit behavior needs to be encoded. Not all of these could be implemented in this way however.
  • Many of these could be implemented in JS that runs at page-load time, but obviously that's not really static site generation
  • Not implementing this could be simpler, because this becomes a new extension point for components.

Feature Request: `<script>` support

Would be very useful to add support for JavaScript execution via what would be <script> in HTML. I understand Ignite is meant for static sites, but it could be useful for certain specific actions, like analytics, reload and other browser actions, etc. Already tried using Embed to see if it would execute, and it doesn't.

Full documentation missing

I was just trying to get started with this project and found that the only documentation seems to live in the README file. While that's a good starting point, I still had lots of questions after fully reading it and it took me ~1 hour to fully discover all the available elements and features by scanning through the entire projects source code and checking the structure and comments in the Starter project.

Since most of the code already has some useful documentation, I think a DocC-rendered site with a couple articles to get people started would go a long way in helping people to quickly check if this project covers their needs or not. Since I'm sure you're busy with WWDC aftermath, I'm happy to help. I can do a similar setup to what I've done for of my open-source project HandySwift, see here. The documentation then would live on swiftpackageindex.com unless you want me to do a GitHub Pages-based deployment, which I've also done just recently for WWDC Notes, see here.

Please let me know if you have other plans for the docs or if I should continue with my suggestion.

Close Button

To dismiss modal dialogs I would like to introduce a close button. It seems it is as easy as adding the case close to Role as Bootstrap will make a close button consisting of a simple cross from btn-close. Would this be an appropriate approach or does this polite the Role type in any way? I could also introduce a CloseButton type which would lead to some duplication though.

Can Ignite Support Gradients?

Hey @twostraws, I've just started checking out Ignite and am very excited to use it for hosting a static site/blog I'm putting together. Part of the design of my blog calls for a gradient mask over text like this, and I was trying to figure out if it's possible to support this in Ignite today.

Plinky Logo

I've gone ahead and looked at your support for Color to try and figure out how it's implemented, but in my cursory glance haven't figured out how I would implement equivalent support for gradients.

I was wondering if:

  1. You had any plans for implementing first class support for gradients.
  2. If not, do you have any advice for how I could do that?

Thank you so much, really excited to put something together using Ignite.

Feature request: Blurs and Material support

A neat little feature, especially for the navigation bar, would be a Blur element or a SwiftUI Material port to Ignite. Like in SwiftUI, where a background can be chosen as Material and then pick a blur of a special thickness, it would be neat for Ignite to have such element, possibly integrated directly into .background as well.

Adding localization support to improve accessibility

While accessibility labels and ARIA support seem to exist, many statically generated sites like app landing pages or documentation sites would be vastly more accessible if they were available in multiple languages. From what I understand, it would be already possible to create a view with buttons that link to separate subfolders of articles (such as en, de-DE etc.). But there are a few others things that need to be considered for a website with multi-language support:

  1. A way to adjust the language value of the Site based on the current language settings (this line)
  2. A way to provide different values for String parameters such as for a sites description or a buttons label
  3. A built-in way to know/determine the supported languages of a site during build
  4. A built-in language switcher component that automatically lists the supported languages & sets it on click
  5. Some kind of string table where users can provide different values for different languages

I know that this sounds like adding a dynamic layer to this "static" site generator. Localization in my opinion is for sure a "dynamic" aspect worth providing, but if implemented in a thoughtful manner, we can retain the static aspect by simply creating a duplicate of each page with only the localized texts changed. The language could be provided at root path level via the Language enums raw value, leading to URLs like https://ignitesamples.hackingwithswift.com/de/grid-examples/. We could generate variants of all pages for each supported language and place them in the respective folder (e.g. de) so everything still is static.

But we would need some JavaScript to set the language value based on the path during page load, so things like the metadata have the correct language set. For things like the usage of localizedContains, while building the different language subfolders, we would need to set a custom locale with the current language being generated for accurate results.

As for the string table, I would suggest we use a subset of String Catalogs as we don't need all features, such as "Vary by device". We could even start without pluralization support to keep things simple. I'm happy to donate my Codable struct to parse them, which I have already implemented for one of my apps. Updating that is simple enough in case Apple makes changes. It's versioned as well, so we should be able to notice easily. This year, they didn't change anything to the structure, so it should be pretty stable. But I'm happy to adjust the code whenever needed.

Using String Catalogs rather than a custom format has great advantages:

  • Users can use well-known APIs like String(localized:) to specify texts that should be localized
  • We can adjust existing components to accept LocalizedStringKey rather than String where needed
  • Xcode will automatically extract the localizable texts to the String Catalog on build/run
  • Xcode provides an easy-to-use editor for String Catalogs built into Xcode with localization progress & more

As not everyone will need or want to localize their sites, we should keep this as opt-in and default to exactly the same behavior without any subpaths like /en. Also, a default language should be set and used as a fallback for when a domain is called without any language subpath. I'm not sure if a safe redirect is even possible on static site calls, so the default locale files should just live in the root directory.

Please let me know what you think about adding localization support and also about my suggestion. I'm happy to do provide an initial version of localization support once you've approved that what I outlined makes sense to you.

Getting warnings about swift-driver

I have a clean Mac with Xcode 16 Beta 2 on MacOS18 Beta 2, tried following the instructions to build and run ignite and got a bunch of warning about swift-driver which I've not come across before. I didn't see reference to this in the readme (appols if I missed it) but unclear if this is something I need to install. Haven't yet had a chance to test this on Linux to see if it is a Mac thing or a general thing. Might be worth addressing this in the readme. I'm also hitting build issues which are being addressed in another thread but wanted to file this anyway.

warning: 'ignite': <unknown>:0: warning: using (deprecated) legacy driver, Swift installation does not contain swift-driver at: '/Library/Developer/CommandLineTools/usr/bin/swift-driver-new'
warning: 'swift-argument-parser': <unknown>:0: warning: using (deprecated) legacy driver, Swift installation does not contain swift-driver at: '/Library/Developer/CommandLineTools/usr/bin/swift-driver-new'
warning: 'swift-markdown': <unknown>:0: warning: using (deprecated) legacy driver, Swift installation does not contain swift-driver at: '/Library/Developer/CommandLineTools/usr/bin/swift-driver-new'
warning: 'swift-cmark': <unknown>:0: warning: using (deprecated) legacy driver, Swift installation does not contain swift-driver at: '/Library/Developer/CommandLineTools/usr/bin/swift-driver-new'

Set Accordion title background colour

Hello,

is it possible to change the background of the Accordion title, when it is open, from blue to a self-defined value?
In my opinion, it would be helpful to maintain a colour style throughout the website.

Regards,
Ralf

Question: How to add Font Awesome Support in <head>

I like to utilize FA in my site. However, the instructions for use are to copy this code into the : <script src="https://kit.fontawesome.com/xxxxxxxxxx.js" crossorigin="anonymous"></script>

How can I add this to the ? I don't see a way to modify that element.

Thank you for the wonderful work on this and I apologize if there is a simple fix that I am just missing.

build command not reporting error with layouts

On my Site definition, I had the layouts assigned like below:

var layouts = [
    BlogPost()
]

where BlogPost is a custom layout inheriting from ContentPage.

When I run the ignite build command, it finishes with the message ✅ Successfully built!, but I look at the Build/ folder and the contents using the BlogPost layout are not there.

I ran the executable scheme on Xcode and there I got an error Failed to find layout named BlogPost.

Should there be a difference between these two building options?
I think it would be nice to have the build command reporting that error which I got reported when running the executable scheme on Xcode.

Placement of <script> after </body> seems to render in browsers but is recommended to be before </body>

I am just starting to look at Ignite and my Nova editor gave an error/warning about the .js files added outside the HTML body. They are supposed to be in the head section or at the end of the body to speed the page render.

I see there is another issue to make conditional inclusions of .js only when needed for each page. I am adding this here as a stepping stone to at least get conformance.

public struct HTML: PageElement {
   ...
 public func render(context: PublishingContext) -> String {
        var output = "<!doctype html>"
        output += "<html lang=\"\(context.site.language.rawValue)\" data-bs-theme=\"light\"\(attributes.description)>"
        output += head?.render(context: context) ?? ""
        output += body?.render(context: context) ?? ""
        output += Script(file: "/js/bootstrap.bundle.min.js").render(context: context)

        if context.site.syntaxHighlighters.isEmpty == false {
            output += Script(file: "/js/syntax-highlighting.js").render(context: context)
        }

        // Activate tooltips if there are any.
        if output.contains(#"data-bs-toggle="tooltip""#) {
            output += Script(code: """
            const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]')
            const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl))
            """).render(context: context)
        }

        output += "</html>"

        return output
    }

Some of the code should go into the body render function.

Incorrect path to static files

After building, the path generated in the index.html file is: /css/bootstrap.min.css instead of: css/bootstrap.min.css, which causes a loading issue with the style.

Found typos in comments

Hello though it's minor, I found a typo in the comments at Button elements.

Should be change defaut to default.

image

Swift 6 build fails

I thought this is interesting. It doesn't find the URL extension when compiling with the Swift 6 keychain.
The output is:

Building for debugging...
[0/5] Write sources
[1/5] Write swift-version-6A63A117629E05AE.txt
error: emit-module command failed with exit code 1 (use -v to see invocation)
[3/7] Emitting module IgniteStarter
/Users/laurentb/Developer/Ignite/ExampleSite/Sources/Site.swift:20:15: error: ambiguous use of 'init(_:)'
18 |     var name = "Hello World"
19 |     var titleSuffix = "My Awesome Site"
20 |     var url = URL("https://www.example.com")
   |               `- error: ambiguous use of 'init(_:)'
21 |     var builtInIconsEnabled = true

Swift 5.10 has no problem with it!

Markdown "could not be parsed" because cannot determine file's encoding ..

I seem to enjoy exploring dark corners!

I added an old file, slightly edited to Markdown format, to my Contents and Ignite reported "Markdown could not be parsed" ..

Making a long story short, the code below, in MarkdownToHTML.swift was failing on the try String(contentsOf: url) call. The reason was that this was a seriously old file (from 1993), encoded as Mac OS Roman and Swift couldn't make a String from it. I suspect the file actually violated that encoding so, strictly, failing to get a String out of it was correct.

    public init(url: URL, removeTitleFromBody: Bool) throws {
        do {
            self.removeTitleFromBody = removeTitleFromBody
            let markdown = try String(contentsOf: url)      <--
            let processed = processMetadata(for: markdown)
            let document = Document(parsing: processed)
            body = visit(document)

Annoyingly, I've not been able to reproduce the error yet (I fixed the file's encoding, and can't un-fix it!). When I can generate a 'bad encoding' file, or re-retrieve that old file from the shadows, and make the error happen in a test, I'll submit a patch. I think it'd be good for the throw/catch to distinguish "garbage data" from "can't parse" especially in this case, where the file was visually perfect.


This is an awful arcane scenario, so much so it may not be worth changing anything to attend to it. I've entered it as an issue because (a) someone, someday may trip over it and read here for clues and (b) it's easy to eliminate any such future confusion, so I will (if @twostraws agrees).

[FR]: Making the buildDirectory changeable

Nice to meet you! Thank you for the wonderful performance at try!Swift. I'm fascinated by the Ignite presentations! 👏

Problem

I am currently working on creating and deploying a hosting server and web page using only Swift, by combining Vapor and Ignite. I tried to host a web page built with Ignite on Vapor and deploy it to Google Cloud Run, but encountered a strange issue. The issue is that the "Build" directory generated by Ignite is not uploaded for some reason when using the gcloud source upload command. (As a test, renaming it to "Workspace" or "Public" allowed successful uploads.) 🤔

Feature Request

Therefore, I would like to propose a fix to pass the buildDirectoryPath to the publish method of the Site.

implementation
// PublishingContext.swift

// Existing Implementation
    init(for site: any Site, rootURL: URL) throws {
        ...
        buildDirectory = rootDirectory.appending(path: "Build")

        try parseContent()
    }

    init(for site: any Site, from file: StaticString) throws {
        ...

        buildDirectory = rootDirectory.appending(path: "Build")

        try parseContent()
    }

// Alternative Implementation
    init(for site: any Site, rootURL: URL, buildDirectoryPath: String = "Build") throws {
        ...
        buildDirectory = rootDirectory.appending(path: buildDirectoryPath)

        try parseContent()
    }

    init(for site: any Site, from file: StaticString, buildDirectoryPath: String = "Build") throws {
        ...

        buildDirectory = rootDirectory.appending(path: buildDirectoryPath)

        try parseContent()
    }


// Site.swift

// Existing Implementation
public protocol Site {
    ...
    func publish(from file: StaticString) throws
}

extension Site {
    public func publish(from file: StaticString = #file) throws {
        let context = try PublishingContext(for: self, from: file)
        ...
    }
}

// Alternative Implementation
public protocol Site {
    ...
    func publish(from file: StaticString, buildDirectoryPath: String) throws
}

extension Site {
    ...
    public func publish(from file: StaticString = #file, buildDirectoryPath: String = "Build") throws {
        let context = try PublishingContext(for: self, from: file, buildDirectoryPath: buildDirectoryPath)
        ...
    }
}
Usage
let site = ExampleSite()

do {
    try site.publish(buildDirectoryPath: "Public")
} catch {
    print(error.localizedDescription)
}

Your consideration would be greatly appreciated 🙌

How To Deploy Ignite Website

Hey @twostraws, thank you so much for such a great looking library, I've been playing around with it today in earnest and hoping to use it for building a couple of static websites!

I was trying to figure out the best way to deploy a website built with Ignite and didn't see any instructions so I decided to take the IgniteSamples project and use it's Build folder as a baseline for testing. I uploaded the folder directly to Cloudflare Pages (which serves static websites), including everything inside like the index.html, feed.rss, and all of the subdirectories to see if the process was that simple.

Unfortunately the result was a website that wouldn't load, and I still am not sure how to deploy an Ignite site. It's quite possible that I'm doing something incorrectly so I was wondering if you could perhaps share some advice or documentation on the matter?

Thank you again, looking forward to playing more with Ignite!

Feature Request: Hooks to patch in alternate Components for Markdown tags.

Purpose

When working on with Markdown, there are sometimes alternate dialects that you'd like to handle. These might simply be as simple as the language-tags on code-blocks, as complicated as custom sorting tools for Markdown Tables, and often these are project specific tweaks that wouldn't be appropriate to merge into the core Ignite library.

Proposed Implementation

In this module, there are a ton of visit* methods that each render raw html.
https://github.com/twostraws/Ignite/blob/main/Sources/Ignite/Rendering/MarkdownToHTML.swift

It'd be great if there was a mapping step, where instead of directly emitting strings, users could hook full Ignite components.

// Current Implementation
func visitOrderedList(_ orderedList: Markdown.OrderedList) -> String {
  var result = "<ol>"

  for listItem in orderedList.listItems {
    result += visit(listItem)
  }

  result += "</ol>"
  return result
}

// Instead:
func visitOrderedList(_ orderedList: Markdown.OrderedList) -> Element {
  return (tagOverrides.OrderedList ?? MarkdownOrderedList)(listItems: visit(orderedList.listItems))
}
// Where tagOverrides obviously needs some way to be populated by the project -- ideally even allowing for different patches in different content directories.

Note: I think this should emit Element instead of String to allow these components to play nice with #3 and #2 -- Otherwise Markdown pages wouldn't be able to have a hypothetical AutomaticOutline static-component.

Alternatives Considered

  • Don't let people tweak the rendered tags 😢
  • Let people provide an alternative MarkdownVisitor implementation -- this would be clunky, but probably would work, but would require much more patching from the consumer code.

Strange problem with IgniteStarter and RegexBuilder

I have the following RegexBuilder:

import RegexBuilder

let regex = Regex {
    "[img:"
    Capture{
        ZeroOrMore{
            /./		      ///<- Operator with postfix spacing cannot start a subexpression
        }
    }
    "]"
}
.anchorsMatchLineEndings()

However for some reason I get an error when trying to build the IgniteStarter project with this specific regex included. This regex works fine in a new CLI project, in the Swift Playground, and in one of my own projects ( not based on Ignite ).

I am trying to capture the text between [img: Some Text] in a markdown file.
I tried a different RegexBuilder as an experiment and it worked fine.

I was going to ask about it on the Swift forums but since it only seems to happen with Ignite I thought I ask here first. I’m thinking it might be a package project thing but I’m not familiar enough with how packages and RegexBuilders work to see what might be going on and to formulate a decent question over there.

Anyway I thought you'd like to know!

Feature / Image Content Mode

I would like to introduce a SwiftUI-like aspectRatio(_:contentMode:) function for images. For example to create square profile image where the source is not square. I found that object-fit-cover on Bootstraps image class in combination with a Group with the desired aspect ratio works great.

I'm wondering if this is the right approach and if an extension on BlockElement with a type constraint for Image is preferable or or a dedicated protocol. The latter has the advantage that object-fit-cover only has an effect for image and video types.

enum ContentMode {
    case fit, fill

    var htmlClass: String {
        "object-fit-\(self == .fill ? "cover" : "contain")"
    }
}

extension BlockElement where Self == Image {
    func aspectRation(_ ratio: AspectRatio, contentMode: ContentMode) -> some BlockElement {
        Group {
            self.class(contentMode.htmlClass)
        }
        .aspectRatio(ratio)
    }
}

// OR

protocol MediaContent: BlockElement { }
extension Image: MediaContent { }
extension Video: MediaContent { }

extension MediaContent {
    func aspectRation(_ ratio: AspectRatio, contentMode: ContentMode) -> some BlockElement {
        Group {
            self.class(contentMode.htmlClass)
        }
        .aspectRatio(ratio)
    }
}

Change to `enum Target` for `case blank`

While I understand that .target(.blank) open a new window I suggest a name change so that it would read better if .newWindow

At present

Link("HWS", target: "https://www.hackingwithswift.com")
  .target(.blank)

Proposed

Link("HWS", target: "https://www.hackingwithswift.com")
 .target(.newWindow)

or just add a new enum case for this with same to prevent breaking code already written

Making a site in a subdirectory

I'd like to use Ignite to build a sub-site that doesn't live directly under the root URL but under a subdirectory of that. I've hunted around to see if that is catered for in the existing code base but not found it (which might easily be a result of my not looking hard enough).

I saw the PR "Making the buildDirectory changeable #16" and thought that might be a way to accomplish my goal by setting PublishingContext(.., buildDirectoryPath="subdir/Build") but, no. Similarly, I tried setting Site.url = https://example.com/subdir but, no there too.

Building a site and placing all its files into a subdirectory doesn't work because assets, css, etc, being referenced as, /xxx are not found because they're actually at /subdir/xxx. I'm going to dig into this more and submit a PR, if necessary, but wanted to check that I hadn't missed something obvious before setting out.

Feature Request: Custom font support

I tried using a custom font on my website, and then I encountered issues. I'd be awesome to have something like var robotsConfiguration = Robots() but for fonts, and then a Font() object.

I was able to get it working by CSS, adding a .style to the Theme() and then another .style on the text I want to change the font, but it's not an ideal solution, clearly a workaround.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.