Skip to content

Commit

Permalink
Major overhaul of Urchin
Browse files Browse the repository at this point in the history
- Added TailwindCSS to Urchin.
- Updated Makefile to download TailwindCSS (currently only Linux is supported)
- Refactored templates to share similar logic between templates.
- Redesigned UI for Urchin.
- Added layout page shared between all sub pages.
- Added dark mode support.
- Added new `renderHtml` method to reduce duplicate code in go.
- Added self-designed minimalistic 'sea urchin' favicon. :D
- Added missing sites `about` and `services`.
- Added `Not Found` handling if a resource is requested that is not present, displaying an error message while keeping the layout page.
- Restructured `static` folder to include stylesheets, scripts and assets.
  • Loading branch information
AlDu2407 committed Nov 3, 2024
1 parent 8e125a9 commit 71695d1
Show file tree
Hide file tree
Showing 38 changed files with 381 additions and 303 deletions.
2 changes: 1 addition & 1 deletion .air.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ tmp_dir = "tmp"
exclude_unchanged = false
follow_symlink = false
include_dir = []
include_ext = ["go", "tpl", "tmpl", "templ", "html"]
include_ext = ["go", "tpl", "tmpl", "templ", "html", "js"]
include_file = []
kill_delay = "0s"
log = "build-errors.log"
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,9 @@ images/


tests/helpers/migrations

# The name of the TailwindCSS CLI
tailwindcss

# Generated TailwindCSS styles
static/css/style.css
2 changes: 0 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
"mode": "auto",
"program": "${workspaceFolder}/cmd/urchin",
"cwd": "${workspaceFolder}",
"envFile": "${workspaceFolder}/envfile",
"args": [
"--config",
"${workspaceFolder}/urchin_config.toml"
Expand All @@ -24,7 +23,6 @@
"mode": "auto",
"program": "${workspaceFolder}/cmd/urchin-admin",
"cwd": "${workspaceFolder}",
"envFile": "${workspaceFolder}/envfile",
"args": [
"--config",
"${workspaceFolder}/urchin_config.toml"
Expand Down
9 changes: 8 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ build: prepare_env
$(TEMPL) generate
GIN_MODE=release $(GOCMD) build -ldflags "-s" -v -o $(BUILD_DIR)/$(BINARY_NAME) $(URCHIN_DIR)
GIN_MODE=release $(GOCMD) build -ldflags "-s" -v -o $(BUILD_DIR)/$(ADMIN_BINARY_NAME) $(URCHIN_ADMIN_DIR)
./tailwindcss -i ./static/css/custom.css -o ./static/css/style.css --minify

test: prepare_env
$(GOCMD) test -v ./...
Expand All @@ -26,9 +27,15 @@ clean:
$(GOCMD) clean
rm -rf $(BUILD_DIR)

# TODO: For now we support only the linux version of tailwindcss, has to be updated in the future to support Windows and MacOS as well.
install-tools:
go install github.com/pressly/goose/v3/cmd/[email protected]
go install github.com/a-h/templ/cmd/[email protected]
go install github.com/cosmtrek/[email protected]

.PHONY: all build test clean
install-tailwindcss:
curl -sLO https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64
chmod +x tailwindcss-linux-x64
mv tailwindcss-linux-x64 tailwindcss

.PHONY: all build test clean install-tailwindcss
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Urchin is a headless CMS (Content Management System) written in Golang, designed
create a website or blog, with any template you like, in only a few
commands.

![Really no head?](static/nohead.gif "So no head meme?")
![Really no head?](static/assets/nohead.gif "So no head meme?")

## Features 🚀

Expand Down Expand Up @@ -122,7 +122,7 @@ The plan is to have two main applications: the public facing application
to serve the content through a website, and the admin application that
can be hidden, where users can modify the settings, add posts, pages, etc.

![diagram of urchin's architecture](static/urchin-architecture.png "Urchin Application Architecture")
![diagram of urchin's architecture](static/assets/urchin-architecture.png "Urchin Application Architecture")

In the above image, you can see the two applications running alongside,
and they share a database connection where the data is actually stored.
Expand Down
12 changes: 12 additions & 0 deletions app/about.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package app

import (
"github.com/gin-gonic/gin"
"github.com/matheusgomes28/urchin/common"
"github.com/matheusgomes28/urchin/database"
"github.com/matheusgomes28/urchin/views"
)

func aboutHandler(c *gin.Context, app_settings common.AppSettings, db database.Database) ([]byte, error) {
return renderHtml(c, views.MakeAboutPage(app_settings.AppNavbar.Links))
}
18 changes: 18 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ func SetupRoutes(app_settings common.AppSettings, database database.Database) *g
cache := MakeCache(4, time.Minute*10, &TimeValidator{})
addCachableHandler(r, "GET", "/", homeHandler, &cache, app_settings, database)
addCachableHandler(r, "GET", "/contact", contactHandler, &cache, app_settings, database)
addCachableHandler(r, "GET", "/about", aboutHandler, &cache, app_settings, database)
addCachableHandler(r, "GET", "/services", servicesHandler, &cache, app_settings, database)
addCachableHandler(r, "GET", "/post/:id", postHandler, &cache, app_settings, database)
addCachableHandler(r, "GET", "/images/:name", imageHandler, &cache, app_settings, database)
addCachableHandler(r, "GET", "/images", imagesHandler, &cache, app_settings, database)
Expand All @@ -45,6 +47,8 @@ func SetupRoutes(app_settings common.AppSettings, database database.Database) *g
// Where all the static files (css, js, etc) are served from
r.Static("/static", "./static")

r.NoRoute(notFoundHandler(app_settings))

return r
}

Expand Down Expand Up @@ -127,3 +131,17 @@ func homeHandler(c *gin.Context, settings common.AppSettings, db database.Databa

return html_buffer.Bytes(), nil
}

func notFoundHandler(app_settings common.AppSettings) func(*gin.Context) {
handler := func(c *gin.Context) {
buffer, err := renderHtml(c, views.MakeNotFoundPage(app_settings.AppNavbar.Links))
if err != nil {
c.JSON(http.StatusInternalServerError, common.ErrorRes("could not render HTML", err))
return
}

c.Data(http.StatusOK, "text/html; charset=utf-8", buffer)
}

return handler
}
9 changes: 1 addition & 8 deletions app/contact.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package app

import (
"bytes"
"encoding/json"
"fmt"
"io"
Expand Down Expand Up @@ -137,11 +136,5 @@ func makeContactFormHandler(app_settings common.AppSettings) func(*gin.Context)

// TODO : This is a duplicate of the index handler... abstract
func contactHandler(c *gin.Context, app_settings common.AppSettings, db database.Database) ([]byte, error) {
index_view := views.MakeContactPage(app_settings.AppNavbar.Links, app_settings.RecaptchaSiteKey)
html_buffer := bytes.NewBuffer(nil)
if err := index_view.Render(c, html_buffer); err != nil {
log.Error().Msgf("could not render: %v", err)
}

return html_buffer.Bytes(), nil
return renderHtml(c, views.MakeContactPage(app_settings.AppNavbar.Links, app_settings.RecaptchaSiteKey))
}
10 changes: 1 addition & 9 deletions app/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,6 @@ func imageHandler(c *gin.Context, app_settings common.AppSettings, database data
AltText: "undefined",
Ext: ext,
}
index_view := views.MakeImagePage(image, app_settings.AppNavbar.Links)
html_buffer := bytes.NewBuffer(nil)

err := index_view.Render(c, html_buffer)
if err != nil {
log.Error().Msgf("Could not render index: %v", err)
return []byte{}, err
}

return html_buffer.Bytes(), nil
return renderHtml(c, views.MakeImagePage(image, app_settings.AppNavbar.Links))
}
9 changes: 1 addition & 8 deletions app/page.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package app

import (
"bytes"
"net/http"

"github.com/gin-gonic/gin"
"github.com/matheusgomes28/urchin/common"
"github.com/matheusgomes28/urchin/database"
"github.com/matheusgomes28/urchin/views"
"github.com/rs/zerolog/log"
)

func pageHandler(c *gin.Context, app_settings common.AppSettings, database database.Database) ([]byte, error) {
Expand All @@ -33,11 +31,6 @@ func pageHandler(c *gin.Context, app_settings common.AppSettings, database datab

// Generate HTML page
page.Content = string(mdToHTML([]byte(page.Content)))
post_view := views.MakePage(page.Title, page.Content, app_settings.AppNavbar.Links)
html_buffer := bytes.NewBuffer(nil)
if err = post_view.Render(c, html_buffer); err != nil {
log.Error().Msgf("could not render: %v", err)
}

return html_buffer.Bytes(), nil
return renderHtml(c, views.MakePage(page.Title, page.Content, app_settings.AppNavbar.Links))
}
8 changes: 1 addition & 7 deletions app/post.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package app

import (
"bytes"
"net/http"

"github.com/gin-gonic/gin"
Expand Down Expand Up @@ -70,11 +69,6 @@ func postHandler(c *gin.Context, app_settings common.AppSettings, database datab

// Generate HTML page
post.Content = string(mdToHTML([]byte(post.Content)))
post_view := views.MakePostPage(post.Title, post.Content, app_settings.AppNavbar.Links)
html_buffer := bytes.NewBuffer(nil)
if err = post_view.Render(c, html_buffer); err != nil {
log.Error().Msgf("could not render: %v", err)
}

return html_buffer.Bytes(), nil
return renderHtml(c, views.MakePostPage(post.Title, post.Content, app_settings.AppNavbar.Links))
}
15 changes: 15 additions & 0 deletions app/renderer.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package app

import (
"bytes"

"github.com/a-h/templ"
"github.com/gin-gonic/gin"
"github.com/rs/zerolog/log"
)

// / This function will render the templ component into
Expand All @@ -11,3 +14,15 @@ func render(c *gin.Context, status int, template templ.Component) error {
c.Status(status)
return template.Render(c.Request.Context(), c.Writer)
}

func renderHtml(c *gin.Context, template templ.Component) ([]byte, error) {
html_buffer := bytes.NewBuffer(nil)

err := template.Render(c, html_buffer)
if err != nil {
log.Error().Msgf("Could not render index: %v", err)
return []byte{}, err
}

return html_buffer.Bytes(), nil
}
12 changes: 12 additions & 0 deletions app/services.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package app

import (
"github.com/gin-gonic/gin"
"github.com/matheusgomes28/urchin/common"
"github.com/matheusgomes28/urchin/database"
"github.com/matheusgomes28/urchin/views"
)

func servicesHandler(c *gin.Context, app_settings common.AppSettings, db database.Database) ([]byte, error) {
return renderHtml(c, views.MakeServicesPage(app_settings.AppNavbar.Links))
}
Binary file added static/assets/favicon.ico
Binary file not shown.
File renamed without changes
File renamed without changes
9 changes: 9 additions & 0 deletions static/css/custom.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/* Loading tailwind builtins. All custom rules have to be added in here. */
@tailwind base;
@tailwind components;
@tailwind utilities;


body {
background: #E5E5E5;
}
File renamed without changes.
19 changes: 19 additions & 0 deletions static/scripts/application.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
document.getElementById('menu-toggle').addEventListener('click', function () {
const menu = document.getElementById('mobile-menu');
menu.classList.toggle('hidden')
});

const themeToggle = document.getElementById('theme-toggle');
const lightIcon = document.getElementById('light-icon');
const darkIcon = document.getElementById('dark-icon');

themeToggle.addEventListener('click', function () {
// Toggle dark class on HTML element
document.documentElement.classList.toggle('dark');
});

document.getElementById('demo-form').addEventListener('submit', function() {
const event = new Event('verified');
const elem = document.querySelector("#demo-form");
elem.dispatchEvent(event);
})
File renamed without changes.
File renamed without changes.
33 changes: 33 additions & 0 deletions tailwind.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/** @type {import('tailwindcss').Config} */
export const content = [
"./views/*.templ",
]

export const theme = {
container: {
center: true,
padding: {
DEFAULT: "1rem",
mobile: "1rem",
tablet: "1rem",
desktop: "1rem",
},
},
extend: {
colors: {
pastel: {
blue: '#AEC6CF',
purple: '#CBAACB',
pink: '#FFB6C1',
orange: '#FFDAB9',
green: '#C4E17F',
yellow: '#FFDD94',
gray: '#E5E5E5'
}
}
}
}

export const darkMode = 'selector'

export const plugins = [require("@tailwindcss/forms"), require("@tailwindcss/typography")]
9 changes: 9 additions & 0 deletions views/about.templ
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package views

import (
. "github.com/matheusgomes28/urchin/common"
)

templ MakeAboutPage(links []Link) {
@MakeLayout("About", links, makeUnderConstruction())
}
4 changes: 2 additions & 2 deletions views/contact-failure.templ
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package views

templ MakeContactFailure(email string, err string) {
<h2 style="color: #720d0d">Failed to send message from { email }!</h2>
<p>Your message could not be sent. Error: { err }</p>
<h2 class="text-2xl text-bold text-red-800 mb-4">Failed to send message from { email }!</h2>
<p class="text-xl text-bold">Your message could not be sent. Error: <span class="text-extrabold">{ err }</span></p>
}
4 changes: 2 additions & 2 deletions views/contact-success.templ
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package views

templ MakeContactSuccess(email string, name string) {
<h2>Message Sent From { email }!</h2>
<p>Thank you { name }. The message was successfully sent.</p>
<h2>Message Sent From { email }!</h2>
<p>Thank you { name }. The message was successfully sent.</p>
}
Loading

0 comments on commit 71695d1

Please sign in to comment.