Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ preview = Preview
loading = Loading…
files = Files

code_toggle_wrap = Toggle code wrap

error = Error
error404 = The page you are trying to reach either <strong>does not exist</strong> or <strong>you are not authorized</strong> to view it.
error503 = The server could not complete your request. Please try again later.
Expand Down
1 change: 1 addition & 0 deletions public/assets/img/svg/material-wrap-text.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions templates/base/head_script.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ If you introduce mistakes in it, Gitea JavaScript code wouldn't run correctly.
mermaidMaxSourceCharacters: {{MermaidMaxSourceCharacters}},
{{/* this global i18n object should only contain general texts. for specialized texts, it should be provided inside the related modules by: (1) API response (2) HTML data-attribute (3) PageData */}}
i18n: {
copy: {{ctx.Locale.Tr "copy"}},
copy_success: {{ctx.Locale.Tr "copy_success"}},
copy_error: {{ctx.Locale.Tr "copy_error"}},
error_occurred: {{ctx.Locale.Tr "error.occurred"}},
Expand All @@ -41,6 +42,7 @@ If you introduce mistakes in it, Gitea JavaScript code wouldn't run correctly.
modal_confirm: {{ctx.Locale.Tr "modal.confirm"}},
modal_cancel: {{ctx.Locale.Tr "modal.cancel"}},
more_items: {{ctx.Locale.Tr "more_items"}},
code_toggle_wrap: {{ctx.Locale.Tr "code_toggle_wrap"}},
},
};
{{/* in case some pages don't render the pageData, we make sure it is an object to prevent null access */}}
Expand Down
2 changes: 1 addition & 1 deletion web_src/css/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
@import "./features/console.css";

@import "./markup/content.css";
@import "./markup/codecopy.css";
@import "./markup/codeblocks.css";
@import "./markup/codepreview.css";
@import "./markup/asciicast.css";

Expand Down
35 changes: 35 additions & 0 deletions web_src/css/markup/codeblocks.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
.markup .code-block-buttons {
position: absolute;
top: 8px;
right: 6px;
display: flex;
gap: 4px;
visibility: hidden;
animation: fadeout 0.2s both;
}

/* adjustments for comment content having only 14px font size */
.repository.view.issue .comment-list .comment .markup .code-copy {
right: 5px;
padding: 8px;
}

.markup .code-block-buttons .btn {
background: var(--color-button) !important;
padding: 9px;
border: 1px solid var(--color-light-border);
}

.markup .code-block-buttons .btn:hover {
background: var(--color-hover-opaque) !important;
}

.markup .code-block-buttons .btn[data-active="false"] {
color: var(--color-text-light-3);
}

.markup .code-block-container:hover .code-block-buttons,
.markup .code-block:hover .code-block-buttons {
visibility: visible;
animation: fadein 0.2s both;
}
30 changes: 0 additions & 30 deletions web_src/css/markup/codecopy.css

This file was deleted.

2 changes: 1 addition & 1 deletion web_src/js/globals.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ interface Element {

interface Window {
__webpack_public_path__: string;
config: import('./web_src/js/types.ts').Config;
config: import('./types.ts').Config;
$: typeof import('@types/jquery'),
jQuery: typeof import('@types/jquery'),
htmx: typeof import('htmx.org').default,
Expand Down
51 changes: 51 additions & 0 deletions web_src/js/markup/codeblocks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import {svg, type SvgName} from '../svg.ts';
import {queryElems} from '../utils/dom.ts';

export function makeCodeBlockButton(className: string, name: SvgName): HTMLButtonElement {
const button = document.createElement('button');
button.classList.add(className, 'btn');
button.innerHTML = svg(name, 14);
return button;
}

const getWrap = () => (localStorage.getItem('wrap-markup-code') || 'false') === 'true';
const saveWrap = (value: boolean) => localStorage.setItem('wrap-markup-code', String(value));

function updateWrap(container: Element, wrap: boolean) {
container.classList.remove(wrap ? 'code-overflow-scroll' : 'code-overflow-wrap');
container.classList.add(wrap ? 'code-overflow-wrap' : 'code-overflow-scroll');
}

export function initMarkupCodeBlocks(elMarkup: HTMLElement): void {
// .markup .code-block code
queryElems(elMarkup, '.code-block code', (el) => {
if (!el.textContent) return;

const copyBtn = makeCodeBlockButton('code-copy', 'octicon-copy');
copyBtn.setAttribute('data-tooltip-content', window.config.i18n.copy);
// remove final trailing newline introduced during HTML rendering
copyBtn.setAttribute('data-clipboard-text', el.textContent.replace(/\r?\n$/, ''));

// we only want to use `.code-block-container` if it exists, no matter `.code-block` exists or not.
const container = el.closest('.code-block-container') ?? el.closest('.code-block');

const wrapBtn = makeCodeBlockButton('code-wrap', 'material-wrap-text');
const wrap = getWrap();
wrapBtn.setAttribute('data-active', String(wrap));
updateWrap(container, wrap);
Copy link
Member Author

@silverwind silverwind Sep 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This causes a flicker on page load, but I think it's okay for now. Moving the initial classes to backend will be more work and I don't know how to use the backend user setting storage.


wrapBtn.setAttribute('data-tooltip-content', window.config.i18n.code_toggle_wrap);
wrapBtn.addEventListener('click', (e) => {
const wrap = !getWrap();
updateWrap(container, wrap);
(e.currentTarget as HTMLButtonElement).setAttribute('data-active', String(wrap));
saveWrap(wrap);
});

const btnContainer = document.createElement('div');
btnContainer.classList.add('code-block-buttons');
btnContainer.append(wrapBtn);
btnContainer.append(copyBtn);
container.append(btnContainer);
});
}
22 changes: 0 additions & 22 deletions web_src/js/markup/codecopy.ts

This file was deleted.

4 changes: 2 additions & 2 deletions web_src/js/markup/content.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import {initMarkupCodeMermaid} from './mermaid.ts';
import {initMarkupCodeMath} from './math.ts';
import {initMarkupCodeCopy} from './codecopy.ts';
import {initMarkupCodeBlocks} from './codeblocks.ts';
import {initMarkupRenderAsciicast} from './asciicast.ts';
import {initMarkupTasklist} from './tasklist.ts';
import {registerGlobalSelectorFunc} from '../modules/observer.ts';

// code that runs for all markup content
export function initMarkupContent(): void {
registerGlobalSelectorFunc('.markup', (el: HTMLElement) => {
initMarkupCodeCopy(el);
initMarkupCodeBlocks(el);
initMarkupTasklist(el);
initMarkupCodeMermaid(el);
initMarkupCodeMath(el);
Expand Down
4 changes: 2 additions & 2 deletions web_src/js/markup/mermaid.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {isDarkTheme} from '../utils.ts';
import {makeCodeCopyButton} from './codecopy.ts';
import {makeCodeBlockButton} from './codeblocks.ts';
import {displayError} from './common.ts';
import {queryElems} from '../utils/dom.ts';
import {html, htmlRaw} from '../utils/html.ts';
Expand Down Expand Up @@ -53,7 +53,7 @@ export async function initMarkupCodeMermaid(elMarkup: HTMLElement): Promise<void
mermaidBlock.classList.add('mermaid-block', 'is-loading', 'tw-hidden');
mermaidBlock.append(iframe);

const btn = makeCodeCopyButton();
const btn = makeCodeBlockButton('code-copy', 'octicon-copy');
btn.setAttribute('data-clipboard-text', source);
mermaidBlock.append(btn);

Expand Down
2 changes: 2 additions & 0 deletions web_src/js/svg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import giteaDoubleChevronLeft from '../../public/assets/img/svg/gitea-double-che
import giteaDoubleChevronRight from '../../public/assets/img/svg/gitea-double-chevron-right.svg';
import giteaEmptyCheckbox from '../../public/assets/img/svg/gitea-empty-checkbox.svg';
import giteaExclamation from '../../public/assets/img/svg/gitea-exclamation.svg';
import materialWrapText from '../../public/assets/img/svg/material-wrap-text.svg';
import octiconArchive from '../../public/assets/img/svg/octicon-archive.svg';
import octiconArrowSwitch from '../../public/assets/img/svg/octicon-arrow-switch.svg';
import octiconBlocked from '../../public/assets/img/svg/octicon-blocked.svg';
Expand Down Expand Up @@ -84,6 +85,7 @@ const svgs = {
'gitea-double-chevron-right': giteaDoubleChevronRight,
'gitea-empty-checkbox': giteaEmptyCheckbox,
'gitea-exclamation': giteaExclamation,
'material-wrap-text': materialWrapText,
'octicon-archive': octiconArchive,
'octicon-arrow-switch': octiconArrowSwitch,
'octicon-blocked': octiconBlocked,
Expand Down
1 change: 1 addition & 0 deletions web_src/svg/material-wrap-text.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.