Load icons using @svgr (#7928)
* extend svg module Signed-off-by: Kerry Archibald <kerrya@element.io> * POC in QuickSettingsButton Signed-off-by: Kerry Archibald <kerrya@element.io> * stylelint Signed-off-by: Kerry Archibald <kerrya@element.io> * update copyright Signed-off-by: Kerry Archibald <kerrya@element.io> * remove aria-hidden, quick docs Signed-off-by: Kerry Archibald <kerrya@element.io>
This commit is contained in:
parent
d50dae5208
commit
e6ea58e84d
4 changed files with 70 additions and 53 deletions
44
docs/icons.md
Normal file
44
docs/icons.md
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
# Icons
|
||||||
|
|
||||||
|
Icons are loaded using [@svgr/webpack](https://www.npmjs.com/package/@svgr/webpack). This is configured in [element-web](https://github.com/vector-im/element-web/blob/develop/webpack.config.js#L458)
|
||||||
|
|
||||||
|
Each .svg exports a `ReactComponent` at the named export `Icon`.
|
||||||
|
Icons have `role="presentation"` and `aria-hidden` automatically applied. These can be overriden by passing props to the icon component.
|
||||||
|
|
||||||
|
eg
|
||||||
|
```
|
||||||
|
import { Icon as FavoriteIcon } from 'res/img/element-icons/favorite.svg';
|
||||||
|
|
||||||
|
const MyComponent = () => {
|
||||||
|
return <>
|
||||||
|
<FavoriteIcon>
|
||||||
|
<FavoriteIcon className="mx_MyComponent-icon" role="img" aria-hidden="false">
|
||||||
|
</>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Styling
|
||||||
|
|
||||||
|
Icon components are svg elements and can be styled as usual.
|
||||||
|
|
||||||
|
```
|
||||||
|
// _MyComponents.scss
|
||||||
|
.mx_MyComponent-icon {
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
|
||||||
|
* {
|
||||||
|
fill: $accent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MyComponent.tsx
|
||||||
|
import { Icon as FavoriteIcon } from 'res/img/element-icons/favorite.svg';
|
||||||
|
|
||||||
|
const MyComponent = () => {
|
||||||
|
return <>
|
||||||
|
<FavoriteIcon>
|
||||||
|
<FavoriteIcon className="mx_MyComponent-icon" role="img" aria-hidden="false">
|
||||||
|
</>;
|
||||||
|
}
|
||||||
|
```
|
|
@ -82,21 +82,6 @@ limitations under the License.
|
||||||
.mx_QuickSettingsButton_pinToSidebarHeading {
|
.mx_QuickSettingsButton_pinToSidebarHeading {
|
||||||
padding-left: 24px;
|
padding-left: 24px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&::before {
|
|
||||||
background-color: $secondary-content;
|
|
||||||
content: "";
|
|
||||||
mask-repeat: no-repeat;
|
|
||||||
mask-position: center;
|
|
||||||
mask-size: contain;
|
|
||||||
mask-image: url('$(res)/img/element-icons/room/pin-upright.svg');
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Checkbox {
|
.mx_Checkbox {
|
||||||
|
@ -112,31 +97,9 @@ limitations under the License.
|
||||||
font-size: $font-15px;
|
font-size: $font-15px;
|
||||||
line-height: $font-24px;
|
line-height: $font-24px;
|
||||||
color: $secondary-content;
|
color: $secondary-content;
|
||||||
|
|
||||||
&::before {
|
|
||||||
background-color: $secondary-content;
|
|
||||||
content: "";
|
|
||||||
mask-repeat: no-repeat;
|
|
||||||
mask-position: center;
|
|
||||||
mask-size: contain;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_QuickSettingsButton_favouritesCheckbox .mx_Checkbox_background + div::before {
|
|
||||||
mask-image: url('$(res)/img/element-icons/roomlist/favorite.svg');
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_QuickSettingsButton_peopleCheckbox .mx_Checkbox_background + div::before {
|
|
||||||
mask-image: url('$(res)/img/element-icons/room/members.svg');
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_QuickSettingsButton_moreOptionsButton {
|
.mx_QuickSettingsButton_moreOptionsButton {
|
||||||
padding-left: 22px;
|
padding-left: 22px;
|
||||||
margin-left: 22px;
|
margin-left: 22px;
|
||||||
|
@ -145,20 +108,17 @@ limitations under the License.
|
||||||
color: $secondary-content;
|
color: $secondary-content;
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
|
|
||||||
&::before {
|
|
||||||
background-color: $secondary-content;
|
|
||||||
content: "";
|
|
||||||
mask-repeat: no-repeat;
|
|
||||||
mask-position: center;
|
|
||||||
mask-size: contain;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
mask-image: url('$(res)/img/element-icons/room/ellipsis.svg');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_QuickSettingsButton_icon {
|
||||||
|
* {
|
||||||
|
fill: $secondary-content;
|
||||||
|
}
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
2
src/@types/svg.d.ts
vendored
2
src/@types/svg.d.ts
vendored
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
|
Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
|
||||||
|
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -16,5 +17,6 @@ limitations under the License.
|
||||||
|
|
||||||
declare module "*.svg" {
|
declare module "*.svg" {
|
||||||
const path: string;
|
const path: string;
|
||||||
|
export const Icon: React.FC<React.SVGProps<SVGSVGElement>>;
|
||||||
export default path;
|
export default path;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,10 @@ import defaultDispatcher from "../../../dispatcher/dispatcher";
|
||||||
import { Action } from "../../../dispatcher/actions";
|
import { Action } from "../../../dispatcher/actions";
|
||||||
import { UserTab } from "../dialogs/UserSettingsDialog";
|
import { UserTab } from "../dialogs/UserSettingsDialog";
|
||||||
import QuickThemeSwitcher from "./QuickThemeSwitcher";
|
import QuickThemeSwitcher from "./QuickThemeSwitcher";
|
||||||
|
import { Icon as PinUprightIcon } from '../../../../res/img/element-icons/room/pin-upright.svg';
|
||||||
|
import { Icon as EllipsisIcon } from '../../../../res/img/element-icons/room/ellipsis.svg';
|
||||||
|
import { Icon as MembersIcon } from '../../../../res/img/element-icons/room/members.svg';
|
||||||
|
import { Icon as FavoriteIcon } from '../../../../res/img/element-icons/roomlist/favorite.svg';
|
||||||
|
|
||||||
const QuickSettingsButton = ({ isPanelCollapsed = false }) => {
|
const QuickSettingsButton = ({ isPanelCollapsed = false }) => {
|
||||||
const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu<HTMLDivElement>();
|
const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu<HTMLDivElement>();
|
||||||
|
@ -59,13 +63,17 @@ const QuickSettingsButton = ({ isPanelCollapsed = false }) => {
|
||||||
{ _t("All settings") }
|
{ _t("All settings") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
|
|
||||||
<h4 className="mx_QuickSettingsButton_pinToSidebarHeading">{ _t("Pin to sidebar") }</h4>
|
<h4 className="mx_QuickSettingsButton_pinToSidebarHeading">
|
||||||
|
<PinUprightIcon className="mx_QuickSettingsButton_icon" />
|
||||||
|
{ _t("Pin to sidebar") }
|
||||||
|
</h4>
|
||||||
|
|
||||||
<StyledCheckbox
|
<StyledCheckbox
|
||||||
className="mx_QuickSettingsButton_favouritesCheckbox"
|
className="mx_QuickSettingsButton_favouritesCheckbox"
|
||||||
checked={!!favouritesEnabled}
|
checked={!!favouritesEnabled}
|
||||||
onChange={onMetaSpaceChangeFactory(MetaSpace.Favourites, "WebQuickSettingsPinToSidebarCheckbox")}
|
onChange={onMetaSpaceChangeFactory(MetaSpace.Favourites, "WebQuickSettingsPinToSidebarCheckbox")}
|
||||||
>
|
>
|
||||||
|
<FavoriteIcon className="mx_QuickSettingsButton_icon" />
|
||||||
{ _t("Favourites") }
|
{ _t("Favourites") }
|
||||||
</StyledCheckbox>
|
</StyledCheckbox>
|
||||||
<StyledCheckbox
|
<StyledCheckbox
|
||||||
|
@ -73,6 +81,8 @@ const QuickSettingsButton = ({ isPanelCollapsed = false }) => {
|
||||||
checked={!!peopleEnabled}
|
checked={!!peopleEnabled}
|
||||||
onChange={onMetaSpaceChangeFactory(MetaSpace.People, "WebQuickSettingsPinToSidebarCheckbox")}
|
onChange={onMetaSpaceChangeFactory(MetaSpace.People, "WebQuickSettingsPinToSidebarCheckbox")}
|
||||||
>
|
>
|
||||||
|
|
||||||
|
<MembersIcon className="mx_QuickSettingsButton_icon" />
|
||||||
{ _t("People") }
|
{ _t("People") }
|
||||||
</StyledCheckbox>
|
</StyledCheckbox>
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
|
@ -85,6 +95,7 @@ const QuickSettingsButton = ({ isPanelCollapsed = false }) => {
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<EllipsisIcon className="mx_QuickSettingsButton_icon" />
|
||||||
{ _t("More options") }
|
{ _t("More options") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue