Skip to content

vdhamer/Photo-Club-Hub-HTML

Repository files navigation

Version Contributors Forks Stargazers Issues Discussions MIT License

Sample output website Sample output website

Photo-Club-Hub-HTML

This MacOS app generates static websites that allow photography clubs to showcase the portfolios of their members.

Photo Club Hub HTML has a companion app named vdhamer/Photo-Club-Hub for iOS and iPadOS. This MacOS version of the app supports users with Android phones, PCs, Macs, and many other platforms. This version is functionally comparable to the iOS version (comparison below), but it works very differently: the app generates cross-linked HTML pages (on a Mac) that can then be viewed on e.g. an Android phone.

How it works

The data model (logical)

The concept behind both apps is to provide a (central) portal to view image portfolios that are managed by individual photo clubs.

The data rendered in both apps is organized as a 4-level hierarchy of data files that each contain (JSON) lists of items:

Level Typical number of files Files are lists of Files are maintained Input data format
3 1000+ Images per photographer by the clubs .html
2 100+ Members per club by the clubs .level2.json
1 10+ Clubs per region centrally .level1.json
0 dozens supported Expertise tags centrally .level0.json

Layers 1-3 form a tree structure: a club Member can show a portfolio containing multiple Images. A Club typically has a dozen or more Members. A photographer can be a member of one or more clubs. To simplify data management and data ownership, Clubs can also be organized into a tree structure (e.g. a node per country, district, etc).

Loading data (physical)

Technically the iOS app downloads the required JSON data files at startup and uses these to populate the user interface on an iPhone or iPad. Furthermore, the iOS app uses an in-app database (currently Core Data) that persists the data downloaded during previous sessions. This allows the app to already display more or less up to date information while refreshing the information. Any changes to the information are propagated to the (SwiftUI) user interface.

The MacOS version of the app reads the same JSON data files at startup (but without persistent storage) and converts them into static HTML pages. The static HTML generation is implemented using twostraws/ignite. These generated HTML pages can be hosted on any HTTP server and then viewed and navigated using a browser on any platform. These generated HTML pages can also be integrated into an existing (e.g. WordPress, Joomla) website by simple links from the existing pages or an existing menu to the newly generated pages.

Because the HTML pages are static, the generator app should ideally be rerun whenever the club data is updated. This might be once a year or once a month, for example when the list of club members changes. This can replace similar updating to traditional (non-generated) web pages but - because the data comes from a single data source - there is no data copying with associated risk of errors.

Running the app

Generation commands

Screenshot of MacOS app

The Build HTML menu at the top-right allows you to choose which kinds of HTML pages to generate:

  • A list of available expertise tags for photographers ("L0: expertises")
  • A list of clubs ("L1: clubs")
  • A list of museums ("L1: museums"). The data exists, but HTML generation hasn't been implemented yet, so it is still disabled.
  • A list of members for a selected club ("L2: club members"). This requires selecting a club from the sidebar.

During website generation here is no proper feedback yet to the user (but the site is generated in less than a second).

The path to the directory with the newly generated pages will resemble /Users/peter/Library/Containers/com.vdHamer.Photo-Club-Hub-HTML/Data/Build.

Hosting

Screenshot 2026-03-23 at 17 15 43

In the Settings... menu you can select whether you want to generate this for a localhost:8000 web server or for a remote host.

For a remote host, the app currently requires you to separately copy the generated directory content to that host. For this you can use an FTP client like Filezilla. The FTP client will require you to know the remote address and the ftp credentials for that site. Once the directory content is copied to your remote server, you can view it in a browser and optionally link to it from an existing website.

Comparing both apps

App versus HTML comparison

This website generator serves as an alternative for the Photo Club Hub iOS app: it allows users to view the images on devices running Android, Windows, MacOS, etc.

Photo Club Hub Photo Club Hub HTML
Runs on iOS, iPadOS, (MacOS, VisionOS) all major browsers
Available via App Store URLs
Mobile friendly yes yes
Lists clubs yes yes
Lists photo museums yes -✲
Lists current club members yes yes
Lists former club members optionally optionally
Displays member portfolios yes yes
Linkable member portfolios partially✲ yes
Autoplay of portfolios yes yes
Content updated whenever club updates its data whenever the data is regenerated
Maps showing clubs yes -
Languages English, Dutch✲ English, Dutch✲
Internal database yes -
Data caching partially✲ by browser
Concurrent data fetching yes yes
Open source yes yes

✲ = might be improved or supported in the future

Technology stack

Technology Description Source
twostraws/Ignite static website generator Github (Paul Hudson)
SwiftUI UI framework Apple
Core Data data storage framework Apple
SwiftyJSON/SwifyJSON JSON parsing Github

Static sites and Ignite

This app runs on MacOS and generates a local directory with a few files and subdirectories (CSS, Javascript, image assets). These are then copied over to a club's existing server via e.g. FTP. Technically the files simply need to be hosted on an HTTP server such as a club's existing WordPress site.

The data being displayed on the individual HTML sites can get updated say 10 times per year. Because the update frequency is relatively low, and because the owners of the data are assumed to have limited "computer" expertise, it is best to generate static websites. This limits the hasstle to uploading a file to a directory and associated username/password. This should be easier and more robust than having custom server software that generates web pages on request.

Ignite allows us to create a tool in pure Swift that generates the content of the static website without having to do HTML/CSS/Javascript coding. Ignite is essentially a declarative higher-level description (Result Builder) that resembles data more than it resembles code.

Why have separate repo's?

From a technical perspective, Photo Club Hub and Photo Club HTML could have been implemented as a single repository with two (very) different targets that run on different platforms.

We chose to split the code into multiple repos to lower the barrier to contribute to either app. That gives us two respos. But common code is being factored out into a package in order to eliminate duplication of large amounts of code. So there will ultimately be three repositories in GitHub:

  • Photo Club Hub (for iOS, interactive browing),
  • Photo Club Hub HTML (for macOS, to generate static websites)
  • Photo Club Hub Data (used by both to load and update JSON data into the Core Data database)

Will 3 hierarchy levels be enough?

Initially there are only a handful of pilot clubs involved. Data for a hundred clubs at <1 kB each can be contained in a single Level 1 file, especially when loaded in the background and cached using Core Data.

To split up the level1.json file we allow the root.level1.json file to contain URL links to additional level1.json files. This allows the root file to support a path like root/Netherlands or root/Japan/Tokio. As a side benefit, this approach could allow a user to choose which banches of the level1 tree to load. This hasn't been implemented yet.

Extra Level 1 sublevels should match the way the data and responsibilities are organized: essentially the tree structure forms a chain of trust. A "rogue" or just non-club site will only be reachable if there is a chain of valid links between the default root and that site. Thus a site with questionable content (say my cat photos) can thus be isolated by removing a link. But it would still be reachable using its URL (path like cats_and_more_cats/Berlin). This is not a problem as long as the hierarchy has a single root node and a single path to any other node. Conceivably both apps could someday allow an alternative root node to be selected for non-photo-club usages. For now this is only possible by changing a constant in the source code.

Roadmap

  • Fix the Ignite code (accepted PR for twostraws/Ignite) so that Ignite can be imported as a regular Swift package.
  • Load the membership list from a .level2.json file. Currently the app contains a hardcoded partial copy of this data.
  • localize the generated website to support multiple languages (initially English and Dutch).
  • localize the app's UI to support English and Dutch (for now there isn't too much of a UI).
  • support for the (new, Level 0) data that allows photographers to be associated with keywords.
  • factor out common code between both apps into a Swift Package Manager package (almost done)
  • allow the user to select the club for which to generate the local site (currently hardcoded constant, almost done).
  • generate a static site that can serve as index of supported clubs (Level 1 data).
  • generate index pages listing photographers associated with a particiular expertise
  • generate all clubs in bulk instead of one club at a time

It would be nice to have an app for data enty/editing (rather than editing JSON files), but that would require adding another repo.

(back to top)

About

The companion app for the Photo Club Hub app. This app generates static sites (using twostraws/Ignite) for platforms like Android or Windows.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages