update
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user