diff options
author | silverwind <me@silverwind.io> | 2024-03-15 03:05:31 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-15 02:05:31 +0000 |
commit | 256a1eeb9a67b18c62a10f5909b584b7b220848a (patch) | |
tree | 0a7cb048ebb91a199cfa3dec045992a027721073 /web_src | |
parent | 4a377c033608d64a7a3e352d1a55955dcc988f87 (diff) | |
download | gitea-256a1eeb9a67b18c62a10f5909b584b7b220848a.tar.gz gitea-256a1eeb9a67b18c62a10f5909b584b7b220848a.zip |
Add `<overflow-menu>`, rename webcomponents (#29400)
1. Add `<overflow-menu>` web component
2. Rename `<gitea-origin-url>` to `<origin-url>` and make filenames
match.
<img width="439" alt="image"
src="https://github.com/go-gitea/gitea/assets/115237/2fbe4ca4-110b-4ad2-8e17-c1e116ccbd74">
<img width="444" alt="Screenshot 2024-03-02 at 21 36 52"
src="https://github.com/go-gitea/gitea/assets/115237/aa8f786e-dc8c-4030-b12d-7cfb74bdfd6e">
<img width="537" alt="Screenshot 2024-03-03 at 03 05 06"
src="https://github.com/go-gitea/gitea/assets/115237/fddd50aa-adf1-4b4b-bd7f-caf30c7b2245">
![image](https://github.com/go-gitea/gitea/assets/115237/0f43770c-834c-4a05-8e3d-d30eb8653786)
![image](https://github.com/go-gitea/gitea/assets/115237/4b4c6bd7-843f-4f49-808f-6b3aed5e9f9a)
TODO:
- [x] Check if removal of `requestAnimationFrame` is possible to avoid
flash of content. Likely needs a `MutationObserver`.
- [x] Hide tippy when button is removed from DOM.
- [x] ~~Implement right-aligned items
(https://github.com/go-gitea/gitea/pull/28976)~~. Not going to do it.
- [x] Clean up CSS so base element has no background and add background
via tailwind instead.
- [x] Use it for org and user page.
---------
Co-authored-by: Giteabot <teabot@gitea.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Diffstat (limited to 'web_src')
-rw-r--r-- | web_src/css/base.css | 69 | ||||
-rw-r--r-- | web_src/css/modules/tippy.css | 29 | ||||
-rw-r--r-- | web_src/css/repo.css | 10 | ||||
-rw-r--r-- | web_src/css/repo/header.css | 11 | ||||
-rw-r--r-- | web_src/css/repo/linebutton.css | 5 | ||||
-rw-r--r-- | web_src/css/shared/repoorg.css | 7 | ||||
-rw-r--r-- | web_src/js/components/DashboardRepoList.vue | 62 | ||||
-rw-r--r-- | web_src/js/modules/tippy.js | 14 | ||||
-rw-r--r-- | web_src/js/webcomponents/README.md | 7 | ||||
-rw-r--r-- | web_src/js/webcomponents/absolute-date.js (renamed from web_src/js/webcomponents/GiteaAbsoluteDate.js) | 2 | ||||
-rw-r--r-- | web_src/js/webcomponents/index.js | 5 | ||||
-rw-r--r-- | web_src/js/webcomponents/origin-url.js (renamed from web_src/js/webcomponents/GiteaOriginUrl.js) | 2 | ||||
-rw-r--r-- | web_src/js/webcomponents/origin-url.test.js (renamed from web_src/js/webcomponents/GiteaOriginUrl.test.js) | 2 | ||||
-rw-r--r-- | web_src/js/webcomponents/overflow-menu.js | 179 | ||||
-rw-r--r-- | web_src/js/webcomponents/polyfills.js (renamed from web_src/js/webcomponents/polyfill.js) | 0 | ||||
-rw-r--r-- | web_src/js/webcomponents/webcomponents.js | 6 |
16 files changed, 271 insertions, 139 deletions
diff --git a/web_src/css/base.css b/web_src/css/base.css index 1c6b3fa488..510a28ad9f 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -248,7 +248,7 @@ a.label, } .page-content .header-wrapper, -.page-content .new-menu { +.page-content overflow-menu { margin-top: -15px !important; padding-top: 15px !important; } @@ -1353,75 +1353,21 @@ strong.attention-caution, span.attention-caution { } } -.ui.menu.new-menu { - margin-bottom: 15px; - background: var(--color-header-wrapper); +overflow-menu { + margin-bottom: 15px !important; border-bottom: 1px solid var(--color-secondary) !important; - overflow: auto; + display: flex; } -.ui.menu.new-menu .new-menu-inner { +overflow-menu .overflow-menu-items { display: flex; - margin-left: auto; - margin-right: auto; - overflow-x: auto; - width: 100%; - mask-image: linear-gradient(to right, #000 0%, #000 calc(100% - 60px), transparent 100%); - -webkit-mask-image: linear-gradient(to right, #000 0%, #000 calc(100% - 60px), transparent 100%); + flex: 1; } -.ui.menu.new-menu .item { +overflow-menu .overflow-menu-items .item { margin-bottom: 0 !important; /* reset fomantic's margin, because the active menu has special bottom border */ } -@media (max-width: 767.98px) { - .ui.menu.new-menu .item { - width: auto !important; - } -} - -.ui.menu.new-menu .item:first-child { - margin-left: auto; /* "justify-content: center" doesn't work with "overflow: auto", so use margin: auto */ -} - -.ui.menu.new-menu .item:last-child { - padding-right: 30px !important; - margin-right: auto; -} - -.ui.menu.new-menu::-webkit-scrollbar { - height: 6px; - display: none; -} - -.ui.menu.new-menu::-webkit-scrollbar-track { - background: none !important; -} - -.ui.menu.new-menu::-webkit-scrollbar-thumb { - box-shadow: none !important; -} - -.ui.menu.new-menu:hover::-webkit-scrollbar { - display: block; -} - -.repos-search { - padding-bottom: 0 !important; -} - -.repos-filter { - margin-top: 0 !important; - border-bottom-width: 0 !important; - margin-bottom: 2px !important; - justify-content: space-evenly; -} - -.ui.secondary.pointing.menu.repos-filter .item { - padding-left: 4.5px; - padding-right: 4.5px; -} - .activity-bar-graph { background-color: var(--color-primary); color: var(--color-primary-contrast); @@ -1927,7 +1873,6 @@ table th[data-sortt-desc] .svg { background: var(--color-body); border-color: var(--color-secondary); color: var(--color-text); - margin-top: 1px; /* offset fomantic's margin-bottom: -1px */ } .ui.segment .ui.tabular.menu .active.item, diff --git a/web_src/css/modules/tippy.css b/web_src/css/modules/tippy.css index d65ecc89fb..76d36b4293 100644 --- a/web_src/css/modules/tippy.css +++ b/web_src/css/modules/tippy.css @@ -5,6 +5,11 @@ display: none !important; } +/* show target element once it's been moved by tippy.js */ +.tippy-content .tippy-target { + display: unset !important; +} + [data-tippy-root] { max-width: calc(100vw - 32px); } @@ -46,18 +51,40 @@ .tippy-box[data-theme="menu"] { background-color: var(--color-menu); color: var(--color-text); + box-shadow: 0 6px 18px var(--color-shadow); } .tippy-box[data-theme="menu"] .tippy-content { - padding: 0; + padding: 4px 0; } .tippy-box[data-theme="menu"] .tippy-svg-arrow-inner { fill: var(--color-menu); } +.tippy-box[data-theme="menu"] .item { + display: flex; + align-items: center; + padding: 9px 18px; + color: inherit; + text-decoration: none; + gap: 10px; +} + +.tippy-box[data-theme="menu"] .item:hover { + background: var(--color-hover); +} + +.tippy-box[data-theme="menu"] .item:focus { + background: var(--color-active); +} + /* box-with-header theme to look like .ui.attached.segment. can contain .ui.attached.header */ +.tippy-box[data-theme="box-with-header"] { + box-shadow: 0 6px 18px var(--color-shadow); +} + .tippy-box[data-theme="box-with-header"] .tippy-content { background: var(--color-box-body); border-radius: var(--border-radius); diff --git a/web_src/css/repo.css b/web_src/css/repo.css index c9c27acf34..23b4e94a06 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -2787,16 +2787,6 @@ tbody.commit-list { border-left: 1px solid var(--color-secondary); } -.repository .ui.menu.new-menu { - background: none !important; -} - -@media (max-width: 1200px) { - .repository .ui.menu.new-menu::after { - background: none !important; - } -} - .migrate-entries { display: grid !important; grid-template-columns: repeat(3, 1fr); diff --git a/web_src/css/repo/header.css b/web_src/css/repo/header.css index 0eb03136ef..4461e3338e 100644 --- a/web_src/css/repo/header.css +++ b/web_src/css/repo/header.css @@ -74,17 +74,6 @@ background-color: var(--color-header-wrapper); } -.repository .header-wrapper .new-menu { - padding-top: 0 !important; - margin-top: 0 !important; - margin-bottom: 0 !important; -} - -.repository .header-wrapper .new-menu .item { - margin-left: 0 !important; - margin-right: 0 !important; -} - @media (max-width: 767.98px) { .repo-header .flex-item { flex-grow: 1; diff --git a/web_src/css/repo/linebutton.css b/web_src/css/repo/linebutton.css index 1e5e51eac5..79be5a7a9e 100644 --- a/web_src/css/repo/linebutton.css +++ b/web_src/css/repo/linebutton.css @@ -2,11 +2,6 @@ color: var(--color-text-dark) !important; } -.code-line-menu { - width: auto !important; - border: none !important; /* the border is provided by tippy, not using the `.ui.menu` border */ -} - .code-line-button { background-color: var(--color-menu); color: var(--color-text-light); diff --git a/web_src/css/shared/repoorg.css b/web_src/css/shared/repoorg.css index 7f0a805d0f..5573ae47b8 100644 --- a/web_src/css/shared/repoorg.css +++ b/web_src/css/shared/repoorg.css @@ -5,13 +5,6 @@ margin-left: 15px; } -.repository .ui.secondary.stackable.pointing.menu, -.organization .ui.secondary.stackable.pointing.menu { - flex-wrap: wrap; - margin-top: 5px; - margin-bottom: 10px; -} - .repository .ui.tabs.container, .organization .ui.tabs.container { margin-top: 14px; diff --git a/web_src/js/components/DashboardRepoList.vue b/web_src/js/components/DashboardRepoList.vue index 2e8f335ce5..b9ee531d2a 100644 --- a/web_src/js/components/DashboardRepoList.vue +++ b/web_src/js/components/DashboardRepoList.vue @@ -384,28 +384,30 @@ export default sfc; // activate the IDE's Vue plugin </div> </div> </div> - <div class="ui secondary tiny pointing borderless menu center grid repos-filter"> - <a class="item" :class="{active: reposFilter === 'all'}" @click="changeReposFilter('all')"> - {{ textAll }} - <div v-show="reposFilter === 'all'" class="ui circular mini grey label">{{ repoTypeCount }}</div> - </a> - <a class="item" :class="{active: reposFilter === 'sources'}" @click="changeReposFilter('sources')"> - {{ textSources }} - <div v-show="reposFilter === 'sources'" class="ui circular mini grey label">{{ repoTypeCount }}</div> - </a> - <a class="item" :class="{active: reposFilter === 'forks'}" @click="changeReposFilter('forks')"> - {{ textForks }} - <div v-show="reposFilter === 'forks'" class="ui circular mini grey label">{{ repoTypeCount }}</div> - </a> - <a class="item" :class="{active: reposFilter === 'mirrors'}" @click="changeReposFilter('mirrors')" v-if="isMirrorsEnabled"> - {{ textMirrors }} - <div v-show="reposFilter === 'mirrors'" class="ui circular mini grey label">{{ repoTypeCount }}</div> - </a> - <a class="item" :class="{active: reposFilter === 'collaborative'}" @click="changeReposFilter('collaborative')"> - {{ textCollaborative }} - <div v-show="reposFilter === 'collaborative'" class="ui circular mini grey label">{{ repoTypeCount }}</div> - </a> - </div> + <overflow-menu class="ui secondary pointing tabular borderless menu repos-filter"> + <div class="overflow-menu-items tw-justify-center"> + <a class="item" tabindex="0" :class="{active: reposFilter === 'all'}" @click="changeReposFilter('all')"> + {{ textAll }} + <div v-show="reposFilter === 'all'" class="ui circular mini grey label">{{ repoTypeCount }}</div> + </a> + <a class="item" tabindex="0" :class="{active: reposFilter === 'sources'}" @click="changeReposFilter('sources')"> + {{ textSources }} + <div v-show="reposFilter === 'sources'" class="ui circular mini grey label">{{ repoTypeCount }}</div> + </a> + <a class="item" tabindex="0" :class="{active: reposFilter === 'forks'}" @click="changeReposFilter('forks')"> + {{ textForks }} + <div v-show="reposFilter === 'forks'" class="ui circular mini grey label">{{ repoTypeCount }}</div> + </a> + <a class="item" tabindex="0" :class="{active: reposFilter === 'mirrors'}" @click="changeReposFilter('mirrors')" v-if="isMirrorsEnabled"> + {{ textMirrors }} + <div v-show="reposFilter === 'mirrors'" class="ui circular mini grey label">{{ repoTypeCount }}</div> + </a> + <a class="item" tabindex="0" :class="{active: reposFilter === 'collaborative'}" @click="changeReposFilter('collaborative')"> + {{ textCollaborative }} + <div v-show="reposFilter === 'collaborative'" class="ui circular mini grey label">{{ repoTypeCount }}</div> + </a> + </div> + </overflow-menu> </div> <div v-if="repos.length" class="ui attached table segment gt-rounded-bottom"> <ul class="repo-owner-name-list"> @@ -501,6 +503,22 @@ ul li:not(:last-child) { border-bottom: 1px solid var(--color-secondary); } +.repos-search { + padding-bottom: 0 !important; +} + +.repos-filter { + padding-top: 0 !important; + margin-top: 0 !important; + border-bottom-width: 0 !important; + margin-bottom: 2px !important; +} + +.repos-filter .item { + padding-left: 6px !important; + padding-right: 6px !important; +} + .repo-list-link { min-width: 0; /* for text truncation */ display: flex; diff --git a/web_src/js/modules/tippy.js b/web_src/js/modules/tippy.js index 489afc0ae1..e7eb39f457 100644 --- a/web_src/js/modules/tippy.js +++ b/web_src/js/modules/tippy.js @@ -7,7 +7,8 @@ const visibleInstances = new Set(); export function createTippy(target, opts = {}) { // the callback functions should be destructured from opts, // because we should use our own wrapper functions to handle them, do not let the user override them - const {onHide, onShow, onDestroy, ...other} = opts; + const {onHide, onShow, onDestroy, role, theme, ...other} = opts; + const instance = tippy(target, { appendTo: document.body, animation: false, @@ -35,17 +36,14 @@ export function createTippy(target, opts = {}) { return onShow?.(instance); }, arrow: `<svg width="16" height="7"><path d="m0 7 8-7 8 7Z" class="tippy-svg-arrow-outer"/><path d="m0 8 8-7 8 7Z" class="tippy-svg-arrow-inner"/></svg>`, - role: 'menu', // HTML role attribute, only tooltips should use "tooltip" - theme: other.role || 'menu', // CSS theme, either "tooltip", "menu" or "box-with-header" + role: role || 'menu', // HTML role attribute + theme: theme || role || 'menu', // CSS theme, either "tooltip", "menu" or "box-with-header" plugins: [followCursor], ...other, }); - // for popups where content refers to a DOM element, we use the 'tippy-target' class - // to initially hide the content, now we can remove it as the content has been removed - // from the DOM by tippy - if (other.content instanceof Element) { - other.content.classList.remove('tippy-target'); + if (role === 'menu') { + target.setAttribute('aria-haspopup', 'true'); } return instance; diff --git a/web_src/js/webcomponents/README.md b/web_src/js/webcomponents/README.md index 0fde507310..45af58e1d2 100644 --- a/web_src/js/webcomponents/README.md +++ b/web_src/js/webcomponents/README.md @@ -6,7 +6,6 @@ https://developer.mozilla.org/en-US/docs/Web/Web_Components # Guidelines -* These components are loaded in `<head>` (before DOM body), - so they should have their own dependencies and should be very light, - then they won't affect the page loading time too much. -* If the component is not a public one, it's suggested to have its own `Gitea` or `gitea-` prefix to avoid conflicts. +* These components are loaded in `<head>` (before DOM body) in a separate entry point, they need to be lightweight to not affect the page loading time too much. +* Do not import `svg.js` into a web component because that file is currently not tree-shakeable, import svg files individually insteat. +* All our components must be added to `webpack.config.js` so they work correctly in Vue. diff --git a/web_src/js/webcomponents/GiteaAbsoluteDate.js b/web_src/js/webcomponents/absolute-date.js index 660aa99d07..d12ea0a437 100644 --- a/web_src/js/webcomponents/GiteaAbsoluteDate.js +++ b/web_src/js/webcomponents/absolute-date.js @@ -1,4 +1,4 @@ -window.customElements.define('gitea-absolute-date', class extends HTMLElement { +window.customElements.define('absolute-date', class extends HTMLElement { static observedAttributes = ['date', 'year', 'month', 'weekday', 'day']; update = () => { diff --git a/web_src/js/webcomponents/index.js b/web_src/js/webcomponents/index.js new file mode 100644 index 0000000000..7cec9da734 --- /dev/null +++ b/web_src/js/webcomponents/index.js @@ -0,0 +1,5 @@ +import './polyfills.js'; +import '@github/relative-time-element'; +import './origin-url.js'; +import './overflow-menu.js'; +import './absolute-date.js'; diff --git a/web_src/js/webcomponents/GiteaOriginUrl.js b/web_src/js/webcomponents/origin-url.js index 6e6f84d739..09aa77f2c0 100644 --- a/web_src/js/webcomponents/GiteaOriginUrl.js +++ b/web_src/js/webcomponents/origin-url.js @@ -15,7 +15,7 @@ export function toOriginUrl(urlStr) { return urlStr; } -window.customElements.define('gitea-origin-url', class extends HTMLElement { +window.customElements.define('origin-url', class extends HTMLElement { connectedCallback() { this.textContent = toOriginUrl(this.getAttribute('data-url')); } diff --git a/web_src/js/webcomponents/GiteaOriginUrl.test.js b/web_src/js/webcomponents/origin-url.test.js index f0629842b8..3b2ab89f2a 100644 --- a/web_src/js/webcomponents/GiteaOriginUrl.test.js +++ b/web_src/js/webcomponents/origin-url.test.js @@ -1,4 +1,4 @@ -import {toOriginUrl} from './GiteaOriginUrl.js'; +import {toOriginUrl} from './origin-url.js'; test('toOriginUrl', () => { const oldLocation = window.location; diff --git a/web_src/js/webcomponents/overflow-menu.js b/web_src/js/webcomponents/overflow-menu.js new file mode 100644 index 0000000000..9fa4585567 --- /dev/null +++ b/web_src/js/webcomponents/overflow-menu.js @@ -0,0 +1,179 @@ +import {throttle} from 'throttle-debounce'; +import {createTippy} from '../modules/tippy.js'; +import {isDocumentFragmentOrElementNode} from '../utils/dom.js'; +import octiconKebabHorizontal from '../../../public/assets/img/svg/octicon-kebab-horizontal.svg'; + +window.customElements.define('overflow-menu', class extends HTMLElement { + updateItems = throttle(100, () => { + if (!this.tippyContent) { + const div = document.createElement('div'); + div.classList.add('tippy-target'); + div.tabIndex = '-1'; // for initial focus, programmatic focus only + div.addEventListener('keydown', (e) => { + if (e.key === 'Tab') { + const items = this.tippyContent.querySelectorAll('[role="menuitem"]'); + if (e.shiftKey) { + if (document.activeElement === items[0]) { + e.preventDefault(); + items[items.length - 1].focus(); + } + } else { + if (document.activeElement === items[items.length - 1]) { + e.preventDefault(); + items[0].focus(); + } + } + } else if (e.key === 'Escape') { + e.preventDefault(); + e.stopPropagation(); + this.button._tippy.hide(); + this.button.focus(); + } else if (e.key === ' ' || e.code === 'Enter') { + if (document.activeElement?.matches('[role="menuitem"]')) { + e.preventDefault(); + e.stopPropagation(); + document.activeElement.click(); + } + } else if (e.key === 'ArrowDown') { + if (document.activeElement?.matches('.tippy-target')) { + e.preventDefault(); + e.stopPropagation(); + document.activeElement.querySelector('[role="menuitem"]:first-of-type').focus(); + } else if (document.activeElement?.matches('[role="menuitem"]')) { + e.preventDefault(); + e.stopPropagation(); + document.activeElement.nextElementSibling?.focus(); + } + } else if (e.key === 'ArrowUp') { + if (document.activeElement?.matches('.tippy-target')) { + e.preventDefault(); + e.stopPropagation(); + document.activeElement.querySelector('[role="menuitem"]:last-of-type').focus(); + } else if (document.activeElement?.matches('[role="menuitem"]')) { + e.preventDefault(); + e.stopPropagation(); + document.activeElement.previousElementSibling?.focus(); + } + } + }); + this.append(div); + this.tippyContent = div; + } + + // move items in tippy back into the menu items for subsequent measurement + for (const item of this.tippyItems || []) { + this.menuItemsEl.append(item); + } + + // measure which items are partially outside the element and move them into the button menu + this.tippyItems = []; + const menuRight = this.offsetLeft + this.offsetWidth; + const menuItems = this.menuItemsEl.querySelectorAll('.item'); + for (const item of menuItems) { + const itemRight = item.offsetLeft + item.offsetWidth; + if (menuRight - itemRight < 38) { // roughly the width of .overflow-menu-button + this.tippyItems.push(item); + } + } + + // if there are no overflown items, remove any previously created button + if (!this.tippyItems?.length) { + const btn = this.querySelector('.overflow-menu-button'); + btn?._tippy?.destroy(); + btn?.remove(); + return; + } + + // remove aria role from items that moved from tippy to menu + for (const item of menuItems) { + if (!this.tippyItems.includes(item)) { + item.removeAttribute('role'); + } + } + + // move all items that overflow into tippy + for (const item of this.tippyItems) { + item.setAttribute('role', 'menuitem'); + this.tippyContent.append(item); + } + + // update existing tippy + if (this.button?._tippy) { + this.button._tippy.setContent(this.tippyContent); + return; + } + + // create button initially + const btn = document.createElement('button'); + btn.classList.add('overflow-menu-button', 'btn', 'tw-px-2', 'hover:tw-text-text-dark'); + btn.setAttribute('aria-label', window.config.i18n.more_items); + btn.innerHTML = octiconKebabHorizontal; + this.append(btn); + this.button = btn; + + createTippy(btn, { + trigger: 'click', + hideOnClick: true, + interactive: true, + placement: 'bottom-end', + role: 'menu', + content: this.tippyContent, + onShow: () => { // FIXME: onShown doesn't work (never be called) + setTimeout(() => { + this.tippyContent.focus(); + }, 0); + }, + }); + }); + + init() { + // ResizeObserver triggers on initial render, so we don't manually call `updateItems` here which + // also avoids a full-page FOUC in Firefox that happens when `updateItems` is called too soon. + this.resizeObserver = new ResizeObserver((entries) => { + for (const entry of entries) { + const newWidth = entry.contentBoxSize[0].inlineSize; + if (newWidth !== this.lastWidth) { + requestAnimationFrame(() => { + this.updateItems(); + }); + this.lastWidth = newWidth; + } + } + }); + this.resizeObserver.observe(this); + } + + connectedCallback() { + this.setAttribute('role', 'navigation'); + + // check whether the mandatory `.overflow-menu-items` element is present initially which happens + // with Vue which renders differently than browsers. If it's not there, like in the case of browser + // template rendering, wait for its addition. + // The eslint rule is not sophisticated enough or aware of this problem, see + // https://github.com/43081j/eslint-plugin-wc/pull/130 + const menuItemsEl = this.querySelector('.overflow-menu-items'); // eslint-disable-line wc/no-child-traversal-in-connectedcallback + if (menuItemsEl) { + this.menuItemsEl = menuItemsEl; + this.init(); + } else { + this.mutationObserver = new MutationObserver((mutations) => { + for (const mutation of mutations) { + for (const node of mutation.addedNodes) { + if (!isDocumentFragmentOrElementNode(node)) continue; + if (node.classList.contains('overflow-menu-items')) { + this.menuItemsEl = node; + this.mutationObserver?.disconnect(); + this.init(); + } + } + } + }); + this.mutationObserver.observe(this, {childList: true}); + } + } + + disconnectedCallback() { + this.mutationObserver?.disconnect(); + this.resizeObserver?.disconnect(); + } +}); diff --git a/web_src/js/webcomponents/polyfill.js b/web_src/js/webcomponents/polyfills.js index 88c7276881..88c7276881 100644 --- a/web_src/js/webcomponents/polyfill.js +++ b/web_src/js/webcomponents/polyfills.js diff --git a/web_src/js/webcomponents/webcomponents.js b/web_src/js/webcomponents/webcomponents.js deleted file mode 100644 index 03348d895f..0000000000 --- a/web_src/js/webcomponents/webcomponents.js +++ /dev/null @@ -1,6 +0,0 @@ -import '@webcomponents/custom-elements'; // polyfill for some browsers like PaleMoon -import './polyfill.js'; - -import '@github/relative-time-element'; -import './GiteaOriginUrl.js'; -import './GiteaAbsoluteDate.js'; |