Clean up html structure (#1869)

Fix different html syntax errors to improve a11y.
This commit is contained in:
Eduard Heimbuch
2021-11-29 13:57:05 +01:00
committed by GitHub
parent 542a5aac59
commit 5eb1d9cd22
19 changed files with 105 additions and 708 deletions

View File

@@ -0,0 +1,2 @@
- type: fixed
description: Cleanup html errors ([#1869](https://github.com/scm-manager/scm-manager/pull/1869))

View File

@@ -36,8 +36,9 @@ const DateFromNow: FC<Props> = ({ className, ...dateProps }) => {
return null;
}
const dateTime = formatter.formatFull();
return (
<DateElement className={className} title={formatter.formatFull()}>
<DateElement className={className} dateTime={dateTime} title={dateTime}>
{formatter.formatDistance()}
</DateElement>
);

View File

@@ -36,8 +36,9 @@ const DateShort: FC<Props> = ({ className, ...dateProps }) => {
return null;
}
const dateTime = formatter.formatFull();
return (
<DateElement className={className} title={formatter.formatFull()}>
<DateElement className={className} dateTime={dateTime} title={dateTime}>
{formatter.formatShort()}
</DateElement>
);

View File

@@ -46,14 +46,14 @@ const Icon: FC<Props> = ({
className,
onClick,
testId,
tabIndex = -1,
tabIndex,
onEnter,
alt = title,
alt = title
}) => {
return (
<i
onClick={onClick}
onKeyPress={(event) => event.key === "Enter" && onEnter && onEnter(event)}
onKeyPress={event => event.key === "Enter" && onEnter && onEnter(event)}
title={title}
className={classNames(iconStyle, "fa-fw", "fa-" + name, `has-text-${color}`, className)}
tabIndex={tabIndex}

View File

@@ -52,7 +52,7 @@ const OverviewPageActions: FC<Props> = ({
groupSelected,
label,
testId,
searchPlaceholder,
searchPlaceholder
}) => {
const history = useHistory();
const location = useLocation();
@@ -63,7 +63,7 @@ const OverviewPageActions: FC<Props> = ({
<div className="column is-flex">
<Select
className="is-fullwidth"
options={groups.map((g) => ({ value: g, label: g }))}
options={groups.map(g => ({ value: g, label: g }))}
value={currentGroup}
onChange={groupSelected}
/>

View File

@@ -36,7 +36,7 @@ export type TooltipLocation = "bottom" | "right" | "top" | "left";
class Tooltip extends React.Component<Props> {
static defaultProps = {
location: "right",
location: "right"
};
render() {

View File

@@ -77,6 +77,7 @@ const FilterInput: FC<Props> = ({ filter, value, testId, placeholder, autoFocus,
onChange={event => setStateValue(event.target.value)}
autoFocus={autoFocus || false}
aria-describedby={id}
aria-label={t("filterEntries")}
{...createAttributesForTesting(testId)}
/>
<span className="icon is-small is-left">

View File

@@ -69,7 +69,7 @@ const InnerSelect: FC<FieldProps<BaseProps, HTMLSelectElement, string>> = ({
const field = useInnerRef(props.innerRef);
let opts = options;
if (value && addValueToOptions && !options.some((o) => o.value === value)) {
if (value && addValueToOptions && !options.some(o => o.value === value)) {
opts = [{ label: value, value }, ...options];
}
@@ -124,11 +124,11 @@ const InnerSelect: FC<FieldProps<BaseProps, HTMLSelectElement, string>> = ({
onChange={handleInput}
onBlur={handleBlur}
disabled={disabled}
aria-labelledby={a11yId}
aria-describedby={helpId}
aria-labelledby={label ? a11yId : undefined}
aria-describedby={helpText ? helpId : undefined}
{...createAttributesForTesting(testId)}
>
{opts.map((opt) => {
{opts.map(opt => {
return (
<option value={opt.value} key={"KEY_" + opt.value}>
{opt.label}

View File

@@ -37,7 +37,7 @@ const SmallHeader: FC<{ children: ReactNode }> = ({ children }) => {
const LargeHeader: FC = () => {
return (
<section className="hero has-scm-background is-small">
<div className="hero has-scm-background is-small">
<div className="hero-body">
<div className="container">
<div className="columns is-vcentered">
@@ -47,7 +47,7 @@ const LargeHeader: FC = () => {
</div>
</div>
</div>
</section>
</div>
);
};

View File

@@ -91,7 +91,7 @@ const SecondaryNavigation: FC<Props> = ({ label, children, collapsible = true })
aria-label={menuAriaLabel}
>
{collapsible ? (
<Icon color="info" className="is-medium" collapsed={isCollapsed}>
<Icon className="is-medium" collapsed={isCollapsed}>
{arrowIcon}
</Icon>
) : null}

View File

@@ -86,13 +86,13 @@ const RepositoryFlags: FC<Props> = ({ repository, className, tooltipLocation = "
);
return (
<span className={classNames("is-flex", "is-align-items-center", className)}>
<div className={classNames("is-flex", "is-align-items-center", className)}>
{modal}
<RepositoryFlagContainer>
{repositoryFlags}
<ExtensionPoint name="repository.flags" props={{ repository, tooltipLocation }} renderAll={true} />
</RepositoryFlagContainer>
</span>
</div>
);
};

View File

@@ -58,7 +58,8 @@
"logout": "Abmelden",
"login": "Anmelden",
"groups": "Gruppen",
"admin": "Administration"
"admin": "Administration",
"navbarBurger": "Navigation öffnen"
},
"secondaryNavigation": {
"showContent": "Navigation vergrößern",
@@ -179,6 +180,8 @@
"w_plural": "{{count}} Wochen"
},
"search": {
"ariaLabel": "Globale Suche",
"placeholder": "Suche...",
"title": "Suche",
"subtitle": "{{type}} Ergebnisse für \"{{query}}\"",
"types": "Ergebnisse",

View File

@@ -59,7 +59,8 @@
"logout": "Logout",
"login": "Login",
"groups": "Groups",
"admin": "Administration"
"admin": "Administration",
"navbarBurger": "Open navigation"
},
"secondaryNavigation": {
"showContent": "Enlarge navigation",
@@ -180,6 +181,8 @@
"w_plural": "{{count}} weeks"
},
"search": {
"ariaLabel": "Global search",
"placeholder": "Search...",
"title": "Search",
"subtitle": "{{type}} results for \"{{query}}\"",
"types": "Results",

View File

@@ -30,6 +30,7 @@ import Notifications from "./Notifications";
import OmniSearch from "./OmniSearch";
import LogoutButton from "./LogoutButton";
import LoginButton from "./LoginButton";
import { useTranslation } from "react-i18next";
const StyledMenuBar = styled.div`
background-color: transparent !important;
@@ -116,6 +117,7 @@ type Props = {
const NavigationBar: FC<Props> = ({ links }) => {
const [burgerActive, setBurgerActive] = useState(false);
const [t] = useTranslation("commons");
useEffect(() => {
const close = () => {
if (burgerActive) {
@@ -127,7 +129,7 @@ const NavigationBar: FC<Props> = ({ links }) => {
}, [burgerActive]);
return (
<StyledNavBar className="navbar mb-0 container" role="navigation" aria-label="main navigation">
<StyledNavBar className="navbar mb-0 container" aria-label="main navigation">
<div className="navbar-brand">
<LogoItem className="navbar-item logo">
<Logo withText={false} className="image is-32x32" />
@@ -135,7 +137,8 @@ const NavigationBar: FC<Props> = ({ links }) => {
<button
className={classNames("navbar-burger", { "is-active": burgerActive })}
aria-expanded="true"
onClick={() => setBurgerActive((active) => !active)}
onClick={() => setBurgerActive(active => !active)}
aria-label={t("primary-navigation.navbarBurger")}
>
<span aria-hidden="true" />
<span aria-hidden="true" />

View File

@@ -119,10 +119,10 @@ const HitsList: FC<HitsProps> = ({ hits, index, clear, gotoDetailSearch }) => {
return (
<>
{hits.map((hit, idx) => (
<div key={id(hit)} onMouseDown={(e) => e.preventDefault()} onClick={clear}>
<div key={id(hit)} onMouseDown={e => e.preventDefault()} onClick={clear}>
<Link
className={classNames("is-flex", "dropdown-item", "has-text-weight-medium", "is-ellipsis-overflow", {
"is-active": idx === index,
"is-active": idx === index
})}
title={id(hit)}
to={`/repo/${id(hit)}`}
@@ -179,7 +179,7 @@ const useKeyBoardNavigation = (gotoDetailSearch: () => void, clear: () => void,
switch (e.which) {
case 40: // e.code: ArrowDown
if (hits) {
setIndex((idx) => {
setIndex(idx => {
if (idx + 1 < hits.length) {
return idx + 1;
}
@@ -189,7 +189,7 @@ const useKeyBoardNavigation = (gotoDetailSearch: () => void, clear: () => void,
break;
case 38: // e.code: ArrowUp
if (hits) {
setIndex((idx) => {
setIndex(idx => {
if (idx > 0) {
return idx - 1;
}
@@ -219,7 +219,7 @@ const useKeyBoardNavigation = (gotoDetailSearch: () => void, clear: () => void,
return {
onKeyDown,
index,
index
};
};
@@ -278,7 +278,7 @@ const useShowResultsOnFocus = () => {
},
onKeyPress: () => setShowResults(true),
onFocus: () => setShowResults(true),
hideResults: () => setShowResults(false),
hideResults: () => setShowResults(false)
};
};
@@ -303,11 +303,12 @@ const useSearchParams = () => {
return {
searchType,
initialQuery,
initialQuery
};
};
const OmniSearch: FC = () => {
const [t] = useTranslation("commons");
const { searchType, initialQuery } = useSearchParams();
const [query, setQuery] = useState(initialQuery);
const debouncedQuery = useDebounce(query, 250);
@@ -334,7 +335,7 @@ const OmniSearch: FC = () => {
{showHelp ? <SyntaxModal close={closeHelp} /> : null}
<div
className={classNames("control", "has-icons-right", {
"is-loading": isLoading,
"is-loading": isLoading
})}
>
<div className={classNames("dropdown", { "is-active": (!!data || error) && showResults })}>
@@ -342,13 +343,15 @@ const OmniSearch: FC = () => {
<Input
className="input is-small"
type="text"
placeholder="Search ..."
onChange={(e) => setQuery(e.target.value)}
placeholder={t("search.placeholder")}
onChange={e => setQuery(e.target.value)}
onKeyDown={onKeyDown}
value={query}
role="combobox"
aria-autocomplete="list"
data-omnisearch="true"
aria-expanded={query.length > 2}
aria-label={t("search.ariaLabel")}
{...handlers}
/>
{isLoading ? null : (
@@ -357,7 +360,7 @@ const OmniSearch: FC = () => {
</span>
)}
</div>
<DropdownMenu className="dropdown-menu" onMouseDown={(e) => e.preventDefault()}>
<DropdownMenu className="dropdown-menu" onMouseDown={e => e.preventDefault()}>
{error ? (
<QuickSearchNotification>
<SearchErrorNotification error={error} showHelp={openHelp} />

View File

@@ -35,7 +35,7 @@ const RepositoryGroupEntry: FC<Props> = ({ group }) => {
const [t] = useTranslation("namespaces");
const settingsLink = group.namespace?._links?.permissions && (
<Link to={`/namespace/${group.name}/settings`}>
<Link to={`/namespace/${group.name}/settings`} aria-label={t("repositoryOverview.settings.tooltip")}>
<Icon color="inherit" name="cog" title={t("repositoryOverview.settings.tooltip")} className="is-size-6 ml-2" />
</Link>
);

View File

@@ -33,13 +33,11 @@ type Props = {
const FileIcon: FC<Props> = ({ file }) => {
const [t] = useTranslation("repos");
if (file.subRepository) {
return (
<Icon title={t("sources.fileTree.subRepository")} iconStyle="far" name="folder" color="inherit" tabIndex={-1} />
);
return <Icon title={t("sources.fileTree.subRepository")} iconStyle="far" name="folder" color="inherit" />;
} else if (file.directory) {
return <Icon title={t("sources.fileTree.folder")} name="folder" color="inherit" tabIndex={-1} />;
return <Icon title={t("sources.fileTree.folder")} name="folder" color="inherit" />;
}
return <Icon title={t("sources.fileTree.file")} name="file" color="inherit" tabIndex={-1} />;
return <Icon title={t("sources.fileTree.file")} name="file" color="inherit" />;
};
export default FileIcon;

View File

@@ -55,9 +55,7 @@ class UserRow extends React.Component<Props> {
{iconType} {this.renderLink(to, user.name)}
</td>
<td className="is-hidden-mobile">{this.renderLink(to, user.displayName)}</td>
<td>
<a href={`mailto:${user.mail}`}>{user.mail}</a>
</td>
<td>{user.mail ? <a href={`mailto:${user.mail}`}>{user.mail}</a> : null}</td>
</tr>
);
}