This commit is contained in:
2026-03-20 21:17:26 +01:00
parent 1a62fcb81d
commit 29c3ff8572
229 changed files with 13147 additions and 2577 deletions

View File

@@ -16,6 +16,14 @@ if (!window.Alpine) {
import './lib/nav-context.js';
import { sendTagInteractionEvent } from './lib/tagAnalytics';
function safeParseJson(value, fallback) {
try {
return JSON.parse(value || 'null') ?? fallback;
} catch (_error) {
return fallback;
}
}
function mountStoryEditor() {
var storyEditorRoot = document.getElementById('story-editor-react-root');
if (!storyEditorRoot) return;
@@ -62,6 +70,176 @@ function mountStoryEditor() {
mountStoryEditor();
function mountToolbarNotifications() {
var rootEl = document.getElementById('toolbar-notification-root');
if (!rootEl || rootEl.dataset.reactMounted === 'true') return;
var props = safeParseJson(rootEl.getAttribute('data-props'), {});
rootEl.dataset.reactMounted = 'true';
void import('./components/social/NotificationDropdown.jsx')
.then(function (module) {
var Component = module.default;
createRoot(rootEl).render(React.createElement(Component, props));
})
.catch(function () {
rootEl.dataset.reactMounted = 'false';
});
}
function mountStorySocial() {
var socialRoot = document.getElementById('story-social-root');
if (socialRoot && socialRoot.dataset.reactMounted !== 'true') {
var props = safeParseJson(socialRoot.getAttribute('data-props'), {});
socialRoot.dataset.reactMounted = 'true';
void import('./components/social/StorySocialPanel.jsx')
.then(function (module) {
var Component = module.default;
createRoot(socialRoot).render(React.createElement(Component, {
story: props.story,
creator: props.creator,
initialState: props.state,
initialComments: props.comments,
isAuthenticated: Boolean(props.is_authenticated),
}));
})
.catch(function () {
socialRoot.dataset.reactMounted = 'false';
});
}
var followRoot = document.getElementById('story-creator-follow-root');
if (!followRoot || followRoot.dataset.reactMounted === 'true') return;
var followProps = safeParseJson(followRoot.getAttribute('data-props'), {});
followRoot.dataset.reactMounted = 'true';
void import('./components/social/FollowButton.jsx')
.then(function (module) {
var Component = module.default;
createRoot(followRoot).render(React.createElement(Component, {
username: followProps.username,
initialFollowing: Boolean(followProps.following),
initialCount: Number(followProps.followers_count || 0),
className: 'w-full justify-center',
}));
})
.catch(function () {
followRoot.dataset.reactMounted = 'false';
});
}
mountToolbarNotifications();
mountStorySocial();
function initStorySyntaxHighlighting() {
var codeBlocks = Array.prototype.slice.call(document.querySelectorAll('.story-prose pre code'));
if (!codeBlocks.length) return;
function fallbackCopyText(text) {
var textarea = document.createElement('textarea');
textarea.value = text;
textarea.setAttribute('readonly', 'true');
textarea.style.position = 'fixed';
textarea.style.top = '-1000px';
textarea.style.left = '-1000px';
document.body.appendChild(textarea);
textarea.select();
try {
return document.execCommand('copy');
} catch (_error) {
return false;
} finally {
document.body.removeChild(textarea);
}
}
function copyText(text) {
if (navigator.clipboard && typeof navigator.clipboard.writeText === 'function') {
return navigator.clipboard.writeText(text);
}
return fallbackCopyText(text)
? Promise.resolve()
: Promise.reject(new Error('Clipboard unavailable'));
}
function attachCopyButton(block) {
var pre = block.parentElement;
if (!pre || pre.dataset.copyButtonMounted === 'true') return;
var button = document.createElement('button');
var icon = document.createElement('span');
var label = document.createElement('span');
button.type = 'button';
button.className = 'story-code-copy-button';
icon.className = 'story-code-copy-icon';
icon.setAttribute('aria-hidden', 'true');
icon.textContent = '⧉';
label.className = 'story-code-copy-label';
label.textContent = 'Copy';
button.appendChild(icon);
button.appendChild(label);
button.dataset.copied = 'idle';
button.setAttribute('aria-label', 'Copy code block');
var resetTimer = 0;
button.addEventListener('click', function () {
var source = block.innerText || block.textContent || '';
copyText(source)
.then(function () {
icon.textContent = '✓';
label.textContent = 'Copied';
button.dataset.copied = 'true';
})
.catch(function () {
icon.textContent = '!';
label.textContent = 'Failed';
button.dataset.copied = 'false';
})
.finally(function () {
window.clearTimeout(resetTimer);
resetTimer = window.setTimeout(function () {
icon.textContent = '⧉';
label.textContent = 'Copy';
button.dataset.copied = 'idle';
}, 1800);
});
});
pre.appendChild(button);
pre.dataset.copyButtonMounted = 'true';
}
void import('highlight.js/lib/common')
.then(function (module) {
var hljs = module.default;
codeBlocks.forEach(function (block) {
attachCopyButton(block);
if (block.dataset.syntaxHighlighted === 'true') return;
var language = (block.getAttribute('data-language') || '').trim();
if (language && !block.className.includes('language-')) {
block.classList.add('language-' + language);
}
hljs.highlightElement(block);
block.dataset.syntaxHighlighted = 'true';
});
})
.catch(function () {
// Leave code blocks readable even if highlighting fails to load.
});
}
initStorySyntaxHighlighting();
function initTagsSearchAssist() {
var roots = document.querySelectorAll('[data-tags-search-root]');
if (!roots.length) return;