Skip to content

Commit e7f4da6

Browse files
committed
Add markdown code blog wrap toggle
Fixes: #35314
1 parent 0b706b0 commit e7f4da6

File tree

13 files changed

+100
-58
lines changed

13 files changed

+100
-58
lines changed

options/locale/locale_en-US.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ preview = Preview
115115
loading = Loading…
116116
files = Files
117117

118+
code_toggle_wrap = Toggle Code Wrap
119+
118120
error = Error
119121
error404 = The page you are trying to reach either <strong>does not exist</strong> or <strong>you are not authorized</strong> to view it.
120122
error503 = The server could not complete your request. Please try again later.

public/assets/img/svg/material-wrap-text.svg

Lines changed: 1 addition & 0 deletions
Loading

templates/base/head_script.tmpl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ If you introduce mistakes in it, Gitea JavaScript code wouldn't run correctly.
3333
mermaidMaxSourceCharacters: {{MermaidMaxSourceCharacters}},
3434
{{/* 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 */}}
3535
i18n: {
36+
copy: {{ctx.Locale.Tr "copy"}},
3637
copy_success: {{ctx.Locale.Tr "copy_success"}},
3738
copy_error: {{ctx.Locale.Tr "copy_error"}},
3839
error_occurred: {{ctx.Locale.Tr "error.occurred"}},
@@ -41,6 +42,7 @@ If you introduce mistakes in it, Gitea JavaScript code wouldn't run correctly.
4142
modal_confirm: {{ctx.Locale.Tr "modal.confirm"}},
4243
modal_cancel: {{ctx.Locale.Tr "modal.cancel"}},
4344
more_items: {{ctx.Locale.Tr "more_items"}},
45+
code_toggle_wrap: {{ctx.Locale.Tr "code_toggle_wrap"}},
4446
},
4547
};
4648
{{/* in case some pages don't render the pageData, we make sure it is an object to prevent null access */}}

web_src/css/index.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
@import "./features/console.css";
4545

4646
@import "./markup/content.css";
47-
@import "./markup/codecopy.css";
47+
@import "./markup/codeblocks.css";
4848
@import "./markup/codepreview.css";
4949
@import "./markup/asciicast.css";
5050

web_src/css/markup/codeblocks.css

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
.markup .code-block-buttons {
2+
position: absolute;
3+
top: 8px;
4+
right: 6px;
5+
display: flex;
6+
gap: 4px;
7+
visibility: hidden;
8+
animation: fadeout 0.2s both;
9+
}
10+
11+
/* adjustments for comment content having only 14px font size */
12+
.repository.view.issue .comment-list .comment .markup .code-copy {
13+
right: 5px;
14+
padding: 8px;
15+
}
16+
17+
.markup .code-block-buttons .btn {
18+
background: var(--color-button) !important;
19+
padding: 9px;
20+
border: 1px solid var(--color-light-border);
21+
}
22+
23+
.markup .code-block-buttons .btn:hover {
24+
background: var(--color-hover-opaque) !important;
25+
}
26+
27+
.markup .code-block-buttons .btn[data-active="false"] {
28+
color: var(--color-text-light-3);
29+
}
30+
31+
.markup .code-block-container:hover .code-block-buttons,
32+
.markup .code-block:hover .code-block-buttons {
33+
visibility: visible;
34+
animation: fadein 0.2s both;
35+
}

web_src/css/markup/codecopy.css

Lines changed: 0 additions & 30 deletions
This file was deleted.

web_src/js/globals.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ interface Element {
5252

5353
interface Window {
5454
__webpack_public_path__: string;
55-
config: import('./web_src/js/types.ts').Config;
55+
config: import('./types.ts').Config;
5656
$: typeof import('@types/jquery'),
5757
jQuery: typeof import('@types/jquery'),
5858
htmx: typeof import('htmx.org').default,

web_src/js/markup/codeblocks.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import {svg, type SvgName} from '../svg.ts';
2+
import {queryElems, type DOMEvent} from '../utils/dom.ts';
3+
4+
export function makeCodeBlockButton(className: string, name: SvgName): HTMLButtonElement {
5+
const button = document.createElement('button');
6+
button.classList.add(className, 'btn');
7+
button.innerHTML = svg(name, 14);
8+
return button;
9+
}
10+
11+
const getMarkupCodeWrap = () => (localStorage.getItem('wrap-markup-code') || 'false') === 'true';
12+
const setMarkupCodeWrap = (value: boolean) => localStorage.setItem('wrap-markup-code', String(value));
13+
14+
function updateWrap(container: Element, wrap: boolean) {
15+
container.classList.remove(wrap ? 'code-overflow-scroll' : 'code-overflow-wrap');
16+
container.classList.add(wrap ? 'code-overflow-wrap' : 'code-overflow-scroll');
17+
}
18+
19+
export function initMarkupCodeBlocks(elMarkup: HTMLElement): void {
20+
// .markup .code-block code
21+
queryElems(elMarkup, '.code-block code', (el) => {
22+
if (!el.textContent) return;
23+
24+
const copyBtn = makeCodeBlockButton('code-copy', 'octicon-copy');
25+
copyBtn.setAttribute('data-tooltip-content', window.config.i18n.copy);
26+
// remove final trailing newline introduced during HTML rendering
27+
copyBtn.setAttribute('data-clipboard-text', el.textContent.replace(/\r?\n$/, ''));
28+
29+
// we only want to use `.code-block-container` if it exists, no matter `.code-block` exists or not.
30+
const container = el.closest('.code-block-container') ?? el.closest('.code-block');
31+
32+
const wrapBtn = makeCodeBlockButton('code-wrap', 'material-wrap-text');
33+
const wrap = getMarkupCodeWrap();
34+
wrapBtn.setAttribute('data-active', String(wrap));
35+
updateWrap(container, wrap);
36+
37+
wrapBtn.setAttribute('data-tooltip-content', window.config.i18n.code_toggle_wrap);
38+
wrapBtn.addEventListener('click', (e) => {
39+
const wrap = !getMarkupCodeWrap();
40+
updateWrap(container, wrap);
41+
(e.currentTarget as HTMLButtonElement).setAttribute('data-active', String(wrap));
42+
setMarkupCodeWrap(wrap);
43+
});
44+
45+
const btnContainer = document.createElement('div');
46+
btnContainer.classList.add('code-block-buttons');
47+
btnContainer.append(wrapBtn);
48+
btnContainer.append(copyBtn);
49+
container.append(btnContainer);
50+
});
51+
}

web_src/js/markup/codecopy.ts

Lines changed: 0 additions & 22 deletions
This file was deleted.

web_src/js/markup/content.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import {initMarkupCodeMermaid} from './mermaid.ts';
22
import {initMarkupCodeMath} from './math.ts';
3-
import {initMarkupCodeCopy} from './codecopy.ts';
3+
import {initMarkupCodeBlocks} from './codeblocks.ts';
44
import {initMarkupRenderAsciicast} from './asciicast.ts';
55
import {initMarkupTasklist} from './tasklist.ts';
66
import {registerGlobalSelectorFunc} from '../modules/observer.ts';
77

88
// code that runs for all markup content
99
export function initMarkupContent(): void {
1010
registerGlobalSelectorFunc('.markup', (el: HTMLElement) => {
11-
initMarkupCodeCopy(el);
11+
initMarkupCodeBlocks(el);
1212
initMarkupTasklist(el);
1313
initMarkupCodeMermaid(el);
1414
initMarkupCodeMath(el);

0 commit comments

Comments
 (0)