Rebuild the room summary card's widgets section

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski 2020-09-30 17:08:41 +01:00
parent ed30750f63
commit 23d95df30b
3 changed files with 144 additions and 72 deletions

View file

@ -109,9 +109,57 @@ limitations under the License.
} }
.mx_RoomSummaryCard_appsGroup { .mx_RoomSummaryCard_appsGroup {
.mx_RoomSummaryCard_widgetRow {
margin: 0;
display: flex;
.mx_RoomSummaryCard_app_pinToggle,
.mx_RoomSummaryCard_app_options {
position: relative;
height: 20px;
width: 20px;
padding: 10px;
border-radius: 8px;
&:hover {
background-color: rgba(141, 151, 165, 0.1);
}
&::before {
content: '';
position: absolute;
height: 20px;
width: 20px;
mask-repeat: no-repeat;
mask-position: center;
mask-size: 16px;
background-color: $icon-button-color;
}
}
.mx_RoomSummaryCard_app_pinToggle {
&::before {
mask-image: url('$(res)/img/element-icons/room/pin-upright.svg');
}
&.mx_RoomSummaryCard_app_pinned {
&::before {
background-color: $accent-color;
}
}
}
.mx_RoomSummaryCard_app_options {
&::before {
mask-image: url('$(res)/img/element-icons/room/ellipsis.svg');
}
}
}
.mx_RoomSummaryCard_Button { .mx_RoomSummaryCard_Button {
padding-left: 12px; padding-left: 12px;
color: $tertiary-fg-color; color: $tertiary-fg-color;
flex: 1;
span { span {
color: $primary-fg-color; color: $primary-fg-color;
@ -127,12 +175,6 @@ limitations under the License.
content: unset; content: unset;
} }
} }
.mx_RoomSummaryCard_icon_app_pinned::after {
mask-image: url('$(res)/img/element-icons/room/pin-upright.svg');
background-color: $accent-color;
transform: unset;
}
} }
.mx_AccessibleButton_kind_link { .mx_AccessibleButton_kind_link {

View file

@ -43,6 +43,9 @@ import WidgetStore, {IApp} from "../../../stores/WidgetStore";
import { E2EStatus } from "../../../utils/ShieldUtils"; import { E2EStatus } from "../../../utils/ShieldUtils";
import RoomContext from "../../../contexts/RoomContext"; import RoomContext from "../../../contexts/RoomContext";
import {UIFeature} from "../../../settings/UIFeature"; import {UIFeature} from "../../../settings/UIFeature";
import {ContextMenuButton} from "../../../accessibility/context_menu/ContextMenuButton";
import {ChevronFace, useContextMenu} from "../../structures/ContextMenu";
import RoomWidgetContextMenu from "../context_menus/RoomWidgetContextMenu";
interface IProps { interface IProps {
room: Room; room: Room;
@ -82,8 +85,93 @@ export const useWidgets = (room: Room) => {
return apps; return apps;
}; };
const AppsSection: React.FC<IAppsSectionProps> = ({ room }) => { interface IAppRowProps {
app: IApp;
}
const AppRow: React.FC<IAppRowProps> = ({ app }) => {
const cli = useContext(MatrixClientContext); const cli = useContext(MatrixClientContext);
const name = WidgetUtils.getWidgetName(app);
const dataTitle = WidgetUtils.getWidgetDataTitle(app);
const subtitle = dataTitle && " - " + dataTitle;
let iconUrls = [require("../../../../res/img/element-icons/room/default_app.svg")];
// heuristics for some better icons until Widgets support their own icons
if (app.type.includes("meeting") || app.type.includes("calendar")) {
iconUrls = [require("../../../../res/img/element-icons/room/default_cal.svg")];
} else if (app.type.includes("pad") || app.type.includes("doc") || app.type.includes("calc")) {
iconUrls = [require("../../../../res/img/element-icons/room/default_doc.svg")];
} else if (app.type.includes("clock")) {
iconUrls = [require("../../../../res/img/element-icons/room/default_clock.svg")];
}
if (app.avatar_url) { // MSC2765
iconUrls.unshift(getHttpUriForMxc(cli.getHomeserverUrl(), app.avatar_url, 20, 20, "crop"));
}
const onOpenWidgetClick = () => {
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
action: Action.SetRightPanelPhase,
phase: RightPanelPhases.Widget,
refireParams: {
widgetId: app.id,
},
});
};
const isPinned = WidgetStore.instance.isPinned(app.id);
const togglePin = isPinned
? () => { WidgetStore.instance.unpinWidget(app.id); }
: () => { WidgetStore.instance.pinWidget(app.id); };
const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu<HTMLDivElement>();
let contextMenu;
if (menuDisplayed) {
const rect = handle.current.getBoundingClientRect();
contextMenu = <RoomWidgetContextMenu
chevronFace={ChevronFace.None}
right={window.innerWidth - rect.right}
bottom={window.innerHeight - rect.top}
onFinished={closeMenu}
app={app}
/>;
}
return <div className="mx_RoomSummaryCard_widgetRow" ref={handle}>
<AccessibleTooltipButton
className="mx_BaseCard_Button mx_RoomSummaryCard_Button mx_RoomSummaryCard_icon_app"
onClick={onOpenWidgetClick}
// only show a tooltip if the widget is pinned
title={isPinned ? _t("You can't view pinned widgets in the right panel") : ""}
forceHide={!isPinned}
disabled={isPinned}
>
<BaseAvatar name={app.id} urls={iconUrls} width={20} height={20} />
<span>{name}</span>
{ subtitle }
</AccessibleTooltipButton>
<AccessibleTooltipButton
className={classNames("mx_RoomSummaryCard_app_pinToggle", {
mx_RoomSummaryCard_app_pinned: isPinned,
})}
onClick={togglePin}
title={isPinned ? _t("Unpin") : _t("Pin")}
/>
<ContextMenuButton
className="mx_RoomSummaryCard_app_options"
isExpanded={menuDisplayed}
onClick={openMenu}
label={_t("Options")}
/>
{ contextMenu }
</div>;
};
const AppsSection: React.FC<IAppsSectionProps> = ({ room }) => {
const apps = useWidgets(room); const apps = useWidgets(room);
const onManageIntegrations = () => { const onManageIntegrations = () => {
@ -100,65 +188,7 @@ const AppsSection: React.FC<IAppsSectionProps> = ({ room }) => {
}; };
return <Group className="mx_RoomSummaryCard_appsGroup" title={_t("Widgets")}> return <Group className="mx_RoomSummaryCard_appsGroup" title={_t("Widgets")}>
{ apps.map(app => { { apps.map(app => <AppRow key={app.id} app={app} />) }
const name = WidgetUtils.getWidgetName(app);
const dataTitle = WidgetUtils.getWidgetDataTitle(app);
const subtitle = dataTitle && " - " + dataTitle;
let iconUrls = [require("../../../../res/img/element-icons/room/default_app.svg")];
// heuristics for some better icons until Widgets support their own icons
if (app.type.includes("meeting") || app.type.includes("calendar")) {
iconUrls = [require("../../../../res/img/element-icons/room/default_cal.svg")];
} else if (app.type.includes("pad") || app.type.includes("doc") || app.type.includes("calc")) {
iconUrls = [require("../../../../res/img/element-icons/room/default_doc.svg")];
} else if (app.type.includes("clock")) {
iconUrls = [require("../../../../res/img/element-icons/room/default_clock.svg")];
}
if (app.avatar_url) { // MSC2765
iconUrls.unshift(getHttpUriForMxc(cli.getHomeserverUrl(), app.avatar_url, 20, 20, "crop"));
}
const isPinned = WidgetStore.instance.isPinned(app.id);
const classes = classNames("mx_RoomSummaryCard_icon_app", {
mx_RoomSummaryCard_icon_app_pinned: isPinned,
});
if (isPinned) {
const onClick = () => {
WidgetStore.instance.unpinWidget(app.id);
};
return <AccessibleTooltipButton
key={app.id}
className={classNames("mx_BaseCard_Button mx_RoomSummaryCard_Button", classes)}
onClick={onClick}
title={_t("Unpin app")}
>
<BaseAvatar name={app.id} urls={iconUrls} width={20} height={20} />
<span>{name}</span>
{ subtitle }
</AccessibleTooltipButton>
}
const onOpenWidgetClick = () => {
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
action: Action.SetRightPanelPhase,
phase: RightPanelPhases.Widget,
refireParams: {
widgetId: app.id,
},
});
};
return (
<Button key={app.id} className={classes} onClick={onOpenWidgetClick}>
<BaseAvatar name={app.id} urls={iconUrls} width={20} height={20} />
<span>{name}</span>
{ subtitle }
</Button>
);
}) }
<AccessibleButton kind="link" onClick={onManageIntegrations}> <AccessibleButton kind="link" onClick={onManageIntegrations}>
{ apps.length > 0 ? _t("Edit widgets, bridges & bots") : _t("Add widgets, bridges & bots") } { apps.length > 0 ? _t("Edit widgets, bridges & bots") : _t("Add widgets, bridges & bots") }

View file

@ -1274,8 +1274,10 @@
"Yours, or the other users session": "Yours, or the other users session", "Yours, or the other users session": "Yours, or the other users session",
"Members": "Members", "Members": "Members",
"Room Info": "Room Info", "Room Info": "Room Info",
"You can't view pinned widgets in the right panel": "You can't view pinned widgets in the right panel",
"Unpin": "Unpin",
"Options": "Options",
"Widgets": "Widgets", "Widgets": "Widgets",
"Unpin app": "Unpin app",
"Edit widgets, bridges & bots": "Edit widgets, bridges & bots", "Edit widgets, bridges & bots": "Edit widgets, bridges & bots",
"Add widgets, bridges & bots": "Add widgets, bridges & bots", "Add widgets, bridges & bots": "Add widgets, bridges & bots",
"Not encrypted": "Not encrypted", "Not encrypted": "Not encrypted",
@ -1298,7 +1300,6 @@
"Invite": "Invite", "Invite": "Invite",
"Share Link to User": "Share Link to User", "Share Link to User": "Share Link to User",
"Direct message": "Direct message", "Direct message": "Direct message",
"Options": "Options",
"Demote yourself?": "Demote yourself?", "Demote yourself?": "Demote yourself?",
"You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.": "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.", "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.": "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.",
"Demote": "Demote", "Demote": "Demote",
@ -1362,9 +1363,6 @@
"You cancelled verification.": "You cancelled verification.", "You cancelled verification.": "You cancelled verification.",
"Verification cancelled": "Verification cancelled", "Verification cancelled": "Verification cancelled",
"Compare emoji": "Compare emoji", "Compare emoji": "Compare emoji",
"Take a picture": "Take a picture",
"Remove for everyone": "Remove for everyone",
"Remove for me": "Remove for me",
"Edit": "Edit", "Edit": "Edit",
"Pin to room": "Pin to room", "Pin to room": "Pin to room",
"You can only pin 2 widgets at a time": "You can only pin 2 widgets at a time", "You can only pin 2 widgets at a time": "You can only pin 2 widgets at a time",
@ -1924,12 +1922,14 @@
"Source URL": "Source URL", "Source URL": "Source URL",
"Collapse Reply Thread": "Collapse Reply Thread", "Collapse Reply Thread": "Collapse Reply Thread",
"Report Content": "Report Content", "Report Content": "Report Content",
"Take a picture": "Take a picture",
"Remove for everyone": "Remove for everyone",
"Remove for me": "Remove for me",
"Clear status": "Clear status", "Clear status": "Clear status",
"Update status": "Update status", "Update status": "Update status",
"Set status": "Set status", "Set status": "Set status",
"Set a new status...": "Set a new status...", "Set a new status...": "Set a new status...",
"View Community": "View Community", "View Community": "View Community",
"Unpin": "Unpin",
"Reload": "Reload", "Reload": "Reload",
"Take picture": "Take picture", "Take picture": "Take picture",
"This room is public": "This room is public", "This room is public": "This room is public",