Files
forge/web_src/js/features/repo-wiki.ts
zeekayandHanzo Dev 412997543a rebrand(rel): rip ALL remaining gitea internals from rendered surfaces
- svg icon set: gitea-* → hanzo-* (60 icons — the names render into the DOM
  as class attributes on every page); webhook-type icon content replaced:
  the white Gitea TEACUP → the Hanzo mark (currentColor).
- Actions bot identity: gitea-actions / 'Gitea Actions' / [email protected] →
  hanzo-actions / 'Hanzo Actions' / [email protected] — this signs every
  Actions-generated commit. Virtual user (id -2, no DB row) so no migration;
  old git commits keep their historical author. Legacy name stays reserved
  so nobody can squat it.
- emoji defaults: :gitea:/:gogs:/:codeberg: ripped (pngs deleted); kept
  git/github/gitlab (real interop marks).
- external-render seam tokens (script#, query params, data-attr, CSS var),
  EasyMDE toolbar keys, theme meta-info marker gitea-theme-meta-info →
  hanzo-theme-meta-info (parser + all 9 theme files + tests).
- meta keywords default → git,self-hosted,hanzo; update-checker cron now
  DISABLED by default + pointed at hanzoai/git releases (was phoning
  dl.gitea.com weekly and comparing against the wrong product's versions).
- user-visible snippets/links: cargo registry name, debian keyring paths,
  LDAP filter placeholders, install placeholders, home/appearance/admin
  links, swagger profile-URL description, oauth2 modal DOM ids,
  web_src module gitea-actions.ts → actions-types.ts.
- KEPT (functional, not brand): webhook TYPE key 'gitea' + /gitea/new route
  (existing hooks), ssh-keygen -n gitea signing namespace (verification
  compat), 'gitea doctor' CLI examples (actual binary name), migrate-from-
  Gitea interop naming, swagger enum values.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-24 12:45:20 -07:00

86 lines
3.6 KiB
TypeScript

import {validateTextareaNonEmpty, initComboMarkdownEditor} from './comp/ComboMarkdownEditor.ts';
import {fomanticMobileScreen} from '../modules/fomantic.ts';
import {POST} from '../modules/fetch.ts';
import type {ComboMarkdownEditor} from './comp/ComboMarkdownEditor.ts';
import {html, htmlRaw} from '../utils/html.ts';
async function initRepoWikiFormEditor() {
const editArea = document.querySelector<HTMLTextAreaElement>('.repository.wiki .combo-markdown-editor textarea');
if (!editArea) return;
const form = document.querySelector('.repository.wiki.new .ui.form')!;
const editorContainer = form.querySelector<HTMLElement>('.combo-markdown-editor')!;
let editor: ComboMarkdownEditor;
let renderRequesting = false;
let lastContent: string = '';
const renderEasyMDEPreview = async function () {
if (renderRequesting) return;
const previewFull = editorContainer.querySelector('.EasyMDEContainer .editor-preview-active');
const previewSide = editorContainer.querySelector('.EasyMDEContainer .editor-preview-active-side');
const previewTarget = previewSide || previewFull;
const newContent = editArea.value;
if (editor && previewTarget && lastContent !== newContent) {
renderRequesting = true;
const formData = new FormData();
formData.append('mode', editor.previewMode);
formData.append('context', editor.previewContext);
formData.append('text', newContent);
try {
const response = await POST(editor.previewUrl, {data: formData});
const data = await response.text();
lastContent = newContent;
previewTarget.innerHTML = html`<div class="render-content markup ui segment">${htmlRaw(data)}</div>`;
} catch (error) {
console.error('Error rendering preview:', error);
} finally {
renderRequesting = false;
setTimeout(renderEasyMDEPreview, 1000);
}
} else {
setTimeout(renderEasyMDEPreview, 1000);
}
};
renderEasyMDEPreview();
editor = await initComboMarkdownEditor(editorContainer, {
// EasyMDE has some problems of height definition, it has inline style height 300px by default, so we also use inline styles to override it.
// And another benefit is that we only need to write the style once for both editors.
// TODO: Move height style to CSS after EasyMDE removal.
editorHeights: {minHeight: '300px', height: 'calc(100vh - 600px)'},
easyMDEOptions: {
previewRender: (_content, previewTarget) => previewTarget.innerHTML, // disable builtin preview render
toolbar: ['bold', 'italic', 'strikethrough', '|',
'heading-1', 'heading-2', 'heading-3', 'heading-bigger', 'heading-smaller', '|',
'hanzo-code-inline', 'code', 'quote', '|', 'hanzo-checkbox-empty', 'hanzo-checkbox-checked', '|',
'unordered-list', 'ordered-list', '|',
'link', 'image', 'table', 'horizontal-rule', '|',
'preview', 'fullscreen', 'side-by-side', '|', 'hanzo-switch-to-textarea',
] as any, // to use custom toolbar buttons
},
});
form.addEventListener('submit', (e) => {
if (!validateTextareaNonEmpty(editArea)) {
e.preventDefault();
e.stopPropagation();
}
});
}
function collapseWikiTocForMobile(collapse: boolean) {
if (collapse) {
document.querySelector('.wiki-content-toc details')?.removeAttribute('open');
}
}
export function initRepoWikiForm() {
if (!document.querySelector('.page-content.repository.wiki')) return;
fomanticMobileScreen.addEventListener('change', (e) => collapseWikiTocForMobile(e.matches));
collapseWikiTocForMobile(fomanticMobileScreen.matches);
initRepoWikiFormEditor();
}