feat(ui): redesign user profile actions layout (#7906)
Related: https://codeberg.org/forgejo/forgejo/pulls/3950#issue-785253, https://codeberg.org/forgejo/forgejo/pulls/3950#issuecomment-1998551.
## Links in dropdown
* move _admin only_ User details link here, give it always-visible text
* add new _self only_ Edit profile link here
* move RSS feed link here
* add new Atom feed link here, previously unadvertised
* add new SSH keys link here (`.keys`), previously unadvertised
* add new GPG keys link here (`.gpg`), previously unadvertised
* move Block/Unblock button here
* move Report abuse link here
If primary action is available (Follow/Unfollow), dropdown with more actions goes after it. If not, it is in line with followers, in place where RSS feed button used to be.
## New dropdown
Related: https://codeberg.org/forgejo/design/issues/23, https://codeberg.org/forgejo/forgejo/issues/3853, https://codeberg.org/0ko/forgejo/issues/2.
Implemented a new dropdown: noJS-usable, JS-enhanced for better keyboard navigation and a11y.
Styling is mostly same as the existing ones have, but row density depends on `@media` pointer type.
My choice of CSS properties have been influenced of these:
* https://github.com/picocss/pico/commit/72a3adb16b2f3248b456da823502f166510720a0
* https://github.com/picocss/pico/commit/51dd2293cab8d77cf13fc2c32b6053ffa654bc56
Inspired-by: KiranMantha <kiranv.mantha@gmail.com>
Inspired-by: Lucas Larroche <lucas@larroche.com>
Co-authored-by: Beowulf <beowulf@beocode.eu>
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/7906
Reviewed-by: Otto <otto@codeberg.org>
Reviewed-by: Beowulf <beowulf@beocode.eu>
Co-authored-by: 0ko <0ko@noreply.codeberg.org>
Co-committed-by: 0ko <0ko@noreply.codeberg.org>
2025-06-24 08:16:51 -04:00
|
|
|
// Copyright 2025 The Forgejo Authors. All rights reserved.
|
|
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
|
|
|
|
|
|
// Details can be opened by clicking summary or by pressing Space or Enter while
|
|
|
|
|
// being focused on summary. But without JS options for closing it are limited.
|
|
|
|
|
// Event listeners in this file provide more convenient options for that:
|
|
|
|
|
// click iteration with anything on the page and pressing Escape.
|
|
|
|
|
|
|
|
|
|
export function initDropdowns() {
|
2025-11-10 07:35:38 -05:00
|
|
|
// Close open dropdown by clicking elsewhere on the page
|
|
|
|
|
document.addEventListener('click', (event: MouseEvent) => {
|
feat(ui): redesign user profile actions layout (#7906)
Related: https://codeberg.org/forgejo/forgejo/pulls/3950#issue-785253, https://codeberg.org/forgejo/forgejo/pulls/3950#issuecomment-1998551.
## Links in dropdown
* move _admin only_ User details link here, give it always-visible text
* add new _self only_ Edit profile link here
* move RSS feed link here
* add new Atom feed link here, previously unadvertised
* add new SSH keys link here (`.keys`), previously unadvertised
* add new GPG keys link here (`.gpg`), previously unadvertised
* move Block/Unblock button here
* move Report abuse link here
If primary action is available (Follow/Unfollow), dropdown with more actions goes after it. If not, it is in line with followers, in place where RSS feed button used to be.
## New dropdown
Related: https://codeberg.org/forgejo/design/issues/23, https://codeberg.org/forgejo/forgejo/issues/3853, https://codeberg.org/0ko/forgejo/issues/2.
Implemented a new dropdown: noJS-usable, JS-enhanced for better keyboard navigation and a11y.
Styling is mostly same as the existing ones have, but row density depends on `@media` pointer type.
My choice of CSS properties have been influenced of these:
* https://github.com/picocss/pico/commit/72a3adb16b2f3248b456da823502f166510720a0
* https://github.com/picocss/pico/commit/51dd2293cab8d77cf13fc2c32b6053ffa654bc56
Inspired-by: KiranMantha <kiranv.mantha@gmail.com>
Inspired-by: Lucas Larroche <lucas@larroche.com>
Co-authored-by: Beowulf <beowulf@beocode.eu>
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/7906
Reviewed-by: Otto <otto@codeberg.org>
Reviewed-by: Beowulf <beowulf@beocode.eu>
Co-authored-by: 0ko <0ko@noreply.codeberg.org>
Co-committed-by: 0ko <0ko@noreply.codeberg.org>
2025-06-24 08:16:51 -04:00
|
|
|
const dropdown = document.querySelector<HTMLDetailsElement>('details.dropdown[open]');
|
2025-11-10 07:35:38 -05:00
|
|
|
if (dropdown === null) {
|
|
|
|
|
// No open dropdowns on page, nothing to do
|
|
|
|
|
return;
|
|
|
|
|
}
|
feat(ui): redesign user profile actions layout (#7906)
Related: https://codeberg.org/forgejo/forgejo/pulls/3950#issue-785253, https://codeberg.org/forgejo/forgejo/pulls/3950#issuecomment-1998551.
## Links in dropdown
* move _admin only_ User details link here, give it always-visible text
* add new _self only_ Edit profile link here
* move RSS feed link here
* add new Atom feed link here, previously unadvertised
* add new SSH keys link here (`.keys`), previously unadvertised
* add new GPG keys link here (`.gpg`), previously unadvertised
* move Block/Unblock button here
* move Report abuse link here
If primary action is available (Follow/Unfollow), dropdown with more actions goes after it. If not, it is in line with followers, in place where RSS feed button used to be.
## New dropdown
Related: https://codeberg.org/forgejo/design/issues/23, https://codeberg.org/forgejo/forgejo/issues/3853, https://codeberg.org/0ko/forgejo/issues/2.
Implemented a new dropdown: noJS-usable, JS-enhanced for better keyboard navigation and a11y.
Styling is mostly same as the existing ones have, but row density depends on `@media` pointer type.
My choice of CSS properties have been influenced of these:
* https://github.com/picocss/pico/commit/72a3adb16b2f3248b456da823502f166510720a0
* https://github.com/picocss/pico/commit/51dd2293cab8d77cf13fc2c32b6053ffa654bc56
Inspired-by: KiranMantha <kiranv.mantha@gmail.com>
Inspired-by: Lucas Larroche <lucas@larroche.com>
Co-authored-by: Beowulf <beowulf@beocode.eu>
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/7906
Reviewed-by: Otto <otto@codeberg.org>
Reviewed-by: Beowulf <beowulf@beocode.eu>
Co-authored-by: 0ko <0ko@noreply.codeberg.org>
Co-committed-by: 0ko <0ko@noreply.codeberg.org>
2025-06-24 08:16:51 -04:00
|
|
|
|
|
|
|
|
const target = event.target as HTMLElement;
|
2025-11-10 07:35:38 -05:00
|
|
|
if (dropdown.contains(target)) {
|
|
|
|
|
// User clicked something in the open dropdown, don't interfere
|
|
|
|
|
return;
|
|
|
|
|
}
|
feat(ui): redesign user profile actions layout (#7906)
Related: https://codeberg.org/forgejo/forgejo/pulls/3950#issue-785253, https://codeberg.org/forgejo/forgejo/pulls/3950#issuecomment-1998551.
## Links in dropdown
* move _admin only_ User details link here, give it always-visible text
* add new _self only_ Edit profile link here
* move RSS feed link here
* add new Atom feed link here, previously unadvertised
* add new SSH keys link here (`.keys`), previously unadvertised
* add new GPG keys link here (`.gpg`), previously unadvertised
* move Block/Unblock button here
* move Report abuse link here
If primary action is available (Follow/Unfollow), dropdown with more actions goes after it. If not, it is in line with followers, in place where RSS feed button used to be.
## New dropdown
Related: https://codeberg.org/forgejo/design/issues/23, https://codeberg.org/forgejo/forgejo/issues/3853, https://codeberg.org/0ko/forgejo/issues/2.
Implemented a new dropdown: noJS-usable, JS-enhanced for better keyboard navigation and a11y.
Styling is mostly same as the existing ones have, but row density depends on `@media` pointer type.
My choice of CSS properties have been influenced of these:
* https://github.com/picocss/pico/commit/72a3adb16b2f3248b456da823502f166510720a0
* https://github.com/picocss/pico/commit/51dd2293cab8d77cf13fc2c32b6053ffa654bc56
Inspired-by: KiranMantha <kiranv.mantha@gmail.com>
Inspired-by: Lucas Larroche <lucas@larroche.com>
Co-authored-by: Beowulf <beowulf@beocode.eu>
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/7906
Reviewed-by: Otto <otto@codeberg.org>
Reviewed-by: Beowulf <beowulf@beocode.eu>
Co-authored-by: 0ko <0ko@noreply.codeberg.org>
Co-committed-by: 0ko <0ko@noreply.codeberg.org>
2025-06-24 08:16:51 -04:00
|
|
|
|
2025-11-10 07:35:38 -05:00
|
|
|
// User clicked something elsewhere, close the open dropdown
|
feat(ui): redesign user profile actions layout (#7906)
Related: https://codeberg.org/forgejo/forgejo/pulls/3950#issue-785253, https://codeberg.org/forgejo/forgejo/pulls/3950#issuecomment-1998551.
## Links in dropdown
* move _admin only_ User details link here, give it always-visible text
* add new _self only_ Edit profile link here
* move RSS feed link here
* add new Atom feed link here, previously unadvertised
* add new SSH keys link here (`.keys`), previously unadvertised
* add new GPG keys link here (`.gpg`), previously unadvertised
* move Block/Unblock button here
* move Report abuse link here
If primary action is available (Follow/Unfollow), dropdown with more actions goes after it. If not, it is in line with followers, in place where RSS feed button used to be.
## New dropdown
Related: https://codeberg.org/forgejo/design/issues/23, https://codeberg.org/forgejo/forgejo/issues/3853, https://codeberg.org/0ko/forgejo/issues/2.
Implemented a new dropdown: noJS-usable, JS-enhanced for better keyboard navigation and a11y.
Styling is mostly same as the existing ones have, but row density depends on `@media` pointer type.
My choice of CSS properties have been influenced of these:
* https://github.com/picocss/pico/commit/72a3adb16b2f3248b456da823502f166510720a0
* https://github.com/picocss/pico/commit/51dd2293cab8d77cf13fc2c32b6053ffa654bc56
Inspired-by: KiranMantha <kiranv.mantha@gmail.com>
Inspired-by: Lucas Larroche <lucas@larroche.com>
Co-authored-by: Beowulf <beowulf@beocode.eu>
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/7906
Reviewed-by: Otto <otto@codeberg.org>
Reviewed-by: Beowulf <beowulf@beocode.eu>
Co-authored-by: 0ko <0ko@noreply.codeberg.org>
Co-committed-by: 0ko <0ko@noreply.codeberg.org>
2025-06-24 08:16:51 -04:00
|
|
|
dropdown.removeAttribute('open');
|
|
|
|
|
});
|
|
|
|
|
|
2025-11-10 07:35:38 -05:00
|
|
|
// Close open dropdown when it is unfocused (e.g. when user pressed Tab or Shift+Tab),
|
|
|
|
|
// but not when user lost focus completely (e.g. browser window became unfocused)
|
|
|
|
|
document.addEventListener('focusout', (event: FocusEvent) => {
|
|
|
|
|
const dropdown = document.querySelector<HTMLDetailsElement>('details.dropdown[open]');
|
|
|
|
|
if (dropdown === null) {
|
|
|
|
|
// No open dropdowns on page, nothing to do
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const target = event.target as HTMLElement;
|
|
|
|
|
const newTarget = event.relatedTarget as HTMLElement;
|
|
|
|
|
|
|
|
|
|
if (newTarget !== null && dropdown.contains(target) && !dropdown.contains(newTarget)) {
|
|
|
|
|
// The previously focused element was within the open dropdown, but something
|
|
|
|
|
// else is now focused, so the dropdown should be closed
|
|
|
|
|
dropdown.removeAttribute('open');
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Keyboard interaction with dropdowns
|
|
|
|
|
document.addEventListener('keydown', (event: KeyboardEvent) => {
|
|
|
|
|
if (!['Escape', 'ArrowUp', 'ArrowDown'].includes(event.key)) {
|
|
|
|
|
// This eventListener is only concerned about a few keys
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (document.activeElement.localName === 'summary' && event.key === 'ArrowDown') {
|
|
|
|
|
const parentDropdown = document.activeElement.parentElement as HTMLDetailsElement;
|
|
|
|
|
if (parentDropdown.classList.contains('dropdown')) {
|
|
|
|
|
// User pressed ArrowDown on a focused summary of a closed dropdown.
|
|
|
|
|
// We'll open the dropdown and focus it's first item
|
|
|
|
|
parentDropdown.setAttribute('open', 'true');
|
|
|
|
|
parentDropdown.querySelector<HTMLElement>('.content > ul > li > :is(a, button)').focus();
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
feat(ui): redesign user profile actions layout (#7906)
Related: https://codeberg.org/forgejo/forgejo/pulls/3950#issue-785253, https://codeberg.org/forgejo/forgejo/pulls/3950#issuecomment-1998551.
## Links in dropdown
* move _admin only_ User details link here, give it always-visible text
* add new _self only_ Edit profile link here
* move RSS feed link here
* add new Atom feed link here, previously unadvertised
* add new SSH keys link here (`.keys`), previously unadvertised
* add new GPG keys link here (`.gpg`), previously unadvertised
* move Block/Unblock button here
* move Report abuse link here
If primary action is available (Follow/Unfollow), dropdown with more actions goes after it. If not, it is in line with followers, in place where RSS feed button used to be.
## New dropdown
Related: https://codeberg.org/forgejo/design/issues/23, https://codeberg.org/forgejo/forgejo/issues/3853, https://codeberg.org/0ko/forgejo/issues/2.
Implemented a new dropdown: noJS-usable, JS-enhanced for better keyboard navigation and a11y.
Styling is mostly same as the existing ones have, but row density depends on `@media` pointer type.
My choice of CSS properties have been influenced of these:
* https://github.com/picocss/pico/commit/72a3adb16b2f3248b456da823502f166510720a0
* https://github.com/picocss/pico/commit/51dd2293cab8d77cf13fc2c32b6053ffa654bc56
Inspired-by: KiranMantha <kiranv.mantha@gmail.com>
Inspired-by: Lucas Larroche <lucas@larroche.com>
Co-authored-by: Beowulf <beowulf@beocode.eu>
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/7906
Reviewed-by: Otto <otto@codeberg.org>
Reviewed-by: Beowulf <beowulf@beocode.eu>
Co-authored-by: 0ko <0ko@noreply.codeberg.org>
Co-committed-by: 0ko <0ko@noreply.codeberg.org>
2025-06-24 08:16:51 -04:00
|
|
|
|
|
|
|
|
const dropdown = document.querySelector<HTMLDetailsElement>('details.dropdown[open]');
|
2025-11-10 07:35:38 -05:00
|
|
|
// This part of the code only knows how to work with open dropdown
|
|
|
|
|
if (dropdown === null) {
|
|
|
|
|
// No open dropdowns on page, nothing to do
|
|
|
|
|
return;
|
|
|
|
|
}
|
feat(ui): redesign user profile actions layout (#7906)
Related: https://codeberg.org/forgejo/forgejo/pulls/3950#issue-785253, https://codeberg.org/forgejo/forgejo/pulls/3950#issuecomment-1998551.
## Links in dropdown
* move _admin only_ User details link here, give it always-visible text
* add new _self only_ Edit profile link here
* move RSS feed link here
* add new Atom feed link here, previously unadvertised
* add new SSH keys link here (`.keys`), previously unadvertised
* add new GPG keys link here (`.gpg`), previously unadvertised
* move Block/Unblock button here
* move Report abuse link here
If primary action is available (Follow/Unfollow), dropdown with more actions goes after it. If not, it is in line with followers, in place where RSS feed button used to be.
## New dropdown
Related: https://codeberg.org/forgejo/design/issues/23, https://codeberg.org/forgejo/forgejo/issues/3853, https://codeberg.org/0ko/forgejo/issues/2.
Implemented a new dropdown: noJS-usable, JS-enhanced for better keyboard navigation and a11y.
Styling is mostly same as the existing ones have, but row density depends on `@media` pointer type.
My choice of CSS properties have been influenced of these:
* https://github.com/picocss/pico/commit/72a3adb16b2f3248b456da823502f166510720a0
* https://github.com/picocss/pico/commit/51dd2293cab8d77cf13fc2c32b6053ffa654bc56
Inspired-by: KiranMantha <kiranv.mantha@gmail.com>
Inspired-by: Lucas Larroche <lucas@larroche.com>
Co-authored-by: Beowulf <beowulf@beocode.eu>
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/7906
Reviewed-by: Otto <otto@codeberg.org>
Reviewed-by: Beowulf <beowulf@beocode.eu>
Co-authored-by: 0ko <0ko@noreply.codeberg.org>
Co-committed-by: 0ko <0ko@noreply.codeberg.org>
2025-06-24 08:16:51 -04:00
|
|
|
|
2025-11-10 07:35:38 -05:00
|
|
|
if (event.key === 'Escape') {
|
|
|
|
|
// User pressed Escape while having an open dropdown, we'll close it
|
|
|
|
|
dropdown.removeAttribute('open');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Knowing document.activeElement, find the <li> that contains it
|
|
|
|
|
const dropdownItems = dropdown.querySelectorAll<HTMLLIElement>('.content > ul > li');
|
|
|
|
|
let activeLi: HTMLLIElement, activeLiIndex: number;
|
|
|
|
|
for (let i = 0; i < dropdownItems.length; i++) {
|
|
|
|
|
const li = dropdownItems[i] as HTMLLIElement;
|
|
|
|
|
if (!li.contains(document.activeElement)) continue;
|
|
|
|
|
activeLi = li;
|
|
|
|
|
activeLiIndex = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (activeLi === undefined) {
|
|
|
|
|
// The focused element is not a list item or it's contents, but something else in the dropdown
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (event.key === 'ArrowUp') {
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
if (activeLiIndex === 0) {
|
|
|
|
|
// Last child is already selected, but we can navigate back to the opener and close the dropdown
|
|
|
|
|
dropdown.querySelector('summary').focus();
|
|
|
|
|
dropdown.removeAttribute('open');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
dropdownItems[activeLiIndex - 1].querySelector<HTMLElement>(':is(a, button)').focus();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (event.key === 'ArrowDown') {
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
if (activeLiIndex === dropdownItems.length - 1) {
|
|
|
|
|
// First child is already selected
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
dropdownItems[activeLiIndex + 1].querySelector<HTMLElement>(':is(a, button)').focus();
|
|
|
|
|
}
|
feat(ui): redesign user profile actions layout (#7906)
Related: https://codeberg.org/forgejo/forgejo/pulls/3950#issue-785253, https://codeberg.org/forgejo/forgejo/pulls/3950#issuecomment-1998551.
## Links in dropdown
* move _admin only_ User details link here, give it always-visible text
* add new _self only_ Edit profile link here
* move RSS feed link here
* add new Atom feed link here, previously unadvertised
* add new SSH keys link here (`.keys`), previously unadvertised
* add new GPG keys link here (`.gpg`), previously unadvertised
* move Block/Unblock button here
* move Report abuse link here
If primary action is available (Follow/Unfollow), dropdown with more actions goes after it. If not, it is in line with followers, in place where RSS feed button used to be.
## New dropdown
Related: https://codeberg.org/forgejo/design/issues/23, https://codeberg.org/forgejo/forgejo/issues/3853, https://codeberg.org/0ko/forgejo/issues/2.
Implemented a new dropdown: noJS-usable, JS-enhanced for better keyboard navigation and a11y.
Styling is mostly same as the existing ones have, but row density depends on `@media` pointer type.
My choice of CSS properties have been influenced of these:
* https://github.com/picocss/pico/commit/72a3adb16b2f3248b456da823502f166510720a0
* https://github.com/picocss/pico/commit/51dd2293cab8d77cf13fc2c32b6053ffa654bc56
Inspired-by: KiranMantha <kiranv.mantha@gmail.com>
Inspired-by: Lucas Larroche <lucas@larroche.com>
Co-authored-by: Beowulf <beowulf@beocode.eu>
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/7906
Reviewed-by: Otto <otto@codeberg.org>
Reviewed-by: Beowulf <beowulf@beocode.eu>
Co-authored-by: 0ko <0ko@noreply.codeberg.org>
Co-committed-by: 0ko <0ko@noreply.codeberg.org>
2025-06-24 08:16:51 -04:00
|
|
|
});
|
|
|
|
|
}
|