mirror of
https://github.com/docmost/docmost.git
synced 2026-05-07 06:23:06 +08:00
accessibility
This commit is contained in:
@@ -899,5 +899,11 @@
|
|||||||
"Link suggestions": "Link suggestions",
|
"Link suggestions": "Link suggestions",
|
||||||
"Diagram editor": "Diagram editor",
|
"Diagram editor": "Diagram editor",
|
||||||
"Add comment": "Add comment",
|
"Add comment": "Add comment",
|
||||||
"Find and replace": "Find and replace"
|
"Find and replace": "Find and replace",
|
||||||
|
"Main navigation": "Main navigation",
|
||||||
|
"Space navigation": "Space navigation",
|
||||||
|
"Settings navigation": "Settings navigation",
|
||||||
|
"AI navigation": "AI navigation",
|
||||||
|
"Breadcrumb": "Breadcrumb",
|
||||||
|
"Skip to main content": "Skip to main content"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,4 +28,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.skipLink {
|
||||||
|
position: fixed;
|
||||||
|
left: 8px;
|
||||||
|
top: 8px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
background: var(--mantine-color-blue-6);
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
text-decoration: none;
|
||||||
|
z-index: 1000;
|
||||||
|
transform: translateY(-150%);
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
transform: translateY(0);
|
||||||
|
outline: 2px solid var(--mantine-color-blue-3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { AppShell, Container } from "@mantine/core";
|
import { AppShell, Container } from "@mantine/core";
|
||||||
import React, { useEffect, useRef, useState } from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import { useLocation } from "react-router-dom";
|
import { useLocation } from "react-router-dom";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import SettingsSidebar from "@/components/settings/settings-sidebar.tsx";
|
import SettingsSidebar from "@/components/settings/settings-sidebar.tsx";
|
||||||
import { useAtom } from "jotai";
|
import { useAtom } from "jotai";
|
||||||
import {
|
import {
|
||||||
@@ -23,11 +24,12 @@ export default function GlobalAppShell({
|
|||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
|
const { t } = useTranslation();
|
||||||
useTrialEndAction();
|
useTrialEndAction();
|
||||||
const [mobileOpened] = useAtom(mobileSidebarAtom);
|
const [mobileOpened] = useAtom(mobileSidebarAtom);
|
||||||
const toggleMobile = useToggleSidebar(mobileSidebarAtom);
|
const toggleMobile = useToggleSidebar(mobileSidebarAtom);
|
||||||
const [desktopOpened] = useAtom(desktopSidebarAtom);
|
const [desktopOpened] = useAtom(desktopSidebarAtom);
|
||||||
const [{ isAsideOpen }] = useAtom(asideStateAtom);
|
const [{ isAsideOpen, tab: asideTab }] = useAtom(asideStateAtom);
|
||||||
const [sidebarWidth, setSidebarWidth] = useAtom(sidebarWidthAtom);
|
const [sidebarWidth, setSidebarWidth] = useAtom(sidebarWidthAtom);
|
||||||
const [isResizing, setIsResizing] = useState(false);
|
const [isResizing, setIsResizing] = useState(false);
|
||||||
const sidebarRef = useRef(null);
|
const sidebarRef = useRef(null);
|
||||||
@@ -79,7 +81,11 @@ export default function GlobalAppShell({
|
|||||||
const showGlobalSidebar = !isSpaceRoute && !isSettingsRoute && !isAiRoute;
|
const showGlobalSidebar = !isSpaceRoute && !isSettingsRoute && !isAiRoute;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppShell
|
<>
|
||||||
|
<a href="#main-content" className={classes.skipLink}>
|
||||||
|
{t("Skip to main content")}
|
||||||
|
</a>
|
||||||
|
<AppShell
|
||||||
header={{ height: 45 }}
|
header={{ height: 45 }}
|
||||||
navbar={{
|
navbar={{
|
||||||
width: isSpaceRoute ? sidebarWidth : 300,
|
width: isSpaceRoute ? sidebarWidth : 300,
|
||||||
@@ -105,6 +111,15 @@ export default function GlobalAppShell({
|
|||||||
className={classes.navbar}
|
className={classes.navbar}
|
||||||
withBorder={false}
|
withBorder={false}
|
||||||
ref={sidebarRef}
|
ref={sidebarRef}
|
||||||
|
aria-label={
|
||||||
|
isSpaceRoute
|
||||||
|
? t("Space navigation")
|
||||||
|
: isSettingsRoute
|
||||||
|
? t("Settings navigation")
|
||||||
|
: isAiRoute
|
||||||
|
? t("AI navigation")
|
||||||
|
: t("Main navigation")
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{isSpaceRoute && (
|
{isSpaceRoute && (
|
||||||
<div className={classes.resizeHandle} onMouseDown={startResizing} />
|
<div className={classes.resizeHandle} onMouseDown={startResizing} />
|
||||||
@@ -114,7 +129,7 @@ export default function GlobalAppShell({
|
|||||||
{isAiRoute && <AiChatSidebar />}
|
{isAiRoute && <AiChatSidebar />}
|
||||||
{showGlobalSidebar && <GlobalSidebar />}
|
{showGlobalSidebar && <GlobalSidebar />}
|
||||||
</AppShell.Navbar>
|
</AppShell.Navbar>
|
||||||
<AppShell.Main>
|
<AppShell.Main id="main-content">
|
||||||
{isSettingsRoute ? (
|
{isSettingsRoute ? (
|
||||||
<Container size={900}>{children}</Container>
|
<Container size={900}>{children}</Container>
|
||||||
) : (
|
) : (
|
||||||
@@ -123,10 +138,24 @@ export default function GlobalAppShell({
|
|||||||
</AppShell.Main>
|
</AppShell.Main>
|
||||||
|
|
||||||
{isPageRoute && (
|
{isPageRoute && (
|
||||||
<AppShell.Aside className={classes.aside} p="md" withBorder={false}>
|
<AppShell.Aside
|
||||||
|
className={classes.aside}
|
||||||
|
p="md"
|
||||||
|
withBorder={false}
|
||||||
|
aria-label={
|
||||||
|
asideTab === "comments"
|
||||||
|
? t("Comments")
|
||||||
|
: asideTab === "toc"
|
||||||
|
? t("Table of contents")
|
||||||
|
: asideTab === "chat"
|
||||||
|
? t("AI Chat")
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
>
|
||||||
<Aside />
|
<Aside />
|
||||||
</AppShell.Aside>
|
</AppShell.Aside>
|
||||||
)}
|
)}
|
||||||
</AppShell>
|
</AppShell>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { ScrollArea, Text, Divider, Modal } from "@mantine/core";
|
import { ScrollArea, Text, Divider, Modal, UnstyledButton } from "@mantine/core";
|
||||||
import {
|
import {
|
||||||
IconHome,
|
IconHome,
|
||||||
IconClock,
|
IconClock,
|
||||||
@@ -119,17 +119,13 @@ export default function GlobalSidebar() {
|
|||||||
</ScrollArea>
|
</ScrollArea>
|
||||||
|
|
||||||
<div className={classes.bottomSection}>
|
<div className={classes.bottomSection}>
|
||||||
<a
|
<UnstyledButton
|
||||||
className={classes.link}
|
className={classes.link}
|
||||||
onClick={(e) => {
|
onClick={openInvite}
|
||||||
e.preventDefault();
|
|
||||||
openInvite();
|
|
||||||
}}
|
|
||||||
href="#"
|
|
||||||
>
|
>
|
||||||
<IconUserPlus className={classes.linkIcon} stroke={2} />
|
<IconUserPlus className={classes.linkIcon} stroke={2} />
|
||||||
<span>{t("Invite People")}</span>
|
<span>{t("Invite People")}</span>
|
||||||
</a>
|
</UnstyledButton>
|
||||||
<Link
|
<Link
|
||||||
className={classes.link}
|
className={classes.link}
|
||||||
data-active={active.startsWith("/settings") || undefined}
|
data-active={active.startsWith("/settings") || undefined}
|
||||||
|
|||||||
@@ -226,32 +226,6 @@ export default function SettingsSidebar() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const isDisabled = isItemDisabled(item);
|
const isDisabled = isItemDisabled(item);
|
||||||
const linkElement = (
|
|
||||||
<Link
|
|
||||||
onMouseEnter={!isDisabled ? prefetchHandler : undefined}
|
|
||||||
className={classes.link}
|
|
||||||
data-active={active.startsWith(item.path) || undefined}
|
|
||||||
data-disabled={isDisabled || undefined}
|
|
||||||
key={item.label}
|
|
||||||
to={isDisabled ? "#" : item.path}
|
|
||||||
onClick={(e) => {
|
|
||||||
if (isDisabled) {
|
|
||||||
e.preventDefault();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mobileSidebarOpened) {
|
|
||||||
toggleMobileSidebar();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
opacity: isDisabled ? 0.5 : 1,
|
|
||||||
cursor: isDisabled ? "not-allowed" : "pointer",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<item.icon className={classes.linkIcon} stroke={2} />
|
|
||||||
<span>{t(item.label)}</span>
|
|
||||||
</Link>
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isDisabled) {
|
if (isDisabled) {
|
||||||
return (
|
return (
|
||||||
@@ -261,12 +235,41 @@ export default function SettingsSidebar() {
|
|||||||
position="right"
|
position="right"
|
||||||
withArrow
|
withArrow
|
||||||
>
|
>
|
||||||
{linkElement}
|
<span
|
||||||
|
className={classes.link}
|
||||||
|
data-disabled
|
||||||
|
role="link"
|
||||||
|
aria-disabled="true"
|
||||||
|
tabIndex={0}
|
||||||
|
style={{
|
||||||
|
opacity: 0.5,
|
||||||
|
cursor: "not-allowed",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<item.icon className={classes.linkIcon} stroke={2} />
|
||||||
|
<span>{t(item.label)}</span>
|
||||||
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return linkElement;
|
return (
|
||||||
|
<Link
|
||||||
|
onMouseEnter={prefetchHandler}
|
||||||
|
className={classes.link}
|
||||||
|
data-active={active.startsWith(item.path) || undefined}
|
||||||
|
key={item.label}
|
||||||
|
to={item.path}
|
||||||
|
onClick={() => {
|
||||||
|
if (mobileSidebarOpened) {
|
||||||
|
toggleMobileSidebar();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<item.icon className={classes.linkIcon} stroke={2} />
|
||||||
|
<span>{t(item.label)}</span>
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -284,7 +287,7 @@ export default function SettingsSidebar() {
|
|||||||
}}
|
}}
|
||||||
variant="transparent"
|
variant="transparent"
|
||||||
c="gray"
|
c="gray"
|
||||||
aria-label="Back"
|
aria-label={t("Back")}
|
||||||
>
|
>
|
||||||
<IconArrowLeft stroke={2} />
|
<IconArrowLeft stroke={2} />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ export default function AudioView(props: NodeViewProps) {
|
|||||||
preload="metadata"
|
preload="metadata"
|
||||||
controls
|
controls
|
||||||
src={safeSrc}
|
src={safeSrc}
|
||||||
|
aria-label={placeholder?.name || t("Audio")}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{!safeSrc && previewSrc && (
|
{!safeSrc && previewSrc && (
|
||||||
@@ -45,6 +46,7 @@ export default function AudioView(props: NodeViewProps) {
|
|||||||
preload="metadata"
|
preload="metadata"
|
||||||
controls
|
controls
|
||||||
src={previewSrc}
|
src={previewSrc}
|
||||||
|
aria-label={placeholder?.name || t("Audio")}
|
||||||
/>
|
/>
|
||||||
<Loader size={20} pos="absolute" top={6} right={6} />
|
<Loader size={20} pos="absolute" top={6} right={6} />
|
||||||
</Group>
|
</Group>
|
||||||
@@ -60,7 +62,7 @@ export default function AudioView(props: NodeViewProps) {
|
|||||||
</Group>
|
</Group>
|
||||||
)}
|
)}
|
||||||
{!safeSrc && !previewSrc && !placeholder && (
|
{!safeSrc && !previewSrc && !placeholder && (
|
||||||
<audio className={classes.audio} controls />
|
<audio className={classes.audio} controls aria-label={t("Audio")} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</NodeViewWrapper>
|
</NodeViewWrapper>
|
||||||
|
|||||||
+24
-3
@@ -194,6 +194,7 @@ function SearchAndReplaceDialog({ editor, editable = true }: PageFindDialogDialo
|
|||||||
<Input
|
<Input
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
placeholder={t("Find")}
|
placeholder={t("Find")}
|
||||||
|
aria-label={t("Find")}
|
||||||
leftSection={<IconSearch size={16} />}
|
leftSection={<IconSearch size={16} />}
|
||||||
rightSection={
|
rightSection={
|
||||||
<Text size="xs" ta="right">
|
<Text size="xs" ta="right">
|
||||||
@@ -218,7 +219,12 @@ function SearchAndReplaceDialog({ editor, editable = true }: PageFindDialogDialo
|
|||||||
|
|
||||||
<ActionIcon.Group>
|
<ActionIcon.Group>
|
||||||
<Tooltip label={t("Previous match (Shift+Enter)")}>
|
<Tooltip label={t("Previous match (Shift+Enter)")}>
|
||||||
<ActionIcon variant="subtle" color="gray" onClick={previous}>
|
<ActionIcon
|
||||||
|
variant="subtle"
|
||||||
|
color="gray"
|
||||||
|
onClick={previous}
|
||||||
|
aria-label={t("Previous match (Shift+Enter)")}
|
||||||
|
>
|
||||||
<IconArrowNarrowUp
|
<IconArrowNarrowUp
|
||||||
style={{ width: "70%", height: "70%" }}
|
style={{ width: "70%", height: "70%" }}
|
||||||
stroke={1.5}
|
stroke={1.5}
|
||||||
@@ -226,7 +232,12 @@ function SearchAndReplaceDialog({ editor, editable = true }: PageFindDialogDialo
|
|||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip label={t("Next match (Enter)")}>
|
<Tooltip label={t("Next match (Enter)")}>
|
||||||
<ActionIcon variant="subtle" color="gray" onClick={next}>
|
<ActionIcon
|
||||||
|
variant="subtle"
|
||||||
|
color="gray"
|
||||||
|
onClick={next}
|
||||||
|
aria-label={t("Next match (Enter)")}
|
||||||
|
>
|
||||||
<IconArrowNarrowDown
|
<IconArrowNarrowDown
|
||||||
style={{ width: "70%", height: "70%" }}
|
style={{ width: "70%", height: "70%" }}
|
||||||
stroke={1.5}
|
stroke={1.5}
|
||||||
@@ -238,6 +249,8 @@ function SearchAndReplaceDialog({ editor, editable = true }: PageFindDialogDialo
|
|||||||
variant="subtle"
|
variant="subtle"
|
||||||
color={caseSensitive.color}
|
color={caseSensitive.color}
|
||||||
onClick={() => caseSensitiveToggle()}
|
onClick={() => caseSensitiveToggle()}
|
||||||
|
aria-label={t("Match case (Alt+C)")}
|
||||||
|
aria-pressed={caseSensitive.isCaseSensitive}
|
||||||
>
|
>
|
||||||
<IconLetterCase
|
<IconLetterCase
|
||||||
style={{ width: "70%", height: "70%" }}
|
style={{ width: "70%", height: "70%" }}
|
||||||
@@ -251,6 +264,8 @@ function SearchAndReplaceDialog({ editor, editable = true }: PageFindDialogDialo
|
|||||||
variant="subtle"
|
variant="subtle"
|
||||||
color={replaceButton.color}
|
color={replaceButton.color}
|
||||||
onClick={() => replaceButtonToggle()}
|
onClick={() => replaceButtonToggle()}
|
||||||
|
aria-label={t("Replace")}
|
||||||
|
aria-pressed={replaceButton.isReplaceShow}
|
||||||
>
|
>
|
||||||
<IconReplace
|
<IconReplace
|
||||||
style={{ width: "70%", height: "70%" }}
|
style={{ width: "70%", height: "70%" }}
|
||||||
@@ -260,7 +275,12 @@ function SearchAndReplaceDialog({ editor, editable = true }: PageFindDialogDialo
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
<Tooltip label={t("Close (Escape)")}>
|
<Tooltip label={t("Close (Escape)")}>
|
||||||
<ActionIcon variant="subtle" color="gray" onClick={closeDialog}>
|
<ActionIcon
|
||||||
|
variant="subtle"
|
||||||
|
color="gray"
|
||||||
|
onClick={closeDialog}
|
||||||
|
aria-label={t("Close (Escape)")}
|
||||||
|
>
|
||||||
<IconX style={{ width: "70%", height: "70%" }} stroke={1.5} />
|
<IconX style={{ width: "70%", height: "70%" }} stroke={1.5} />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -270,6 +290,7 @@ function SearchAndReplaceDialog({ editor, editable = true }: PageFindDialogDialo
|
|||||||
<Flex align="center" gap="xs">
|
<Flex align="center" gap="xs">
|
||||||
<Input
|
<Input
|
||||||
placeholder={t("Replace")}
|
placeholder={t("Replace")}
|
||||||
|
aria-label={t("Replace")}
|
||||||
leftSection={<IconReplace size={16} />}
|
leftSection={<IconReplace size={16} />}
|
||||||
rightSection={<div></div>}
|
rightSection={<div></div>}
|
||||||
rightSectionPointerEvents="all"
|
rightSectionPointerEvents="all"
|
||||||
|
|||||||
@@ -102,21 +102,26 @@ const CommandList = ({
|
|||||||
scrollbarSize={8}
|
scrollbarSize={8}
|
||||||
overscrollBehavior="contain"
|
overscrollBehavior="contain"
|
||||||
>
|
>
|
||||||
{Object.entries(items).map(([category, categoryItems]) => (
|
{(() => {
|
||||||
|
let flatIndex = -1;
|
||||||
|
return Object.entries(items).map(([category, categoryItems]) => (
|
||||||
<div key={category} role="group" aria-label={category}>
|
<div key={category} role="group" aria-label={category}>
|
||||||
<Text c="dimmed" mb={4} fw={500} tt="capitalize">
|
<Text c="dimmed" mb={4} fw={500} tt="capitalize">
|
||||||
{category}
|
{category}
|
||||||
</Text>
|
</Text>
|
||||||
{categoryItems.map((item: SlashMenuItemType, index: number) => (
|
{categoryItems.map((item: SlashMenuItemType) => {
|
||||||
|
flatIndex += 1;
|
||||||
|
const itemIndex = flatIndex;
|
||||||
|
return (
|
||||||
<UnstyledButton
|
<UnstyledButton
|
||||||
data-item-index={index}
|
data-item-index={itemIndex}
|
||||||
key={index}
|
key={itemIndex}
|
||||||
id={`slash-command-option-${index}`}
|
id={`slash-command-option-${itemIndex}`}
|
||||||
role="option"
|
role="option"
|
||||||
aria-selected={index === selectedIndex}
|
aria-selected={itemIndex === selectedIndex}
|
||||||
onClick={() => selectItem(index)}
|
onClick={() => selectItem(itemIndex)}
|
||||||
className={clsx(classes.menuBtn, {
|
className={clsx(classes.menuBtn, {
|
||||||
[classes.selectedItem]: index === selectedIndex,
|
[classes.selectedItem]: itemIndex === selectedIndex,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Group>
|
<Group>
|
||||||
@@ -135,9 +140,11 @@ const CommandList = ({
|
|||||||
</div>
|
</div>
|
||||||
</Group>
|
</Group>
|
||||||
</UnstyledButton>
|
</UnstyledButton>
|
||||||
))}
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
))}
|
));
|
||||||
|
})()}
|
||||||
</ScrollArea>
|
</ScrollArea>
|
||||||
</Paper>
|
</Paper>
|
||||||
) : null;
|
) : null;
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ export default function VideoView(props: NodeViewProps) {
|
|||||||
preload="metadata"
|
preload="metadata"
|
||||||
controls
|
controls
|
||||||
src={getFileUrl(src)}
|
src={getFileUrl(src)}
|
||||||
|
aria-label={placeholder?.name || t("Video")}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{!src && previewSrc && (
|
{!src && previewSrc && (
|
||||||
@@ -56,6 +57,7 @@ export default function VideoView(props: NodeViewProps) {
|
|||||||
preload="metadata"
|
preload="metadata"
|
||||||
controls
|
controls
|
||||||
src={previewSrc}
|
src={previewSrc}
|
||||||
|
aria-label={placeholder?.name || t("Video")}
|
||||||
/>
|
/>
|
||||||
<Loader size={20} pos="absolute" top={6} right={6} />
|
<Loader size={20} pos="absolute" top={6} right={6} />
|
||||||
</Group>
|
</Group>
|
||||||
@@ -71,7 +73,7 @@ export default function VideoView(props: NodeViewProps) {
|
|||||||
</Group>
|
</Group>
|
||||||
)}
|
)}
|
||||||
{!src && !previewSrc && !placeholder && (
|
{!src && !previewSrc && !placeholder && (
|
||||||
<video className={classes.video} controls />
|
<video className={classes.video} controls aria-label={t("Video")} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</NodeViewWrapper>
|
</NodeViewWrapper>
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ export default function Breadcrumb() {
|
|||||||
));
|
));
|
||||||
|
|
||||||
const renderAnchor = useCallback(
|
const renderAnchor = useCallback(
|
||||||
(node: SpaceTreeNode) => (
|
(node: SpaceTreeNode, isCurrent = false) => (
|
||||||
<Tooltip label={node.name} key={node.id}>
|
<Tooltip label={node.name} key={node.id}>
|
||||||
<Anchor
|
<Anchor
|
||||||
component={Link}
|
component={Link}
|
||||||
@@ -91,6 +91,7 @@ export default function Breadcrumb() {
|
|||||||
fz="sm"
|
fz="sm"
|
||||||
key={node.id}
|
key={node.id}
|
||||||
className={classes.truncatedText}
|
className={classes.truncatedText}
|
||||||
|
aria-current={isCurrent ? "page" : undefined}
|
||||||
>
|
>
|
||||||
{getTitle(node.name, node.icon)}
|
{getTitle(node.name, node.icon)}
|
||||||
</Anchor>
|
</Anchor>
|
||||||
@@ -130,11 +131,13 @@ export default function Breadcrumb() {
|
|||||||
</Popover.Dropdown>
|
</Popover.Dropdown>
|
||||||
</Popover>,
|
</Popover>,
|
||||||
//renderAnchor(secondLastNode),
|
//renderAnchor(secondLastNode),
|
||||||
renderAnchor(lastNode),
|
renderAnchor(lastNode, true),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return breadcrumbNodes.map(renderAnchor);
|
return breadcrumbNodes.map((node, i) =>
|
||||||
|
renderAnchor(node, i === breadcrumbNodes.length - 1),
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getMobileBreadcrumbItems = () => {
|
const getMobileBreadcrumbItems = () => {
|
||||||
@@ -167,16 +170,18 @@ export default function Breadcrumb() {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return breadcrumbNodes.map(renderAnchor);
|
return breadcrumbNodes.map((node, i) =>
|
||||||
|
renderAnchor(node, i === breadcrumbNodes.length - 1),
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.breadcrumbDiv}>
|
<nav aria-label={t("Breadcrumb")} className={classes.breadcrumbDiv}>
|
||||||
{breadcrumbNodes && (
|
{breadcrumbNodes && (
|
||||||
<Breadcrumbs className={classes.breadcrumbs}>
|
<Breadcrumbs className={classes.breadcrumbs}>
|
||||||
{isMobile ? getMobileBreadcrumbItems() : getBreadcrumbItems()}
|
{isMobile ? getMobileBreadcrumbItems() : getBreadcrumbItems()}
|
||||||
</Breadcrumbs>
|
</Breadcrumbs>
|
||||||
)}
|
)}
|
||||||
</div>
|
</nav>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user