mirror of
https://github.com/Theodor-Springmann-Stiftung/musenalm.git
synced 2025-10-29 09:15:33 +00:00
Titelzeile
This commit is contained in:
@@ -53,7 +53,7 @@ time = false
|
|||||||
clean_on_exit = true
|
clean_on_exit = true
|
||||||
|
|
||||||
[proxy]
|
[proxy]
|
||||||
app_port = 8080
|
app_port = 8090
|
||||||
enabled = true
|
enabled = true
|
||||||
proxy_port = 8081
|
proxy_port = 8081
|
||||||
|
|
||||||
|
|||||||
@@ -109,7 +109,14 @@ func (app *App) setupTestuser() {
|
|||||||
|
|
||||||
func (app *App) Serve() error {
|
func (app *App) Serve() error {
|
||||||
engine := templating.NewEngine(&views.LayoutFS, &views.RoutesFS)
|
engine := templating.NewEngine(&views.LayoutFS, &views.RoutesFS)
|
||||||
engine.Globals(map[string]interface{}{"isDev": app.MAConfig.Debug})
|
engine.Globals(map[string]interface{}{
|
||||||
|
"isDev": app.MAConfig.Debug,
|
||||||
|
"lang": "de",
|
||||||
|
"site": map[string]interface{}{
|
||||||
|
"title": "Musenalm",
|
||||||
|
"lang": "de",
|
||||||
|
"desc": "Bibliographie deutscher Almanache des 18. und 19. Jahrhunderts",
|
||||||
|
}})
|
||||||
|
|
||||||
// INFO: hot reloading for poor people
|
// INFO: hot reloading for poor people
|
||||||
if app.MAConfig.Debug {
|
if app.MAConfig.Debug {
|
||||||
|
|||||||
@@ -2,11 +2,15 @@ package dbmodels
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"slices"
|
"slices"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/Theodor-Springmann-Stiftung/musenalm/helpers/datatypes"
|
||||||
"github.com/pocketbase/dbx"
|
"github.com/pocketbase/dbx"
|
||||||
"github.com/pocketbase/pocketbase/core"
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
"golang.org/x/text/cases"
|
||||||
"golang.org/x/text/collate"
|
"golang.org/x/text/collate"
|
||||||
"golang.org/x/text/language"
|
"golang.org/x/text/language"
|
||||||
|
"golang.org/x/text/unicode/norm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SeriesEntries map[string][]*REntriesSeries
|
type SeriesEntries map[string][]*REntriesSeries
|
||||||
@@ -19,6 +23,17 @@ func SortSeriessesByTitle(series []*Series) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func BasicSearchSeries(app core.App, query string) ([]*Series, []*Series, error) {
|
func BasicSearchSeries(app core.App, query string) ([]*Series, []*Series, error) {
|
||||||
|
query = strings.TrimSpace(query)
|
||||||
|
query = datatypes.DeleteTags(query)
|
||||||
|
query = datatypes.NormalizeString(query)
|
||||||
|
query = datatypes.RemovePunctuation(query)
|
||||||
|
query = cases.Lower(language.German).String(query)
|
||||||
|
query = norm.NFKD.String(query)
|
||||||
|
|
||||||
|
if query == "" {
|
||||||
|
return []*Series{}, []*Series{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
series, err := TitleSearchSeries(app, query)
|
series, err := TitleSearchSeries(app, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@@ -33,8 +48,20 @@ func BasicSearchSeries(app core.App, query string) ([]*Series, []*Series, error)
|
|||||||
|
|
||||||
func TitleSearchSeries(app core.App, query string) ([]*Series, error) {
|
func TitleSearchSeries(app core.App, query string) ([]*Series, error) {
|
||||||
series := []*Series{}
|
series := []*Series{}
|
||||||
err := app.RecordQuery(SERIES_TABLE).
|
queries := strings.Split(query, " ")
|
||||||
Where(dbx.Like(SERIES_TITLE_FIELD, query).Match(true, true)).
|
q := app.RecordQuery(SERIES_TABLE).
|
||||||
|
Where(dbx.Like(SERIES_TITLE_FIELD, queries[0]).Match(true, true))
|
||||||
|
|
||||||
|
if len(queries) > 1 {
|
||||||
|
for _, que := range queries[1:] {
|
||||||
|
que = strings.TrimSpace(que)
|
||||||
|
if que != "" {
|
||||||
|
q.AndWhere(dbx.Like(SERIES_TITLE_FIELD, que).Match(true, true))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := q.
|
||||||
OrderBy(SERIES_TITLE_FIELD).
|
OrderBy(SERIES_TITLE_FIELD).
|
||||||
All(&series)
|
All(&series)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 19 KiB |
@@ -1,51 +1,64 @@
|
|||||||
const p = "script[xslt-onload]", a = "xslt-template", u = "xslt-transformed", c = /* @__PURE__ */ new Map();
|
const f = "script[xslt-onload]", i = "xslt-template", m = "xslt-transformed", c = /* @__PURE__ */ new Map();
|
||||||
function m() {
|
function u() {
|
||||||
let t = htmx.findAll(p);
|
let t = htmx.findAll(f);
|
||||||
for (let e of t)
|
for (let r of t)
|
||||||
T(e);
|
p(r);
|
||||||
}
|
}
|
||||||
function T(t) {
|
function p(t) {
|
||||||
if (t.getAttribute(u) === "true" || !t.hasAttribute(a))
|
if (t.getAttribute(m) === "true" || !t.hasAttribute(i))
|
||||||
return;
|
return;
|
||||||
let e = "#" + t.getAttribute(a), o = c.get(e);
|
let r = "#" + t.getAttribute(i), o = c.get(r);
|
||||||
if (!o) {
|
if (!o) {
|
||||||
let n = htmx.find(e);
|
let s = htmx.find(r);
|
||||||
if (n) {
|
if (s) {
|
||||||
let l = n.innerHTML ? new DOMParser().parseFromString(n.innerHTML, "application/xml") : n.contentDocument;
|
let l = s.innerHTML ? new DOMParser().parseFromString(s.innerHTML, "application/xml") : s.contentDocument;
|
||||||
o = new XSLTProcessor(), o.importStylesheet(l), c.set(e, o);
|
o = new XSLTProcessor(), o.importStylesheet(l), c.set(r, o);
|
||||||
} else
|
} else
|
||||||
throw new Error("Unknown XSLT template: " + e);
|
throw new Error("Unknown XSLT template: " + r);
|
||||||
}
|
}
|
||||||
let i = new DOMParser().parseFromString(t.innerHTML, "application/xml"), s = o.transformToFragment(i, document), r = new XMLSerializer().serializeToString(s);
|
let a = new DOMParser().parseFromString(t.innerHTML, "application/xml"), e = o.transformToFragment(a, document), n = new XMLSerializer().serializeToString(e);
|
||||||
t.outerHTML = r;
|
t.outerHTML = n;
|
||||||
}
|
}
|
||||||
function f() {
|
function d() {
|
||||||
document.querySelectorAll("template[simple]").forEach((e) => {
|
document.querySelectorAll("template[simple]").forEach((r) => {
|
||||||
let o = e.getAttribute("id"), i = e.content;
|
let o = r.getAttribute("id"), a = r.content;
|
||||||
customElements.define(
|
customElements.define(
|
||||||
o,
|
o,
|
||||||
class extends HTMLElement {
|
class extends HTMLElement {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(), this.appendChild(i.cloneNode(!0)), this.slots = this.querySelectorAll("slot");
|
super(), this.appendChild(a.cloneNode(!0)), this.slots = this.querySelectorAll("slot");
|
||||||
}
|
}
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
let s = [];
|
let e = [];
|
||||||
this.slots.forEach((r) => {
|
this.slots.forEach((n) => {
|
||||||
let n = r.getAttribute("name"), l = this.querySelector(`[slot="${n}"]`);
|
let s = n.getAttribute("name"), l = this.querySelector(`[slot="${s}"]`);
|
||||||
l && (r.replaceWith(l.cloneNode(!0)), s.push(l));
|
l && (n.replaceWith(l.cloneNode(!0)), e.push(l));
|
||||||
}), s.forEach((r) => {
|
}), e.forEach((n) => {
|
||||||
r.remove();
|
n.remove();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function d() {
|
function h() {
|
||||||
m(), htmx.on("htmx:load", function(t) {
|
u(), htmx.on("htmx:load", function(t) {
|
||||||
m();
|
u();
|
||||||
}), f();
|
}), d();
|
||||||
|
}
|
||||||
|
function T(t) {
|
||||||
|
t || (t = window.location.href);
|
||||||
|
const r = document.querySelectorAll("nav");
|
||||||
|
if (r && r.length > 0)
|
||||||
|
for (const o of r)
|
||||||
|
o.querySelectorAll("a, [data-url]").forEach((e) => {
|
||||||
|
if (e.dataset.url && e.dataset.url !== "") {
|
||||||
|
let n = window.location.origin + e.dataset.url;
|
||||||
|
t.startsWith(n) ? e.setAttribute("aria-current", "page") : e.removeAttribute("aria-current");
|
||||||
|
} else e.href && (t.startsWith(e.href) ? e.setAttribute("aria-current", "page") : e.removeAttribute("aria-current"));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
export {
|
export {
|
||||||
d as setup
|
T as setMenuActive,
|
||||||
|
h as setup
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,4 +1,43 @@
|
|||||||
<div class="flex flex-row justify-center mt-8 gap-x-2">
|
<div
|
||||||
<a href="/reihen">Reihen</a>
|
class="pb-1.5 border-b border-zinc-300"
|
||||||
|
x-data="{ openeditionmenu: window.location.pathname.startsWith('/edition/')}">
|
||||||
|
<div class="flex flex-row justify-between">
|
||||||
|
<div>
|
||||||
|
<h1 class="font-bold">{{ .site.title }}</h1>
|
||||||
|
<h2 class="italic">{{ .site.desc }}</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav
|
||||||
|
class="self-end font-serif font-bold flex flex-row gap-x-6 [&>a]:no-underline
|
||||||
|
[&>*]:px-1.5 [&>*]:pt-1 [&>*]:-mb-1.5">
|
||||||
|
<a href="/reihen/">Reihen</a>
|
||||||
<a href="/personen/">Personen</a>
|
<a href="/personen/">Personen</a>
|
||||||
|
<a href="/suche/">Suche</a>
|
||||||
|
<button
|
||||||
|
data-url="/edition/"
|
||||||
|
class="text-slate-600 hover:text-slate-900 hover:cursor-pointer"
|
||||||
|
:class="openeditionmenu? 'bg-slate-200' : 'closed'"
|
||||||
|
@click="openeditionmenu = !openeditionmenu">
|
||||||
|
<i x-show="!openeditionmenu" class="ri-arrow-right-s-fill"></i>
|
||||||
|
<i x-show="openeditionmenu" class="ri-arrow-down-s-fill"></i>
|
||||||
|
Redaktion & Kontakt
|
||||||
|
</button>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
<nav
|
||||||
|
:class="openeditionmenu? 'open' : 'closed'"
|
||||||
|
x-show="openeditionmenu"
|
||||||
|
class="submenu w-full flex flex-row justify-end pt-3 gap-x-6 font-bold font-serif
|
||||||
|
[&>a]:no-underline [&>*]:-mb-1.5">
|
||||||
|
<a href="/edition/einfuehrung/">Einführung</a>
|
||||||
|
<a href="/edition/dokumentation/">Dokumentation</a>
|
||||||
|
<a href="/edition/literatur/">Literatur</a>
|
||||||
|
<a href="/edition/danksagungen/">Danksagungen</a>
|
||||||
|
<a href="/edition/kontakt/">Kontakt</a>
|
||||||
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script type="module">
|
||||||
|
import { setMenuActive } from "/assets/scripts.js";
|
||||||
|
setMenuActive();
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -30,18 +30,14 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="w-full" hx-ext="response-targets" hx-boost="true">
|
<body class="w-full" hx-ext="response-targets" hx-boost="true">
|
||||||
<div class="container flex flex-col min-h-screen max-w-(--breakpoint-2xl) mx-auto">
|
<div class="container flex flex-col min-h-screen max-w-(--breakpoint-xl) mx-auto">
|
||||||
<header>
|
<header class="px-3 py-2.5" id="header">
|
||||||
{{ block "_header" . }}
|
|
||||||
<!-- Default app header... -->
|
|
||||||
{{ end }}
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
{{ block "_menu" . }}
|
{{ block "_menu" . }}
|
||||||
<!-- Default app menu... -->
|
<!-- Default app menu... -->
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</div>
|
</header>
|
||||||
|
|
||||||
|
<div></div>
|
||||||
|
|
||||||
<main class="">
|
<main class="">
|
||||||
{{ block "body" . }}
|
{{ block "body" . }}
|
||||||
|
|||||||
11
views/package-lock.json
generated
11
views/package-lock.json
generated
@@ -10,6 +10,7 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/postcss": "^4.0.0",
|
"@tailwindcss/postcss": "^4.0.0",
|
||||||
|
"daisyui": "^5.0.0-beta.8",
|
||||||
"postcss": "^8.4.47",
|
"postcss": "^8.4.47",
|
||||||
"postcss-cli": "^11.0.0",
|
"postcss-cli": "^11.0.0",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.3.3",
|
||||||
@@ -1143,6 +1144,16 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/daisyui": {
|
||||||
|
"version": "5.0.0-beta.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-5.0.0-beta.8.tgz",
|
||||||
|
"integrity": "sha512-jSokqm5i+Pv1jG80wliNzMHjmcF+iMx5xRUpk0/QExVoVNyQNWeCsaWJQubPvUq7bt9nzSsQTR2uIZBoyIIoaA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/saadeghi/daisyui?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dependency-graph": {
|
"node_modules/dependency-graph": {
|
||||||
"version": "0.11.0",
|
"version": "0.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz",
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/postcss": "^4.0.0",
|
"@tailwindcss/postcss": "^4.0.0",
|
||||||
|
"daisyui": "^5.0.0-beta.8",
|
||||||
"postcss": "^8.4.47",
|
"postcss": "^8.4.47",
|
||||||
"postcss-cli": "^11.0.0",
|
"postcss-cli": "^11.0.0",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.3.3",
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 19 KiB |
@@ -90,4 +90,32 @@ function setup() {
|
|||||||
setup_templates();
|
setup_templates();
|
||||||
}
|
}
|
||||||
|
|
||||||
export { setup };
|
function setMenuActive(url) {
|
||||||
|
if (!url) {
|
||||||
|
url = window.location.href;
|
||||||
|
}
|
||||||
|
const menus = document.querySelectorAll("nav");
|
||||||
|
if (menus && menus.length > 0) {
|
||||||
|
for (const menu of menus) {
|
||||||
|
const links = menu.querySelectorAll("a, [data-url]");
|
||||||
|
links.forEach((link) => {
|
||||||
|
if (link.dataset.url && link.dataset.url !== "") {
|
||||||
|
let fullurl = window.location.origin + link.dataset.url;
|
||||||
|
if (url.startsWith(fullurl)) {
|
||||||
|
link.setAttribute("aria-current", "page");
|
||||||
|
} else {
|
||||||
|
link.removeAttribute("aria-current");
|
||||||
|
}
|
||||||
|
} else if (link.href) {
|
||||||
|
if (url.startsWith(link.href)) {
|
||||||
|
link.setAttribute("aria-current", "page");
|
||||||
|
} else {
|
||||||
|
link.removeAttribute("aria-current");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { setup, setMenuActive };
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
@import 'tailwindcss';
|
@import "tailwindcss";
|
||||||
|
|
||||||
@theme {
|
@theme {
|
||||||
--font-script: Rancho, ui-serif;
|
--font-script: Rancho, ui-serif;
|
||||||
--font-sans: 'Source Sans 3', 'Merriweather Sans', ui-sans-serif;
|
--font-sans: "Source Sans 3", "Merriweather Sans", ui-sans-serif;
|
||||||
--font-serif: 'Merriweather', ui-serif;
|
--font-serif: "Merriweather", ui-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -44,7 +43,7 @@
|
|||||||
h2,
|
h2,
|
||||||
h3,
|
h3,
|
||||||
h4 {
|
h4 {
|
||||||
@apply font-serif font-bold;
|
@apply font-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
@@ -59,8 +58,20 @@
|
|||||||
@apply ml-14 list-disc;
|
@apply ml-14 list-disc;
|
||||||
}
|
}
|
||||||
|
|
||||||
a[aria-current="page"] {
|
nav > * {
|
||||||
@apply text-red-500!;
|
@apply border-b-4 border-transparent hover:!border-zinc-200;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a[aria-current="page"] {
|
||||||
|
@apply text-blue-400;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a[aria-current="page"] {
|
||||||
|
@apply !border-zinc-300;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav.submenu a[aria-current="page"] {
|
||||||
|
@apply text-blue-400;
|
||||||
}
|
}
|
||||||
|
|
||||||
main {
|
main {
|
||||||
|
|||||||
Reference in New Issue
Block a user