refactor: move tenant templates to internal/tenant
- Move internal/build/ to internal/tenant/ - Rename assets for clarity - Add tenant-blog.js for shared blog functionality - Update style.css with improved code block styling Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
bef5dd4437
commit
6e2959f619
11 changed files with 153 additions and 358 deletions
|
|
@ -1,127 +0,0 @@
|
||||||
(function() {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
// Live reload when studio saves settings
|
|
||||||
const channel = new BroadcastChannel('writekit-studio');
|
|
||||||
channel.onmessage = function(event) {
|
|
||||||
if (event.data.type === 'settings-changed') {
|
|
||||||
location.reload();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', initSearch);
|
|
||||||
|
|
||||||
function initSearch() {
|
|
||||||
const trigger = document.getElementById('search-trigger');
|
|
||||||
const modal = document.getElementById('search-modal');
|
|
||||||
const backdrop = modal?.querySelector('.search-modal-backdrop');
|
|
||||||
const input = document.getElementById('search-input');
|
|
||||||
const results = document.getElementById('search-results');
|
|
||||||
|
|
||||||
if (!trigger || !modal || !input || !results) return;
|
|
||||||
|
|
||||||
let debounceTimer;
|
|
||||||
|
|
||||||
function open() {
|
|
||||||
modal.classList.add('active');
|
|
||||||
document.body.style.overflow = 'hidden';
|
|
||||||
input.value = '';
|
|
||||||
results.innerHTML = '';
|
|
||||||
setTimeout(() => input.focus(), 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
function close() {
|
|
||||||
modal.classList.remove('active');
|
|
||||||
document.body.style.overflow = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
trigger.addEventListener('click', open);
|
|
||||||
backdrop.addEventListener('click', close);
|
|
||||||
|
|
||||||
document.addEventListener('keydown', function(e) {
|
|
||||||
if (e.key === '/' && !modal.classList.contains('active') &&
|
|
||||||
!['INPUT', 'TEXTAREA'].includes(document.activeElement.tagName)) {
|
|
||||||
e.preventDefault();
|
|
||||||
open();
|
|
||||||
}
|
|
||||||
if (e.key === 'Escape' && modal.classList.contains('active')) {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
input.addEventListener('input', function() {
|
|
||||||
const query = this.value.trim();
|
|
||||||
clearTimeout(debounceTimer);
|
|
||||||
|
|
||||||
if (query.length < 2) {
|
|
||||||
results.innerHTML = '';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
debounceTimer = setTimeout(() => search(query), 150);
|
|
||||||
});
|
|
||||||
|
|
||||||
input.addEventListener('keydown', function(e) {
|
|
||||||
const items = results.querySelectorAll('.search-result');
|
|
||||||
const focused = results.querySelector('.search-result.focused');
|
|
||||||
|
|
||||||
if (e.key === 'ArrowDown') {
|
|
||||||
e.preventDefault();
|
|
||||||
if (!focused && items.length) {
|
|
||||||
items[0].classList.add('focused');
|
|
||||||
} else if (focused?.nextElementSibling) {
|
|
||||||
focused.classList.remove('focused');
|
|
||||||
focused.nextElementSibling.classList.add('focused');
|
|
||||||
}
|
|
||||||
} else if (e.key === 'ArrowUp') {
|
|
||||||
e.preventDefault();
|
|
||||||
if (focused?.previousElementSibling) {
|
|
||||||
focused.classList.remove('focused');
|
|
||||||
focused.previousElementSibling.classList.add('focused');
|
|
||||||
}
|
|
||||||
} else if (e.key === 'Enter' && focused) {
|
|
||||||
e.preventDefault();
|
|
||||||
const link = focused.querySelector('a');
|
|
||||||
if (link) window.location.href = link.href;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
async function search(query) {
|
|
||||||
try {
|
|
||||||
const res = await fetch('/api/reader/search?q=' + encodeURIComponent(query));
|
|
||||||
const data = await res.json();
|
|
||||||
|
|
||||||
if (!data || data.length === 0) {
|
|
||||||
results.innerHTML = '<div class="search-no-results">No results found</div>';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
results.innerHTML = data.map(r => `
|
|
||||||
<div class="search-result">
|
|
||||||
<a href="${r.url}">
|
|
||||||
<div class="search-result-title">${highlight(r.title, query)}</div>
|
|
||||||
${r.description ? `<div class="search-result-snippet">${highlight(r.description, query)}</div>` : ''}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
`).join('');
|
|
||||||
} catch (e) {
|
|
||||||
results.innerHTML = '<div class="search-no-results">Search failed</div>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function highlight(text, query) {
|
|
||||||
if (!text) return '';
|
|
||||||
const escaped = escapeHtml(text);
|
|
||||||
const tokens = query.split(/\s+/).filter(t => t.length > 0);
|
|
||||||
if (!tokens.length) return escaped;
|
|
||||||
const pattern = tokens.map(t => t.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|');
|
|
||||||
return escaped.replace(new RegExp(`(${pattern})`, 'gi'), '<mark>$1</mark>');
|
|
||||||
}
|
|
||||||
|
|
||||||
function escapeHtml(text) {
|
|
||||||
const div = document.createElement('div');
|
|
||||||
div.textContent = text;
|
|
||||||
return div.innerHTML;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>{{.Title}}</title>
|
|
||||||
<meta name="description" content="{{.Description}}">
|
|
||||||
<link rel="canonical" href="{{.CanonicalURL}}">
|
|
||||||
|
|
||||||
{{if .NoIndex}}<meta name="robots" content="noindex">{{end}}
|
|
||||||
|
|
||||||
<!-- Open Graph -->
|
|
||||||
<meta property="og:title" content="{{.Title}}">
|
|
||||||
<meta property="og:description" content="{{.Description}}">
|
|
||||||
<meta property="og:type" content="{{.OGType}}">
|
|
||||||
<meta property="og:url" content="{{.CanonicalURL}}">
|
|
||||||
{{if .OGImage}}<meta property="og:image" content="{{.OGImage}}">{{end}}
|
|
||||||
<meta property="og:site_name" content="{{.SiteName}}">
|
|
||||||
|
|
||||||
<!-- Twitter Card -->
|
|
||||||
<meta name="twitter:card" content="summary_large_image">
|
|
||||||
<meta name="twitter:title" content="{{.Title}}">
|
|
||||||
<meta name="twitter:description" content="{{.Description}}">
|
|
||||||
{{if .OGImage}}<meta name="twitter:image" content="{{.OGImage}}">{{end}}
|
|
||||||
|
|
||||||
<!-- Fonts -->
|
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
||||||
{{if .FontURL}}<link rel="stylesheet" href="{{.FontURL}}">{{end}}
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="/static/css/style.css">
|
|
||||||
|
|
||||||
<style>
|
|
||||||
:root {
|
|
||||||
--accent: {{with index .Settings "accent_color"}}{{.}}{{else}}#2563eb{{end}};
|
|
||||||
--font-body: {{or .FontFamily "system-ui, -apple-system, sans-serif"}};
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
{{if .StructuredData}}
|
|
||||||
<script type="application/ld+json">{{.StructuredData}}</script>
|
|
||||||
{{end}}
|
|
||||||
</head>
|
|
||||||
<body class="layout-{{with index .Settings "layout"}}{{.}}{{else}}default{{end}} compactness-{{with index .Settings "compactness"}}{{.}}{{else}}cozy{{end}}">
|
|
||||||
<header class="site-header">
|
|
||||||
<a href="/" class="site-name">{{.SiteName}}</a>
|
|
||||||
<nav class="site-nav">
|
|
||||||
<button type="button" id="search-trigger" class="search-trigger">
|
|
||||||
<span>Search</span>
|
|
||||||
<kbd>/</kbd>
|
|
||||||
</button>
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<main>
|
|
||||||
{{template "content" .}}
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<footer class="site-footer">
|
|
||||||
<span>© {{.Year}} {{.SiteName}}</span>
|
|
||||||
{{if .ShowBadge}}<a href="https://writekit.dev" class="powered-by" target="_blank" rel="noopener">Powered by WriteKit</a>{{end}}
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<div id="search-modal" class="search-modal">
|
|
||||||
<div class="search-modal-backdrop"></div>
|
|
||||||
<div class="search-modal-content">
|
|
||||||
<input type="text" id="search-input" placeholder="Search..." autocomplete="off">
|
|
||||||
<div id="search-results" class="search-results"></div>
|
|
||||||
<div class="search-hint">Press <kbd>ESC</kbd> to close</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="/static/js/main.js"></script>
|
|
||||||
<script src="https://unpkg.com/quicklink@2.3.0/dist/quicklink.umd.js"></script>
|
|
||||||
<script>quicklink.listen({ignores: [/\/studio/, /\/api\//]});</script>
|
|
||||||
{{block "scripts" .}}{{end}}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -6,6 +6,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Embedded static assets for tenant blogs
|
||||||
|
//
|
||||||
//go:embed css js
|
//go:embed css js
|
||||||
var staticFS embed.FS
|
var staticFS embed.FS
|
||||||
|
|
||||||
|
|
@ -392,7 +392,7 @@ main {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.prose pre {
|
.prose pre:not(.chroma) {
|
||||||
margin: var(--content-spacing) 0;
|
margin: var(--content-spacing) 0;
|
||||||
padding: 1.125rem 1.25rem;
|
padding: 1.125rem 1.25rem;
|
||||||
background: var(--bg-secondary);
|
background: var(--bg-secondary);
|
||||||
|
|
@ -404,6 +404,13 @@ main {
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.prose pre.chroma {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 0.875rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.prose code {
|
.prose code {
|
||||||
font-family: var(--font-mono);
|
font-family: var(--font-mono);
|
||||||
font-size: 0.875em;
|
font-size: 0.875em;
|
||||||
|
|
@ -419,6 +426,64 @@ main {
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Enhanced Code Block */
|
||||||
|
.code-block {
|
||||||
|
margin: var(--content-spacing) 0;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
overflow: hidden;
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-block pre {
|
||||||
|
margin: 0;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0;
|
||||||
|
padding: 1rem 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
padding: 0.625rem 1rem;
|
||||||
|
background: var(--bg);
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-icon {
|
||||||
|
width: 1rem;
|
||||||
|
height: 1rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-title {
|
||||||
|
flex: 1;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-copy {
|
||||||
|
padding: 0.25rem 0.625rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--text-muted);
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.15s;
|
||||||
|
font-family: var(--font-body);
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-copy:hover {
|
||||||
|
color: var(--text);
|
||||||
|
background: var(--bg);
|
||||||
|
border-color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
.prose img {
|
.prose img {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
|
|
@ -512,147 +577,6 @@ main {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Search */
|
|
||||||
.search-trigger {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.5rem;
|
|
||||||
padding: 0.375rem 0.75rem;
|
|
||||||
border: 1px solid var(--border);
|
|
||||||
border-radius: 0.375rem;
|
|
||||||
background: var(--bg);
|
|
||||||
color: var(--text-muted);
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
transition: border-color 0.15s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-trigger:hover {
|
|
||||||
border-color: color-mix(in srgb, var(--accent) 50%, var(--border));
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-trigger kbd {
|
|
||||||
padding: 0.125rem 0.375rem;
|
|
||||||
background: var(--bg-secondary);
|
|
||||||
border-radius: 0.25rem;
|
|
||||||
font-family: var(--font-mono);
|
|
||||||
font-size: 0.6875rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-modal {
|
|
||||||
display: none;
|
|
||||||
position: fixed;
|
|
||||||
inset: 0;
|
|
||||||
z-index: 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-modal.active {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-modal-backdrop {
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
background: rgba(0, 0, 0, 0.4);
|
|
||||||
backdrop-filter: blur(2px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-modal-content {
|
|
||||||
position: absolute;
|
|
||||||
top: 15%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
width: 90%;
|
|
||||||
max-width: 520px;
|
|
||||||
background: var(--bg);
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
box-shadow: 0 20px 40px -8px rgba(0, 0, 0, 0.2);
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
#search-input {
|
|
||||||
width: 100%;
|
|
||||||
padding: 1rem 1.25rem;
|
|
||||||
border: none;
|
|
||||||
font-size: 1rem;
|
|
||||||
outline: none;
|
|
||||||
background: var(--bg);
|
|
||||||
color: var(--text);
|
|
||||||
}
|
|
||||||
|
|
||||||
#search-input::placeholder {
|
|
||||||
color: var(--text-muted);
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-results {
|
|
||||||
max-height: 320px;
|
|
||||||
overflow-y: auto;
|
|
||||||
border-top: 1px solid var(--border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-result {
|
|
||||||
border-bottom: 1px solid var(--border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-result:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-result a {
|
|
||||||
display: block;
|
|
||||||
padding: 0.875rem 1.25rem;
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-result a:hover {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-result:hover, .search-result.focused {
|
|
||||||
background: var(--bg-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-result-title {
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 0.9375rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-result-snippet {
|
|
||||||
font-size: 0.8125rem;
|
|
||||||
color: var(--text-muted);
|
|
||||||
margin-top: 0.25rem;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-result mark {
|
|
||||||
background: color-mix(in srgb, var(--accent) 25%, transparent);
|
|
||||||
color: inherit;
|
|
||||||
border-radius: 0.125rem;
|
|
||||||
padding: 0 0.125rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-hint {
|
|
||||||
padding: 0.625rem 1.25rem;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
color: var(--text-muted);
|
|
||||||
text-align: center;
|
|
||||||
border-top: 1px solid var(--border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-hint kbd {
|
|
||||||
padding: 0.125rem 0.375rem;
|
|
||||||
background: var(--bg-secondary);
|
|
||||||
border-radius: 0.25rem;
|
|
||||||
font-family: var(--font-mono);
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-no-results {
|
|
||||||
padding: 1.5rem 1.25rem;
|
|
||||||
text-align: center;
|
|
||||||
color: var(--text-muted);
|
|
||||||
font-size: 0.9375rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Comment Form */
|
/* Comment Form */
|
||||||
.comment-form textarea {
|
.comment-form textarea {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
10
internal/tenant/assets/js/tenant-blog.js
Normal file
10
internal/tenant/assets/js/tenant-blog.js
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const channel = new BroadcastChannel('writekit-studio');
|
||||||
|
channel.onmessage = function(event) {
|
||||||
|
if (event.data.type === 'settings-changed') {
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
63
internal/tenant/templates/base.html
Normal file
63
internal/tenant/templates/base.html
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>{{.Title}}</title>
|
||||||
|
<meta name="description" content="{{.Description}}">
|
||||||
|
<link rel="canonical" href="{{.CanonicalURL}}">
|
||||||
|
|
||||||
|
{{if .NoIndex}}<meta name="robots" content="noindex">{{end}}
|
||||||
|
|
||||||
|
<!-- Open Graph -->
|
||||||
|
<meta property="og:title" content="{{.Title}}">
|
||||||
|
<meta property="og:description" content="{{.Description}}">
|
||||||
|
<meta property="og:type" content="{{.OGType}}">
|
||||||
|
<meta property="og:url" content="{{.CanonicalURL}}">
|
||||||
|
{{if .OGImage}}<meta property="og:image" content="{{.OGImage}}">{{end}}
|
||||||
|
<meta property="og:site_name" content="{{.SiteName}}">
|
||||||
|
|
||||||
|
<!-- Twitter Card -->
|
||||||
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
|
<meta name="twitter:title" content="{{.Title}}">
|
||||||
|
<meta name="twitter:description" content="{{.Description}}">
|
||||||
|
{{if .OGImage}}<meta name="twitter:image" content="{{.OGImage}}">{{end}}
|
||||||
|
|
||||||
|
<!-- Fonts -->
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
{{if .FontURL}}<link rel="stylesheet" href="{{.FontURL}}">{{end}}
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/static/css/style.css">
|
||||||
|
|
||||||
|
{{if .StructuredData}}
|
||||||
|
<script type="application/ld+json">{{.StructuredData}}</script>
|
||||||
|
{{end}}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="page" class="layout-{{with index .Settings "layout"}}{{.}}{{else}}default{{end}} compactness-{{with index .Settings "compactness"}}{{.}}{{else}}cozy{{end}}">
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--accent: {{with index .Settings "accent_color"}}{{.}}{{else}}#2563eb{{end}};
|
||||||
|
--font-body: {{or .FontFamily "system-ui, -apple-system, sans-serif"}};
|
||||||
|
}
|
||||||
|
{{.CodeThemeCSS}}
|
||||||
|
</style>
|
||||||
|
<header class="site-header">
|
||||||
|
<a href="/" class="site-name">{{.SiteName}}</a>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
{{template "content" .}}
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="site-footer">
|
||||||
|
<span>© {{.Year}} {{.SiteName}}</span>
|
||||||
|
{{if .ShowBadge}}<a href="https://writekit.dev" class="powered-by" target="_blank" rel="noopener">Powered by WriteKit</a>{{end}}
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script src="/static/js/tenant-blog.js"></script>
|
||||||
|
{{block "scripts" .}}{{end}}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -42,7 +42,7 @@
|
||||||
|
|
||||||
{{define "scripts"}}
|
{{define "scripts"}}
|
||||||
{{if or .InteractionConfig.ReactionsEnabled .InteractionConfig.CommentsEnabled}}
|
{{if or .InteractionConfig.ReactionsEnabled .InteractionConfig.CommentsEnabled}}
|
||||||
<script src="/static/js/post.js"></script>
|
<script src="/static/js/tenant-post.js"></script>
|
||||||
<script>
|
<script>
|
||||||
WriteKit.init({
|
WriteKit.init({
|
||||||
slug: "{{.Post.Slug}}",
|
slug: "{{.Post.Slug}}",
|
||||||
|
|
@ -76,6 +76,7 @@ type PageData struct {
|
||||||
StructuredData template.JS
|
StructuredData template.JS
|
||||||
Settings map[string]any
|
Settings map[string]any
|
||||||
ShowBadge bool
|
ShowBadge bool
|
||||||
|
CodeThemeCSS template.CSS
|
||||||
}
|
}
|
||||||
|
|
||||||
type HomeData struct {
|
type HomeData struct {
|
||||||
Loading…
Add table
Add a link
Reference in a new issue