mirror of
https://github.com/cinnyapp/cinny.git
synced 2025-02-24 06:03:04 +01:00
add room nav item component in space room list
This commit is contained in:
parent
0b8a9d64f9
commit
45a5717560
8 changed files with 305 additions and 61 deletions
17
src/app/components/nav/NavItemOptions.tsx
Normal file
17
src/app/components/nav/NavItemOptions.tsx
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import React, { ComponentProps } from 'react';
|
||||||
|
import { Box, as } from 'folds';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import * as css from './styles.css';
|
||||||
|
|
||||||
|
export const NavItemOptions = as<'div', ComponentProps<typeof Box>>(
|
||||||
|
({ className, ...props }, ref) => (
|
||||||
|
<Box
|
||||||
|
className={classNames(css.NavItemOptions, className)}
|
||||||
|
alignItems="Center"
|
||||||
|
shrink="No"
|
||||||
|
gap="0"
|
||||||
|
{...props}
|
||||||
|
ref={ref}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
);
|
|
@ -3,3 +3,4 @@ export * from './NavCategoryHeader';
|
||||||
export * from './NavEmptyLayout';
|
export * from './NavEmptyLayout';
|
||||||
export * from './NavItem';
|
export * from './NavItem';
|
||||||
export * from './NavItemContent';
|
export * from './NavItemContent';
|
||||||
|
export * from './NavItemOptions';
|
||||||
|
|
|
@ -52,13 +52,15 @@ const NavItemBase = style({
|
||||||
color: OnContainer,
|
color: OnContainer,
|
||||||
outline: 'none',
|
outline: 'none',
|
||||||
minHeight: toRem(38),
|
minHeight: toRem(38),
|
||||||
gap: config.space.S200,
|
|
||||||
|
|
||||||
selectors: {
|
selectors: {
|
||||||
'&:hover, &:focus-visible': {
|
'&:hover, &:focus-visible': {
|
||||||
backgroundColor: ContainerHover,
|
backgroundColor: ContainerHover,
|
||||||
},
|
},
|
||||||
'&:active': {
|
'&[data-hover=true]': {
|
||||||
|
backgroundColor: ContainerHover,
|
||||||
|
},
|
||||||
|
[`&:has(.${NavLink}:active)`]: {
|
||||||
backgroundColor: ContainerActive,
|
backgroundColor: ContainerActive,
|
||||||
},
|
},
|
||||||
'&[aria-selected=true]': {
|
'&[aria-selected=true]': {
|
||||||
|
@ -121,3 +123,7 @@ export const NavItemContent = style({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const NavItemOptions = style({
|
||||||
|
paddingRight: config.space.S200,
|
||||||
|
});
|
||||||
|
|
252
src/app/features/room-nav-item/RoomNavItem.tsx
Normal file
252
src/app/features/room-nav-item/RoomNavItem.tsx
Normal file
|
@ -0,0 +1,252 @@
|
||||||
|
import React, { MouseEventHandler, forwardRef, useState } from 'react';
|
||||||
|
import { Room } from 'matrix-js-sdk';
|
||||||
|
import {
|
||||||
|
Avatar,
|
||||||
|
Box,
|
||||||
|
Icon,
|
||||||
|
IconButton,
|
||||||
|
Icons,
|
||||||
|
Text,
|
||||||
|
Menu,
|
||||||
|
MenuItem,
|
||||||
|
config,
|
||||||
|
PopOut,
|
||||||
|
toRem,
|
||||||
|
Line,
|
||||||
|
} from 'folds';
|
||||||
|
import { useFocusWithin, useHover } from 'react-aria';
|
||||||
|
import FocusTrap from 'focus-trap-react';
|
||||||
|
import { NavItem, NavItemContent, NavItemOptions, NavLink } from '../../components/nav';
|
||||||
|
import { UnreadBadge, UnreadBadgeCenter } from '../../components/unread-badge';
|
||||||
|
import { RoomAvatar, RoomIcon } from '../../components/room-avatar';
|
||||||
|
import { getRoomAvatarUrl } from '../../utils/room';
|
||||||
|
import { nameInitials } from '../../utils/common';
|
||||||
|
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
||||||
|
import { useRoomUnread } from '../../state/hooks/unread';
|
||||||
|
import { roomToUnreadAtom } from '../../state/room/roomToUnread';
|
||||||
|
import { usePowerLevels } from '../../hooks/usePowerLevels';
|
||||||
|
import { copyToClipboard } from '../../utils/dom';
|
||||||
|
import { getOriginBaseUrl, withOriginBaseUrl } from '../../pages/pathUtils';
|
||||||
|
import { markAsRead } from '../../../client/action/notifications';
|
||||||
|
import { openInviteUser } from '../../../client/action/navigation';
|
||||||
|
|
||||||
|
type RoomNavItemMenuProps = {
|
||||||
|
room: Room;
|
||||||
|
linkPath: string;
|
||||||
|
requestClose: () => void;
|
||||||
|
};
|
||||||
|
const RoomNavItemMenu = forwardRef<HTMLDivElement, RoomNavItemMenuProps>(
|
||||||
|
({ room, linkPath, requestClose }, ref) => {
|
||||||
|
const mx = useMatrixClient();
|
||||||
|
const unread = useRoomUnread(room.roomId, roomToUnreadAtom);
|
||||||
|
const { getPowerLevel, canDoAction } = usePowerLevels(room);
|
||||||
|
const canInvite = canDoAction('invite', getPowerLevel(mx.getUserId() ?? ''));
|
||||||
|
|
||||||
|
const handleMarkAsRead = () => {
|
||||||
|
markAsRead(room.roomId);
|
||||||
|
requestClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInvite = () => {
|
||||||
|
openInviteUser(room.roomId);
|
||||||
|
requestClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCopyLink = () => {
|
||||||
|
copyToClipboard(withOriginBaseUrl(getOriginBaseUrl(), linkPath));
|
||||||
|
requestClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRoomSettings = () => {
|
||||||
|
alert('Work In Progress...');
|
||||||
|
requestClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleLeaveRoom = () => {
|
||||||
|
mx.leave(room.roomId);
|
||||||
|
requestClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Menu ref={ref} style={{ maxWidth: toRem(160), width: '100vw' }}>
|
||||||
|
<Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
|
||||||
|
<MenuItem
|
||||||
|
onClick={handleMarkAsRead}
|
||||||
|
size="300"
|
||||||
|
after={<Icon size="100" src={Icons.CheckTwice} />}
|
||||||
|
radii="300"
|
||||||
|
disabled={!unread}
|
||||||
|
>
|
||||||
|
<Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
|
||||||
|
Mark as Read
|
||||||
|
</Text>
|
||||||
|
</MenuItem>
|
||||||
|
</Box>
|
||||||
|
<Line variant="Surface" size="300" />
|
||||||
|
<Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
|
||||||
|
<MenuItem
|
||||||
|
onClick={handleInvite}
|
||||||
|
variant="Primary"
|
||||||
|
fill="None"
|
||||||
|
size="300"
|
||||||
|
after={<Icon size="100" src={Icons.UserPlus} />}
|
||||||
|
radii="300"
|
||||||
|
disabled={!canInvite}
|
||||||
|
>
|
||||||
|
<Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
|
||||||
|
Invite
|
||||||
|
</Text>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem
|
||||||
|
onClick={handleCopyLink}
|
||||||
|
size="300"
|
||||||
|
after={<Icon size="100" src={Icons.Link} />}
|
||||||
|
radii="300"
|
||||||
|
>
|
||||||
|
<Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
|
||||||
|
Copy Link
|
||||||
|
</Text>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem
|
||||||
|
onClick={handleRoomSettings}
|
||||||
|
size="300"
|
||||||
|
after={<Icon size="100" src={Icons.Setting} />}
|
||||||
|
radii="300"
|
||||||
|
>
|
||||||
|
<Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
|
||||||
|
Room Settings
|
||||||
|
</Text>
|
||||||
|
</MenuItem>
|
||||||
|
</Box>
|
||||||
|
<Line variant="Surface" size="300" />
|
||||||
|
<Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
|
||||||
|
<MenuItem
|
||||||
|
onClick={handleLeaveRoom}
|
||||||
|
variant="Critical"
|
||||||
|
fill="None"
|
||||||
|
size="300"
|
||||||
|
after={<Icon size="100" src={Icons.ArrowGoLeft} />}
|
||||||
|
radii="300"
|
||||||
|
>
|
||||||
|
<Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
|
||||||
|
Leave Room
|
||||||
|
</Text>
|
||||||
|
</MenuItem>
|
||||||
|
</Box>
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
type RoomNavItemProps = {
|
||||||
|
room: Room;
|
||||||
|
selected: boolean;
|
||||||
|
linkPath: string;
|
||||||
|
muted?: boolean;
|
||||||
|
direct?: boolean;
|
||||||
|
};
|
||||||
|
export function RoomNavItem({ room, selected, direct, muted, linkPath }: RoomNavItemProps) {
|
||||||
|
const mx = useMatrixClient();
|
||||||
|
const [hover, setHover] = useState(false);
|
||||||
|
const { hoverProps } = useHover({ onHoverChange: setHover });
|
||||||
|
const { focusWithinProps } = useFocusWithin({ onFocusWithinChange: setHover });
|
||||||
|
const [menu, setMenu] = useState(false);
|
||||||
|
const unread = useRoomUnread(room.roomId, roomToUnreadAtom);
|
||||||
|
|
||||||
|
const handleContextMenu: MouseEventHandler<HTMLElement> = (evt) => {
|
||||||
|
evt.preventDefault();
|
||||||
|
setMenu(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const optionsVisible = hover || menu;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NavItem
|
||||||
|
variant="Background"
|
||||||
|
radii="400"
|
||||||
|
highlight={unread !== undefined || selected}
|
||||||
|
aria-selected={selected}
|
||||||
|
data-hover={menu}
|
||||||
|
onContextMenu={handleContextMenu}
|
||||||
|
{...hoverProps}
|
||||||
|
{...focusWithinProps}
|
||||||
|
>
|
||||||
|
<NavLink to={linkPath}>
|
||||||
|
<NavItemContent size="T300">
|
||||||
|
<Box as="span" grow="Yes" alignItems="Center" gap="200">
|
||||||
|
<Avatar size="200" radii="400">
|
||||||
|
{direct ? (
|
||||||
|
<RoomAvatar
|
||||||
|
variant="Background"
|
||||||
|
src={getRoomAvatarUrl(mx, room, 96)}
|
||||||
|
alt={room.name}
|
||||||
|
renderInitials={() => <Text size="H6">{nameInitials(room.name)}</Text>}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<RoomIcon
|
||||||
|
style={{ opacity: unread ? config.opacity.P500 : config.opacity.P300 }}
|
||||||
|
filled={selected}
|
||||||
|
size="100"
|
||||||
|
joinRule={room.getJoinRule()}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Avatar>
|
||||||
|
<Box as="span" grow="Yes">
|
||||||
|
<Text priority={unread ? '500' : '300'} as="span" size="Inherit" truncate>
|
||||||
|
{room.name}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
{!optionsVisible && unread && (
|
||||||
|
<UnreadBadgeCenter>
|
||||||
|
<UnreadBadge highlight={unread.highlight > 0} count={unread.total} />
|
||||||
|
</UnreadBadgeCenter>
|
||||||
|
)}
|
||||||
|
{muted && !optionsVisible && <Icon size="50" src={Icons.BellMute} />}
|
||||||
|
</Box>
|
||||||
|
</NavItemContent>
|
||||||
|
</NavLink>
|
||||||
|
{optionsVisible && (
|
||||||
|
<NavItemOptions>
|
||||||
|
<PopOut
|
||||||
|
open={menu}
|
||||||
|
alignOffset={-5}
|
||||||
|
position="Bottom"
|
||||||
|
align="End"
|
||||||
|
content={
|
||||||
|
<FocusTrap
|
||||||
|
focusTrapOptions={{
|
||||||
|
initialFocus: false,
|
||||||
|
returnFocusOnDeactivate: false,
|
||||||
|
onDeactivate: () => setMenu(false),
|
||||||
|
clickOutsideDeactivates: true,
|
||||||
|
isKeyForward: (evt: KeyboardEvent) => evt.key === 'ArrowDown',
|
||||||
|
isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<RoomNavItemMenu
|
||||||
|
room={room}
|
||||||
|
linkPath={linkPath}
|
||||||
|
requestClose={() => setMenu(false)}
|
||||||
|
/>
|
||||||
|
</FocusTrap>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{(anchorRef) => (
|
||||||
|
<IconButton
|
||||||
|
ref={anchorRef}
|
||||||
|
onClick={() => setMenu(true)}
|
||||||
|
aria-pressed={menu}
|
||||||
|
variant="Background"
|
||||||
|
fill="None"
|
||||||
|
size="300"
|
||||||
|
radii="300"
|
||||||
|
>
|
||||||
|
<Icon size="50" src={Icons.VerticalDots} />
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
|
</PopOut>
|
||||||
|
</NavItemOptions>
|
||||||
|
)}
|
||||||
|
</NavItem>
|
||||||
|
);
|
||||||
|
}
|
|
@ -803,7 +803,7 @@ export const Message = as<'div', MessageProps>(
|
||||||
isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp',
|
isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Menu {...props} ref={ref}>
|
<Menu>
|
||||||
{canSendReaction && (
|
{canSendReaction && (
|
||||||
<MessageQuickReactions
|
<MessageQuickReactions
|
||||||
onReaction={(key, shortcode) => {
|
onReaction={(key, shortcode) => {
|
||||||
|
|
|
@ -35,7 +35,7 @@ import {
|
||||||
_SERVER_PATH,
|
_SERVER_PATH,
|
||||||
} from './paths';
|
} from './paths';
|
||||||
import { isAuthenticated } from '../../client/state/auth';
|
import { isAuthenticated } from '../../client/state/auth';
|
||||||
import { getAbsolutePathFromHref, getHomePath, getLoginPath } from './pathUtils';
|
import { getAbsolutePathFromHref, getHomePath, getLoginPath, getOriginBaseUrl } from './pathUtils';
|
||||||
import { ConfigConfigError, ConfigConfigLoading } from './ConfigConfig';
|
import { ConfigConfigError, ConfigConfigLoading } from './ConfigConfig';
|
||||||
import { FeatureCheck } from './FeatureCheck';
|
import { FeatureCheck } from './FeatureCheck';
|
||||||
import { ClientLayout, ClientRoot } from './client';
|
import { ClientLayout, ClientRoot } from './client';
|
||||||
|
@ -59,7 +59,7 @@ const createRouter = (clientConfig: ClientConfig) => {
|
||||||
loader={() => {
|
loader={() => {
|
||||||
if (isAuthenticated()) return redirect(getHomePath());
|
if (isAuthenticated()) return redirect(getHomePath());
|
||||||
|
|
||||||
const afterLoginPath = getAbsolutePathFromHref(window.location.href);
|
const afterLoginPath = getAbsolutePathFromHref(getOriginBaseUrl(), window.location.href);
|
||||||
if (afterLoginPath) setAfterLoginRedirectPath(afterLoginPath);
|
if (afterLoginPath) setAfterLoginRedirectPath(afterLoginPath);
|
||||||
return redirect(getLoginPath());
|
return redirect(getLoginPath());
|
||||||
}}
|
}}
|
||||||
|
@ -73,7 +73,10 @@ const createRouter = (clientConfig: ClientConfig) => {
|
||||||
<Route
|
<Route
|
||||||
loader={() => {
|
loader={() => {
|
||||||
if (!isAuthenticated()) {
|
if (!isAuthenticated()) {
|
||||||
const afterLoginPath = getAbsolutePathFromHref(window.location.href);
|
const afterLoginPath = getAbsolutePathFromHref(
|
||||||
|
getOriginBaseUrl(),
|
||||||
|
window.location.href
|
||||||
|
);
|
||||||
if (afterLoginPath) setAfterLoginRedirectPath(afterLoginPath);
|
if (afterLoginPath) setAfterLoginRedirectPath(afterLoginPath);
|
||||||
return redirect(getLoginPath());
|
return redirect(getLoginPath());
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,21 +16,18 @@ import {
|
||||||
NavItemContent,
|
NavItemContent,
|
||||||
NavLink,
|
NavLink,
|
||||||
} from '../../../components/nav';
|
} from '../../../components/nav';
|
||||||
import { UnreadBadge, UnreadBadgeCenter } from '../../../components/unread-badge';
|
|
||||||
import { RoomAvatar, RoomIcon } from '../../../components/room-avatar';
|
|
||||||
import { getSpaceLobbyPath, getSpaceRoomPath, getSpaceSearchPath } from '../../pathUtils';
|
import { getSpaceLobbyPath, getSpaceRoomPath, getSpaceSearchPath } from '../../pathUtils';
|
||||||
import { getCanonicalAliasOrRoomId } from '../../../utils/matrix';
|
import { getCanonicalAliasOrRoomId } from '../../../utils/matrix';
|
||||||
import { RoomUnreadProvider } from '../../../components/RoomUnreadProvider';
|
|
||||||
import { useSelectedRoom } from '../../../hooks/router/useSelectedRoom';
|
import { useSelectedRoom } from '../../../hooks/router/useSelectedRoom';
|
||||||
import {
|
import {
|
||||||
useSpaceLobbySelected,
|
useSpaceLobbySelected,
|
||||||
useSpaceSearchSelected,
|
useSpaceSearchSelected,
|
||||||
} from '../../../hooks/router/useSelectedSpace';
|
} from '../../../hooks/router/useSelectedSpace';
|
||||||
import { getRoomAvatarUrl } from '../../../utils/room';
|
|
||||||
import { nameInitials } from '../../../utils/common';
|
|
||||||
import { useSpace } from '../../../hooks/useSpace';
|
import { useSpace } from '../../../hooks/useSpace';
|
||||||
import { VirtualTile } from '../../../components/virtualizer';
|
import { VirtualTile } from '../../../components/virtualizer';
|
||||||
import { useSpaceHierarchy } from './useSpaceHierarchy';
|
import { useSpaceHierarchy } from './useSpaceHierarchy';
|
||||||
|
import { RoomNavItem } from '../../../features/room-nav-item/RoomNavItem';
|
||||||
|
import { muteChangesAtom } from '../../../state/room-list/mutedRoomList';
|
||||||
|
|
||||||
export function Space() {
|
export function Space() {
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
|
@ -38,6 +35,8 @@ export function Space() {
|
||||||
const spaceIdOrAlias = getCanonicalAliasOrRoomId(mx, space.roomId);
|
const spaceIdOrAlias = getCanonicalAliasOrRoomId(mx, space.roomId);
|
||||||
const scrollRef = useRef<HTMLDivElement>(null);
|
const scrollRef = useRef<HTMLDivElement>(null);
|
||||||
const mDirects = useAtomValue(mDirectAtom);
|
const mDirects = useAtomValue(mDirectAtom);
|
||||||
|
const muteChanges = useAtomValue(muteChangesAtom);
|
||||||
|
const mutedRooms = muteChanges.added;
|
||||||
|
|
||||||
const hierarchy = useSpaceHierarchy(space.roomId);
|
const hierarchy = useSpaceHierarchy(space.roomId);
|
||||||
|
|
||||||
|
@ -158,54 +157,13 @@ export function Space() {
|
||||||
</NavCategoryHeader>
|
</NavCategoryHeader>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<RoomUnreadProvider roomId={roomId}>
|
<RoomNavItem
|
||||||
{(unread) => (
|
room={room}
|
||||||
<NavItem
|
selected={selected}
|
||||||
variant="Background"
|
direct={direct}
|
||||||
radii="400"
|
linkPath={getToLink(roomId)}
|
||||||
highlight={!!unread || selected}
|
muted={mutedRooms.includes(roomId)}
|
||||||
aria-selected={selected}
|
/>
|
||||||
>
|
|
||||||
<NavLink to={getToLink(roomId)}>
|
|
||||||
<NavItemContent size="T300">
|
|
||||||
<Box as="span" grow="Yes" alignItems="Center" gap="200">
|
|
||||||
<Avatar size="200" radii="400">
|
|
||||||
{direct ? (
|
|
||||||
<RoomAvatar
|
|
||||||
variant="Background"
|
|
||||||
src={getRoomAvatarUrl(mx, room, 96)}
|
|
||||||
alt={room.name}
|
|
||||||
renderInitials={() => (
|
|
||||||
<Text size="H6">{nameInitials(room.name)}</Text>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<RoomIcon
|
|
||||||
filled={selected}
|
|
||||||
size="100"
|
|
||||||
joinRule={room.getJoinRule()}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Avatar>
|
|
||||||
<Box as="span" grow="Yes">
|
|
||||||
<Text as="span" size="Inherit" truncate>
|
|
||||||
{room.name}
|
|
||||||
</Text>
|
|
||||||
</Box>
|
|
||||||
{unread && (
|
|
||||||
<UnreadBadgeCenter>
|
|
||||||
<UnreadBadge
|
|
||||||
highlight={unread.highlight > 0}
|
|
||||||
count={unread.total}
|
|
||||||
/>
|
|
||||||
</UnreadBadgeCenter>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
</NavItemContent>
|
|
||||||
</NavLink>
|
|
||||||
</NavItem>
|
|
||||||
)}
|
|
||||||
</RoomUnreadProvider>
|
|
||||||
</VirtualTile>
|
</VirtualTile>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
|
@ -36,8 +36,15 @@ export const withSearchParam = <T extends Record<string, string>>(
|
||||||
export const encodeSearchParamValueArray = (ids: string[]): string => ids.join(',');
|
export const encodeSearchParamValueArray = (ids: string[]): string => ids.join(',');
|
||||||
export const decodeSearchParamValueArray = (idsParam: string): string[] => idsParam.split(',');
|
export const decodeSearchParamValueArray = (idsParam: string): string[] => idsParam.split(',');
|
||||||
|
|
||||||
export const getAbsolutePathFromHref = (href: string): string | undefined => {
|
export const getOriginBaseUrl = (): string => {
|
||||||
const baseUrl = `${trimTrailingSlash(window.location.origin)}${import.meta.env.BASE_URL}`;
|
const baseUrl = `${trimTrailingSlash(window.location.origin)}${import.meta.env.BASE_URL}`;
|
||||||
|
return baseUrl;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const withOriginBaseUrl = (baseUrl: string, path: string): string =>
|
||||||
|
`${trimTrailingSlash(baseUrl)}${path}`;
|
||||||
|
|
||||||
|
export const getAbsolutePathFromHref = (baseUrl: string, href: string): string | undefined => {
|
||||||
const [, path] = href.split(trimTrailingSlash(baseUrl));
|
const [, path] = href.split(trimTrailingSlash(baseUrl));
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
|
@ -121,7 +128,7 @@ export const getExplorePath = (): string => EXPLORE_PATH;
|
||||||
export const getExploreFeaturedPath = (): string => EXPLORE_FEATURED_PATH;
|
export const getExploreFeaturedPath = (): string => EXPLORE_FEATURED_PATH;
|
||||||
export const getExploreServerPath = (server: string): string => {
|
export const getExploreServerPath = (server: string): string => {
|
||||||
const params = {
|
const params = {
|
||||||
server,
|
server: encodeURIComponent(server),
|
||||||
};
|
};
|
||||||
return generatePath(EXPLORE_SERVER_PATH, params);
|
return generatePath(EXPLORE_SERVER_PATH, params);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue