Files
bfa381ef26 feat(site): add keyboard shortcuts to the icons page (#5035)
* feat(docs): add keyboard shortcuts to the icons page

Add the shortcuts suggested in #4916 and list them on the page:

- Ctrl/Cmd + click on an icon copies its name
- Arrow keys move from the search field into the results and between
  the icons
- Ctrl/Cmd + C copies the name of the selected icon
- Ctrl/Cmd + Shift + C copies the SVG of the selected icon

Icons can now be focused with the keyboard, and a keyboard button next to
the sort select opens a dialog with all shortcuts, including the existing
Ctrl/Cmd + K and Shift + click. The dialog also opens with Shift + ?
(except while typing in a field).

Closes #4916

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(docs): add copy toasts, open icons with Enter and a shared Kbd component

- Copying an icon shows a toast (vue-sonner, bottom-center) that says
  whether its name or its SVG was copied
- Enter opens the selected icon's drawer
- The SVG shortcut is now Shift + C, as Ctrl/Cmd + Shift + C opens the
  browser's inspect tool
- Kbd component shared by the search inputs and the shortcuts dialog

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Adjust keyboard shortcuts

* Revert customizer change

* Adjust kbd style

* Fix toaster styling

* Fix types

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Eric <eric.fennis@gmail.com>
2026-11-10 08:29:51 +01:00

716 lines
16 KiB
CSS

:root {
--vp-c-brand: #f56565;
--vp-c-brand-light: #f67373;
--vp-c-brand-lighter: #f89191;
--vp-c-brand-dark: #dc5a5a;
--vp-c-brand-darker: #c45050;
--vp-c-brand-1: #f67373;
--vp-c-brand-2: #ff7070;
--vp-c-brand-3: #f56565;
--vp-c-brand-4: #dc5a5a;
--vp-c-brand-5: #c45050;
--vp-c-bg-alt-up: #fff;
--vp-c-bg-alt-down: #fff;
--vp-code-editor-plain: #24292e;
--vp-code-editor-comment: #6a737d;
--vp-code-editor-keyword: #d73a49;
--vp-code-editor-tag: #22863a;
--vp-code-editor-punctuation: #24292e;
--vp-code-editor-definition: #6f42c1;
--vp-code-editor-property: #005cc5;
--vp-code-editor-static: #f78c6c;
--vp-code-editor-string: #032f62;
--vp-c-text-4: rgba(60, 60, 67, 0.32);
--vp-home-hero-name-color: var(--vp-c-text);
--vp-a11y-danger: var(--vp-c-danger-3);
--vp-a11y-success: var(--vp-c-success-3);
--vp-a11y-warning: #da9200;
--vp-sidebar-input: var(--vp-c-gray-3);
}
.dark {
--vp-c-bg-alt-up: #1b1b1d;
--vp-c-bg-alt-down: #0f0f10;
--vp-code-editor-plain: #e1e4e8;
--vp-code-editor-comment: #6a737d;
--vp-code-editor-keyword: #f97583;
--vp-code-editor-tag: #85e89d;
--vp-code-editor-punctuation: #9ecbff;
--vp-code-editor-definition: #b392f0;
--vp-code-editor-property: #79b8ff;
--vp-code-editor-static: #f78c6c;
--vp-code-editor-string: #9ecbff;
--vp-c-text-1: #dfdfd6;
--vp-c-text-4: rgba(235, 235, 245, 0.16);
--vp-a11y-danger: var(--vp-c-danger-2);
--vp-a11y-success: var(--vp-c-success-2);
--vp-a11y-warning: var(--vp-c-warning-2);
--vp-sidebar-input: var(--vp-c-bg-soft);
}
@view-transition {
navigation: auto;
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0s !important;
transition-delay: 0s !important;
scroll-behavior: auto !important;
}
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
animation: none !important;
}
}
/* ::view-transition-old(icons-search-box),
::view-transition-new(icons-search-box) {
animation: .3s transition 0s ease;
} */
html {
scrollbar-gutter: stable;
}
/* Page scrollbar in the site's colours: a slim rounded thumb on the page background */
html::-webkit-scrollbar {
width: 12px;
height: 12px;
}
html::-webkit-scrollbar-track,
html::-webkit-scrollbar-corner {
background-color: var(--vp-c-bg);
}
html::-webkit-scrollbar-thumb {
background-color: var(--vp-c-text-3);
background-clip: padding-box;
border: 3px solid transparent;
border-radius: 12px;
}
html::-webkit-scrollbar-thumb:hover {
background-color: var(--vp-c-text-2);
}
html::-webkit-scrollbar-thumb:active {
background-color: var(--vp-c-brand-1);
}
/* Browsers without the scrollbar pseudo-elements, such as Firefox */
@supports not selector(::-webkit-scrollbar) {
html {
scrollbar-width: thin;
scrollbar-color: var(--vp-c-text-3) var(--vp-c-bg);
}
}
.VPHome {
overflow-x: hidden;
}
.VPNavBarTitle .logo {
height: 36px;
width: 36px;
}
.VPNavBarTitle .title {
font-size: 21px;
}
.VPHomeHero > .container {
gap: 24px;
}
.VPHomeHero .image-container {
transform: none;
width: 100%;
}
.VPHomeHero .name::first-line {
color: var(--vp-c-brand);
}
.VPHomeHero .container .image {
margin: 0;
order: 2;
/* margin-top: 32px; */
}
.VPHomeHero .container .image-container {
height: auto;
justify-content: flex-end;
}
.VPFeature {
border: 1px solid var(--vp-c-divider) !important;
}
.VPFeature .icon {
background-color: var(--vp-c-bg);
}
.vp-doc[class*=' _icons_'] > div {
max-width: 100%;
}
.VPDoc:has(.vp-doc[class*=' _icons_']) > .container > .content {
padding-right: 0;
padding-left: 0;
}
.overview-container.icon-drawer-open {
padding-bottom: 288px;
}
.VPHomeHero .container {
flex-direction: column-reverse;
}
.content-body .search {
display: none;
}
@media (min-width: 960px) {
.VPHomeHero .container .image {
order: 1;
margin-bottom: auto;
margin-top: 0;
position: relative;
}
.VPHomeHero .container .main {
width: 50%;
}
.VPHomeHero .container .image {
width: 50%;
}
.VPHomeHero .container .image-container {
display: block;
}
.VPHomeHero .container {
flex-direction: row;
}
.VPDoc:has(.vp-doc[class*=' _icons_']) {
padding: 32px 32px 0;
}
}
.VPNavBarHamburger .container > span {
border-radius: 2px;
}
/* Nav bar links: on hover an underline draws in from the side the mouse enters and leaves
towards the side it exits (see utils/underlineDirection.ts). Without that script it
draws in from the left and leaves to the right. It stays under the link of the current page. */
.VPNav .VPNavBarMenuLink,
.VPNav .VPNavBarMenuGroup .button {
position: relative;
transition: opacity 0.25s;
}
.VPNav .VPNavBarMenuLink::before,
.VPNav .VPNavBarMenuGroup .button::before {
content: '';
position: absolute;
right: 12px;
bottom: 16px;
left: 12px;
height: 2px;
border-radius: 2px;
background-color: var(--vp-c-brand-1);
transform: scaleX(0);
transform-origin: var(--underline-origin, right);
transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1);
}
.VPNav .VPNavBarMenuLink:hover::before,
.VPNav .VPNavBarMenuLink:focus-visible::before,
.VPNav .VPNavBarMenuLink.active::before,
.VPNav .VPNavBarMenuGroup:hover .button::before,
.VPNav .VPNavBarMenuGroup .button[aria-expanded='true']::before,
.VPNav .VPNavBarMenuGroup.active .button::before {
transform: scaleX(1);
transform-origin: var(--underline-origin, left);
}
/* On hover the link text dims, like the dropdown buttons do; the current page keeps its brand colour */
.VPNav .VPNavBarMenuLink:not(.active):hover {
color: var(--vp-c-text-1);
opacity: 0.8;
}
/* The chevron turns up while the dropdown is open, and the menu slides down into place.
VitePress draws the down chevron as a right chevron turned by 90deg. */
.VPNav .VPNavBarMenuGroup .text-icon {
transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1);
}
.VPNav .VPNavBarMenuGroup:hover .text-icon,
.VPNav .VPNavBarMenuGroup .button[aria-expanded='true'] .text-icon {
transform: rotate(-90deg);
}
.VPNav .VPNavBarMenuGroup .button[aria-expanded='false'] + .menu {
transform: translateY(-8px);
}
.VPNav .VPNavBarMenuGroup:hover .button + .menu,
.VPNav .VPNavBarMenuGroup .button[aria-expanded='true'] + .menu {
transform: translateY(0);
}
/* Appearance switch: the thumb sits 2px inside the track and slides over with a small bounce,
while the sun and the moon turn and grow as they swap places */
.VPNav .VPSwitchAppearance .check {
top: 2px;
left: 2px;
width: 16px;
height: 16px;
transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
html.dark .VPNav .VPSwitchAppearance .check {
transform: translateX(18px);
}
.VPNav .VPSwitchAppearance:hover .check,
.VPNav .VPSwitchAppearance:focus-visible .check {
box-shadow:
var(--vp-shadow-1),
0 0 0 3px color-mix(in srgb, var(--vp-c-brand) 25%, transparent);
}
.VPNav .VPSwitchAppearance .icon {
width: 16px;
height: 16px;
}
.VPNav .VPSwitchAppearance .icon .sun,
.VPNav .VPSwitchAppearance .icon .moon {
top: 2px;
left: 2px;
transition:
opacity 0.3s ease,
transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.VPNav .VPSwitchAppearance .icon .moon,
html.dark .VPNav .VPSwitchAppearance .icon .sun {
opacity: 0;
transform: rotate(-90deg) scale(0.4);
}
.VPNav .VPSwitchAppearance .icon .sun,
html.dark .VPNav .VPSwitchAppearance .icon .moon {
opacity: 1;
transform: rotate(0) scale(1);
}
/* Nav bar social icons get a soft rounded background and lift a little on hover */
.VPNav .VPSocialLinks .VPSocialLink {
border-radius: 8px;
transition:
color 0.25s,
background-color 0.25s,
transform 0.25s;
}
.VPNav .VPSocialLinks .VPSocialLink:hover,
.VPNav .VPSocialLinks .VPSocialLink:focus-visible {
outline: none;
color: var(--vp-c-text-1);
background-color: var(--vp-c-default-soft);
transform: translateY(-2px);
}
.package-lucide-logo {
margin: 0 auto 48px;
max-width: 480px;
}
/* Sidebar links: a soft pill on hover with the text sliding in a little, a light brand pill
for the current page, and a smooth turn of the section chevrons */
.VPSidebar .VPSidebarItem.is-link > .item > .link {
margin: 1px -8px;
padding: 0 8px;
border-radius: 6px;
transition: background-color 0.25s;
}
.VPSidebar .VPSidebarItem.is-link > .item > .link > .text {
transition:
color 0.25s,
transform 0.25s ease;
}
.VPSidebar .VPSidebarItem.is-link > .item > .link:hover,
.VPSidebar .VPSidebarItem.is-link > .item > .link:focus-visible {
outline: none;
background-color: var(--vp-c-default-soft);
}
.VPSidebar .VPSidebarItem.is-link > .item > .link:hover > .text,
.VPSidebar .VPSidebarItem.is-link > .item > .link:focus-visible > .text {
transform: translateX(3px);
}
.VPSidebar .VPSidebarItem.is-active > .item > .link {
background-color: color-mix(in srgb, var(--vp-c-brand) 10%, transparent);
}
.VPSidebar .VPSidebarItem .caret-icon {
transition: transform 0.3s cubic-bezier(0.34, 1.4, 0.64, 1);
}
@media (min-width: 960px) {
.VPSidebar {
padding-right: 24px !important;
}
}
/* Links in the page text: a faint underline shows they are links, and on hover a solid
underline draws in from the left. Drawn with backgrounds so it also follows links that
wrap onto a second line. */
.vp-doc a:not([class]) {
text-decoration: none;
padding-bottom: 1px;
background-image:
linear-gradient(currentColor, currentColor),
linear-gradient(
color-mix(in srgb, var(--vp-c-brand) 35%, transparent),
color-mix(in srgb, var(--vp-c-brand) 35%, transparent)
);
background-position:
0 100%,
0 100%;
background-repeat: no-repeat;
background-size:
0% 2px,
100% 1px;
transition:
color 0.25s,
background-size 0.35s cubic-bezier(0.4, 0, 0.2, 1);
}
.vp-doc a:not([class]):hover,
.vp-doc a:not([class]):focus-visible {
background-size:
100% 2px,
100% 1px;
}
.vp-doc a:not([class]):has(img) {
background-image: none;
}
/* "Edit this page": a soft brand pill on hover, with the pen tilting as if it starts writing */
.VPDocFooter .edit-link-button {
margin-left: -10px;
padding: 0 12px 0 10px;
border-radius: 8px;
transition:
color 0.25s,
background-color 0.25s;
}
.VPDocFooter .edit-link-button:hover,
.VPDocFooter .edit-link-button:focus-visible {
outline: none;
background-color: color-mix(in srgb, var(--vp-c-brand) 10%, transparent);
}
.VPDocFooter .edit-link-icon {
transform-origin: 30% 70%;
transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.VPDocFooter .edit-link-button:hover .edit-link-icon,
.VPDocFooter .edit-link-button:focus-visible .edit-link-icon {
transform: rotate(-14deg) scale(1.1);
}
/* Previous / next page links: Lucide's arrow-left and arrow-right icons point the way, and
on hover the card lifts with a light brand tint while its arrow moves on */
.VPDocFooter .pager-link {
transition:
border-color 0.25s,
background-color 0.25s,
transform 0.25s ease,
box-shadow 0.25s;
}
.VPDocFooter .pager-link:hover,
.VPDocFooter .pager-link:focus-visible {
outline: none;
transform: translateY(-2px);
background-color: color-mix(in srgb, var(--vp-c-brand) 6%, transparent);
box-shadow: var(--vp-shadow-2);
}
.VPDocFooter .pager-link .title {
display: flex;
align-items: center;
gap: 6px;
font-size: 15px;
font-weight: 600;
}
.VPDocFooter .pager-link.next .title {
justify-content: flex-end;
}
.VPDocFooter .pager-link.prev .title::before,
.VPDocFooter .pager-link.next .title::after {
content: '';
flex-shrink: 0;
width: 16px;
height: 16px;
background-color: currentColor;
transition: transform 0.25s ease;
}
.VPDocFooter .pager-link.prev .title::before {
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m12 19-7-7 7-7'/%3E%3Cpath d='M19 12H5'/%3E%3C/svg%3E")
center / contain no-repeat;
}
.VPDocFooter .pager-link.next .title::after {
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3Cpath d='m12 5 7 7-7 7'/%3E%3C/svg%3E")
center / contain no-repeat;
}
.VPDocFooter .pager-link.prev:hover .title::before {
transform: translateX(-4px);
}
.VPDocFooter .pager-link.next:hover .title::after {
transform: translateX(4px);
}
/* "On this page" outline: each heading is a soft pill on hover and slides in a little,
the current heading takes the brand colour and the marker glides to it */
.VPDoc .VPDocAsideOutline .outline-link {
margin: 0 -8px;
padding: 0 8px;
border-radius: 6px;
transition:
color 0.25s,
background-color 0.25s,
padding-left 0.25s ease;
}
.VPDoc .VPDocAsideOutline .outline-link:hover,
.VPDoc .VPDocAsideOutline .outline-link:focus-visible {
outline: none;
padding-left: 12px;
color: var(--vp-c-text-1);
background-color: var(--vp-c-default-soft);
}
.VPDoc .VPDocAsideOutline .outline-link.active {
color: var(--vp-c-brand-1);
}
.VPDoc .VPDocAsideOutline .outline-marker {
transition:
top 0.35s cubic-bezier(0.34, 1.3, 0.64, 1),
opacity 0.25s;
}
/* Sidebar scrollbar: a slim rounded thumb that stays quiet until the sidebar is hovered */
.VPSidebar::-webkit-scrollbar {
width: 8px;
}
.VPSidebar::-webkit-scrollbar-track {
background: transparent;
}
.VPSidebar::-webkit-scrollbar-thumb {
background-color: var(--vp-c-divider);
background-clip: padding-box;
border: 2px solid transparent;
border-radius: 8px;
}
.VPSidebar:hover::-webkit-scrollbar-thumb {
background-color: var(--vp-c-text-3);
}
.VPSidebar::-webkit-scrollbar-thumb:hover,
.VPSidebar::-webkit-scrollbar-thumb:active {
background-color: var(--vp-c-brand-1);
}
/* Browsers without the scrollbar pseudo-elements, such as Firefox */
@supports not selector(::-webkit-scrollbar) {
.VPSidebar {
scrollbar-width: thin;
scrollbar-color: var(--vp-c-text-3) transparent;
}
}
.custom-block.success {
border-color: transparent;
color: var(--vp-c-text-1);
background-color: var(--vp-c-success-soft);
}
/* Example guidance blocks */
.example-block {
margin: 32px 0;
}
.example-block__title {
margin: 0 0 12px;
font-size: 20px;
line-height: 1.4;
}
.example-block > :first-child {
margin-top: 0;
}
.example-block > :last-child {
margin-bottom: 0;
}
.example-block__content > :first-child {
margin-top: 0;
}
.example-block__content > :last-child {
margin-bottom: 0;
}
.example-guidance__image {
display: block;
width: 100%;
height: auto;
background-color: var(--vp-c-bg-soft);
border-bottom: 4px solid var(--vp-c-divider);
border-top-left-radius: 16px;
border-top-right-radius: 16px;
overflow: hidden;
}
.example-guidance__image--raw svg {
display: block;
width: 100%;
height: auto;
}
.example-guidance__text {
display: flex;
flex-direction: column;
gap: 8px;
align-items: center;
justify-content: center;
min-height: 160px;
padding: 24px;
background-color: var(--vp-c-bg-alt);
border-bottom: 1px solid var(--vp-c-divider);
border-top-left-radius: 16px;
border-top-right-radius: 16px;
color: var(--vp-c-text-1);
font-size: 20px;
line-height: 1.4;
text-align: center;
text-wrap: balance;
}
.example-guidance__text svg.lucide {
flex-shrink: 0;
display: inline-block;
vertical-align: -6px;
}
.example-guidance__caption {
color: var(--vp-c-text-1);
}
.example-guidance__caption > p {
margin: 0;
padding: 0 16px 16px;
}
.example-guidance__label {
display: flex;
gap: 8px;
padding: 12px;
margin: 0 0 16px;
background-color: var(--example-guidance-label-bg);
color: var(--vp-c-neutral-inverse);
border-bottom-left-radius: 16px;
border-bottom-right-radius: 16px;
}
.example-guidance--do {
--example-guidance-label-bg: var(--vp-c-success-1);
}
.example-guidance--dont {
--example-guidance-label-bg: var(--vp-c-danger-1);
}
.example-guidance--caution {
--example-guidance-label-bg: var(--vp-c-warning-1);
}
@media (min-width: 640px) {
.example-block {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 24px;
}
.example-block__content {
grid-column: 1 / -1;
}
.example-guidance {
margin: 0;
}
}
@media (min-width: 960px) {
.example-block {
grid-template-columns: minmax(0, 0.9fr) repeat(2, minmax(0, 1fr));
}
.example-block--guidance-only {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.example-block__content {
grid-column: 1;
}
.example-guidance {
grid-column: auto;
grid-row: auto;
}
}