Skip to content

Commit

Permalink
Switch publisher to Bootstrap based templates & add dark theme (#302)
Browse files Browse the repository at this point in the history
Signed-off-by: Igor Shishkin <me@teran.ru>
  • Loading branch information
teran authored Jan 2, 2025
1 parent d6e5ff2 commit 269fde9
Show file tree
Hide file tree
Showing 21 changed files with 595 additions and 138 deletions.
8 changes: 7 additions & 1 deletion cmd/publisher/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ type config struct {
VersionsPerPage uint64 `envconfig:"VERSIONS_PER_PAGE" default:"50"`
ObjectsPerPage uint64 `envconfig:"OBJECTS_PER_PAGE" default:"50"`
ContainersPerPage uint64 `envconfig:"CONTAINERS_PER_PAGE" default:"50"`

MaxPagesInPagination uint64 `envconfig:"MAX_PAGES_IN_PAGINATION" default:"5"`
DefaultTheme htmlPresenter.Theme `envconfig:"DEFAULT_THEME" default:"dark"`
}

func main() {
Expand Down Expand Up @@ -126,7 +129,10 @@ func main() {

publisherSvc := service.NewPublisher(repo, blobRepo, cfg.VersionsPerPage, cfg.ObjectsPerPage, cfg.ContainersPerPage)

p := htmlPresenter.New(publisherSvc, cfg.HTMLTemplateDir, cfg.StaticDir, cfg.BLOBS3PreserveSchemeOnRedirect)
p := htmlPresenter.New(publisherSvc, cfg.HTMLTemplateDir, cfg.StaticDir, cfg.BLOBS3PreserveSchemeOnRedirect, htmlPresenter.DisplayConfig{
DefaultTheme: cfg.DefaultTheme,
MaxPagesInPagination: cfg.MaxPagesInPagination,
})
p.Register(e)

g.Go(func() error {
Expand Down
37 changes: 34 additions & 3 deletions dockerfiles/Dockerfile.publisher
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,45 @@ FROM alpine:3.20.3 AS certificates
RUN apk add --update --no-cache \
ca-certificates=20240705-r0

FROM scratch
FROM index.docker.io/library/node:22.12.0 AS depsbuilder

RUN mkdir /src
WORKDIR /src
RUN npm install \
bootstrap@5.3.3 \
bootstrap-icons@1.11.3

FROM index.docker.io/library/node:22.12.0 AS tsbuilder

RUN mkdir /src
WORKDIR /src
RUN npm install -g \
typescript@5.7.2
COPY publisher/presenter/html/static/scripts /src/scripts
RUN tsc scripts/index.ts --strict --removeComments --outDir /build

FROM ubuntu:24.04

RUN mkdir -p \
/static/archived/scripts \
/static/archived/styles


COPY dockerfiles/rootfs/etc/passwd /etc/passwd
COPY dockerfiles/rootfs/etc/group /etc/group

COPY --from=certificates /etc/ssl/cert.pem /etc/ssl/cert.pem
COPY --from=certificates --chown=root:root --chmod=0644 /etc/ssl/cert.pem /etc/ssl/cert.pem
COPY --chmod=0755 --chown=root:root dist/archived-publisher_linux_amd64_v3/archived-publisher /archived-publisher
COPY --chmod=0644 --chown=root:root publisher/presenter/html/templates /templates
COPY --chmod=0755 --chown=root:root publisher/presenter/html/templates /templates
COPY --chmod=0755 --chown=root:root publisher/presenter/html/static /static/archived

COPY --from=tsbuilder --chown=root:root --chmod=0644 /build /static/archived/scripts

COPY --from=depsbuilder --chown=root:root /src/node_modules/bootstrap/dist /static/bootstrap
COPY --from=depsbuilder --chown=root:root /src/node_modules/@popperjs/core/dist/umd /static/popperjs
COPY --from=depsbuilder --chown=root:root /src/node_modules/bootstrap-icons/bootstrap-icons.svg /static/bootstrap-icons/bootstrap-icons.svg
COPY --from=depsbuilder --chown=root:root /src/node_modules/bootstrap-icons/font /static/bootstrap-icons/font
COPY --from=depsbuilder --chown=root:root /src/node_modules/bootstrap-icons/icons /static/bootstrap-icons/icons

ENV HTML_TEMPLATE_DIR=/templates
ENV STATIC_DIR=/static
Expand Down
98 changes: 57 additions & 41 deletions publisher/presenter/html/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,33 @@ type Handlers interface {
Register(e *echo.Echo)
}

type Theme string

const (
ThemeDark Theme = "dark"
ThemeLight Theme = "light"
)

type DisplayConfig struct {
DefaultTheme Theme
MaxPagesInPagination uint64
}

type handlers struct {
svc service.Publisher
staticDir string
templateDir string
preserveSchemeOnRedirect bool
dc DisplayConfig
}

func New(svc service.Publisher, templateDir, staticDir string, preserveSchemeOnRedirect bool) Handlers {
func New(svc service.Publisher, templateDir, staticDir string, preserveSchemeOnRedirect bool, dc DisplayConfig) Handlers {
return &handlers{
svc: svc,
staticDir: staticDir,
templateDir: templateDir,
preserveSchemeOnRedirect: preserveSchemeOnRedirect,
dc: dc,
}
}

Expand All @@ -52,13 +66,15 @@ func (h *handlers) NamespaceIndex(c echo.Context) error {
}

type data struct {
Title string
Namespaces []string
Title string
DefaultTheme Theme
Namespaces []string
}

return c.Render(http.StatusOK, "namespace-list.html", &data{
Title: "Namespace index",
Namespaces: namespaces,
Title: "Namespace index",
DefaultTheme: h.dc.DefaultTheme,
Namespaces: namespaces,
})
}

Expand Down Expand Up @@ -86,19 +102,19 @@ func (h *handlers) ContainerIndex(c echo.Context) error {
}

type data struct {
Title string
CurrentPage uint64
PagesCount uint64
Namespace string
Containers []models.Container
Title string
DefaultTheme Theme
Pagination Pagination
Namespace string
Containers []models.Container
}

return c.Render(http.StatusOK, "container-list.html", &data{
Title: fmt.Sprintf("Container index (%s)", namespace),
CurrentPage: page,
PagesCount: pagesCount,
Namespace: namespace,
Containers: containers,
Title: fmt.Sprintf("Container index (%s)", namespace),
DefaultTheme: h.dc.DefaultTheme,
Pagination: NewPagination(pagesCount, page, h.dc.MaxPagesInPagination, fmt.Sprintf("/%s/", namespace)),
Namespace: namespace,
Containers: containers,
})
}

Expand Down Expand Up @@ -127,21 +143,21 @@ func (h *handlers) VersionIndex(c echo.Context) error {
}

type data struct {
Title string
CurrentPage uint64
PagesCount uint64
Namespace string
Container string
Versions []models.Version
Title string
DefaultTheme Theme
Pagination Pagination
Namespace string
Container string
Versions []models.Version
}

return c.Render(http.StatusOK, "version-list.html", &data{
Title: fmt.Sprintf("Version index (%s/%s)", namespace, container),
CurrentPage: page,
PagesCount: pagesCount,
Namespace: namespace,
Container: container,
Versions: versions,
Title: fmt.Sprintf("Version index (%s/%s)", namespace, container),
DefaultTheme: h.dc.DefaultTheme,
Pagination: NewPagination(pagesCount, page, h.dc.MaxPagesInPagination, fmt.Sprintf("/%s/%s/", namespace, container)),
Namespace: namespace,
Container: container,
Versions: versions,
})
}

Expand Down Expand Up @@ -171,22 +187,22 @@ func (h *handlers) ObjectIndex(c echo.Context) error {
}

type data struct {
Title string
CurrentPage uint64
PagesCount uint64
Namespace string
Container string
Version string
Objects []string
Title string
DefaultTheme Theme
Pagination Pagination
Namespace string
Container string
Version string
Objects []string
}
return c.Render(http.StatusOK, "object-list.html", &data{
Title: fmt.Sprintf("Object index (%s/%s/%s)", namespace, container, version),
CurrentPage: page,
PagesCount: pagesCount,
Namespace: namespace,
Container: container,
Version: version,
Objects: objects,
Title: fmt.Sprintf("Object index (%s/%s/%s)", namespace, container, version),
DefaultTheme: h.dc.DefaultTheme,
Pagination: NewPagination(pagesCount, page, h.dc.MaxPagesInPagination, fmt.Sprintf("/%s/%s/%s/", namespace, container, version)),
Namespace: namespace,
Container: container,
Version: version,
Objects: objects,
})
}

Expand Down
5 changes: 4 additions & 1 deletion publisher/presenter/html/handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,10 @@ func (s *handlersTestSuite) SetupTest() {

s.serviceMock = service.NewMock()

s.handlers = New(s.serviceMock, "templates", "static", true)
s.handlers = New(s.serviceMock, "templates", "static", true, DisplayConfig{
DefaultTheme: ThemeDark,
MaxPagesInPagination: 5,
})
s.handlers.Register(e)

s.srv = httptest.NewServer(e)
Expand Down
70 changes: 70 additions & 0 deletions publisher/presenter/html/pagination.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package html

import "strconv"

type Pagination struct {
HasPrevious bool
PreviousPageNum uint64
PreviousPageURL string
Pages []Page
HasNext bool
NextPageNum uint64
NextPageURL string
}

type Page struct {
IsCurrent bool
Number uint64
URL string
}

func NewPagination(total, current, maxPages uint64, pageURL string) Pagination {
pages := []Page{}
max := current + maxPages
if current+maxPages > total {
max = total
}
for i := current; i <= max; i++ {
isCurrent := false
if i == current {
isCurrent = true
}
pages = append(pages, Page{
IsCurrent: isCurrent,
Number: i,
URL: pageURL + "?page=" + strconv.FormatUint(i, 10),
})
}

var (
hasPrevious bool
previousPageNum uint64
previousPageURL string
)
if current > 1 {
hasPrevious = true
previousPageNum = current - 1
previousPageURL = pageURL + "?page=" + strconv.FormatUint(previousPageNum, 10)
}

var (
hasNext bool
nextPageNum uint64
nextPageURL string
)
if max < total {
hasNext = true
nextPageNum = current + maxPages + 1
nextPageURL = pageURL + "?page=" + strconv.FormatUint(nextPageNum, 10)
}

return Pagination{
HasPrevious: hasPrevious,
PreviousPageNum: previousPageNum,
PreviousPageURL: previousPageURL,
Pages: pages,
HasNext: hasNext,
NextPageNum: nextPageNum,
NextPageURL: nextPageURL,
}
}
27 changes: 27 additions & 0 deletions publisher/presenter/html/pagination_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package html

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestPagination(t *testing.T) {
r := require.New(t)

pagination := NewPagination(305, 10, 3, "/some/page")
r.Equal(Pagination{
HasPrevious: true,
PreviousPageNum: 9,
PreviousPageURL: "/some/page?page=9",
Pages: []Page{
{IsCurrent: true, URL: "/some/page?page=10", Number: 10},
{IsCurrent: false, URL: "/some/page?page=11", Number: 11},
{IsCurrent: false, URL: "/some/page?page=12", Number: 12},
{IsCurrent: false, URL: "/some/page?page=13", Number: 13},
},
HasNext: true,
NextPageNum: 14,
NextPageURL: "/some/page?page=14",
}, pagination)
}
26 changes: 26 additions & 0 deletions publisher/presenter/html/static/scripts/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
window.addEventListener('load', () => {
const currentSwitch = localStorage.getItem('lightSwitch')?.toString()
const htmlTag = document.getElementById('html');
const lightSwitch = document.getElementById('lightSwitch');

if (currentSwitch) {
htmlTag?.setAttribute('data-bs-theme', currentSwitch);
}

lightSwitch?.addEventListener('click', () => {
if (document.getElementById('html')?.getAttribute('data-bs-theme')?.toString() == "dark") {
htmlTag?.setAttribute('data-bs-theme', 'light');
lightSwitch?.classList.remove('dark');
lightSwitch?.classList.add('light');

localStorage.setItem('lightSwitch', 'light');
return
}
htmlTag?.setAttribute('data-bs-theme', 'dark');
lightSwitch?.classList.remove('light');
lightSwitch?.classList.add('dark');

localStorage.setItem('lightSwitch', 'dark');
return
});
});
6 changes: 6 additions & 0 deletions publisher/presenter/html/static/styles/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.container {
margin: 15px;
}
nav.pagination {
margin-left: 45px;
}
19 changes: 13 additions & 6 deletions publisher/presenter/html/templates/404.html
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Resource not found</title>
</head>
<body>

<head>
<title>Resource not found</title>
</head>

<body>
<div class="container">
<h1>404 Not Found</h1>
<p>
There is not the resource you are looking for
</p>
<hr>
</div>
<hr>
<div class="container">
Powered by <a href="https://github.com/teran/archived" target="_blank" rel="noopener">archived</a>
</body>
</div>
</body>

</html>
Loading

0 comments on commit 269fde9

Please sign in to comment.