1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-11-24 23:01:05 +03:00

frontend: make the navbar better and push it under the user avatar/name

This commit is contained in:
Quentin Gliech
2023-08-08 12:31:08 +02:00
parent 4556332efb
commit c2268cc164
9 changed files with 115 additions and 38 deletions

View File

@@ -19,13 +19,19 @@
}
.footer {
margin-top: var(--cpd-space-6x);
padding: var(--cpd-space-6x) 0;
border-top: 1px solid var(--cpd-color-border-interactive-secondary);
text-align: center;
}
.separator {
border: 0;
height: 1px;
background: var(--cpd-color-border-interactive-secondary);
.footer-links {
margin: var(--cpd-space-4x) 0;
}
& > ul {
display: flex;
flex-direction: row;
justify-content: center;
gap: var(--cpd-space-2x);
}
}

View File

@@ -12,26 +12,42 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Link } from "@vector-im/compound-web";
import { useAtomValue } from "jotai";
import { currentUserIdAtom } from "../atoms";
import { isErr, unwrapErr, unwrapOk } from "../result";
import GraphQLError from "./GraphQLError";
import styles from "./Layout.module.css";
import NavBar from "./NavBar";
import NavItem, { ExternalLink } from "./NavItem";
const Separator: React.FC = () => <hr className={styles.separator} />;
import NavItem from "./NavItem";
import NotLoggedIn from "./NotLoggedIn";
import UserGreeting from "./UserGreeting";
const Layout: React.FC<{ children?: React.ReactNode }> = ({ children }) => {
const result = useAtomValue(currentUserIdAtom);
if (isErr(result)) return <GraphQLError error={unwrapErr(result)} />;
const userId = unwrapOk(result);
if (userId === null)
return (
<div className={styles.container}>
<NotLoggedIn />
</div>
);
return (
<div className={styles.container}>
<UserGreeting userId={userId} />
<NavBar>
<NavItem route={{ type: "home" }}>Sessions</NavItem>
<NavItem route={{ type: "account" }}>Emails</NavItem>
</NavBar>
<Separator />
<main>{children}</main>
<Separator />
<footer className={styles.footer}>
<a href="https://matrix.org" target="_blank" rel="noreferrer noopener">
<img
@@ -43,17 +59,15 @@ const Layout: React.FC<{ children?: React.ReactNode }> = ({ children }) => {
/>
</a>
<NavBar>
<ExternalLink href="https://matrix.org/legal/copyright-notice">
Info
</ExternalLink>
<ExternalLink href="https://matrix.org/legal/privacy-notice">
Privacy
</ExternalLink>
<ExternalLink href="https://matrix.org/legal/terms-and-conditions">
<nav className={styles.footerLinks}>
<ul>
<Link href="https://matrix.org/legal/copyright-notice">Info</Link>
<Link href="https://matrix.org/legal/privacy-notice">Privacy</Link>
<Link href="https://matrix.org/legal/terms-and-conditions">
Terms & Conditions
</ExternalLink>
</NavBar>
</Link>
</ul>
</nav>
</footer>
</div>
);

View File

@@ -13,9 +13,16 @@
* limitations under the License.
*/
.nav-bar {
border-bottom: var(--cpd-border-width-1) solid var(--cpd-color-gray-400);
margin: var(--cpd-space-6x) 0;
padding: 0 var(--cpd-space-10x);
}
.nav-bar-items {
display: flex;
flex-direction: row;
justify-content: center;
gap: var(--cpd-space-4x);
justify-content: flex-start;
align-items: center;
gap: var(--cpd-space-3x);
}

View File

@@ -15,7 +15,7 @@
import styles from "./NavBar.module.css";
const NavBar: React.FC<React.PropsWithChildren<{}>> = ({ children }) => (
<nav>
<nav className={styles.navBar}>
<ul className={styles.navBarItems}>{children}</ul>
</nav>
);

View File

@@ -13,11 +13,41 @@
* limitations under the License.
*/
.nav-tab {
padding: var(--cpd-space-4x) 0;
position: relative;
}
/* Underline effect */
.nav-tab::before {
content: "";
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 0;
border-radius: var(--cpd-radius-pill-effect) var(--cpd-radius-pill-effect) 0 0;
background-color: var(--cpd-color-bg-action-primary-rest);
transition: height 0.1s ease-in-out;
}
.nav-tab[data-current]::before {
/* This is not exactly right: designs says 3px, but there are no variables for that */
height: var(--cpd-border-width-4);
}
.nav-item {
padding: var(--cpd-space-1x) var(--cpd-space-2x);
color: var(--cpd-color-text-secondary);
line-height: var(--cpd-space-6x);
border-radius: var(--cpd-radius-pill-effect);
border: transparent var(--cpd-border-width-2) solid;
}
.nav-item.external-link {
text-decoration: underline;
color: var(--cpd-color-text-primary);
}
.nav-item:hover {
@@ -25,6 +55,16 @@
background-color: var(--cpd-color-bg-subtle-secondary);
}
.nav-item:active {
color: var(--cpd-color-text-primary);
background-color: var(--cpd-color-bg-subtle-primary);
}
.nav-item:focus {
outline: none;
border-color: var(--cpd-color-border-focused);
}
.nav-item[aria-current="page"] {
color: var(--cpd-color-text-primary);
}

View File

@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Link as CpdLink } from "@vector-im/compound-web";
import classNames from "classnames";
import { useAtomValue } from "jotai";
import { Link, Route, routeAtom } from "../../Router";
@@ -24,12 +24,13 @@ const NavItem: React.FC<React.PropsWithChildren<{ route: Route }>> = ({
children,
}) => {
const currentRoute = useAtomValue(routeAtom);
const active = currentRoute.type === route.type;
return (
<li>
<li className={styles.navTab} data-current={active ? true : undefined}>
<Link
className={styles.navItem}
route={route}
aria-current={currentRoute.type === route.type ? "page" : undefined}
aria-current={active ? "page" : undefined}
>
{children}
</Link>
@@ -40,8 +41,14 @@ const NavItem: React.FC<React.PropsWithChildren<{ route: Route }>> = ({
export const ExternalLink: React.FC<
React.PropsWithChildren<{ href: string }>
> = ({ href, children }) => (
<li>
<CpdLink href={href}>{children}</CpdLink>
<li className={styles.navTab}>
<a
rel="noreferrer noopener"
className={classNames(styles.navItem, styles.externalLink)}
href={href}
>
{children}
</a>
</li>
);

View File

@@ -1,7 +1,10 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`NavItem > render an active <NavItem /> 1`] = `
<li>
<li
className="_navTab_8603fc"
data-current={true}
>
<a
aria-current="page"
className="_navItem_8603fc"
@@ -14,7 +17,9 @@ exports[`NavItem > render an active <NavItem /> 1`] = `
`;
exports[`NavItem > render an inactive <NavItem /> 1`] = `
<li>
<li
className="_navTab_8603fc"
>
<a
className="_navItem_8603fc"
href=""
@@ -26,7 +31,9 @@ exports[`NavItem > render an inactive <NavItem /> 1`] = `
`;
exports[`NavItem > renders a different route 1`] = `
<li>
<li
className="_navTab_8603fc"
>
<a
className="_navItem_8603fc"
href="account"

View File

@@ -18,13 +18,11 @@ import { currentUserIdAtom } from "../atoms";
import GraphQLError from "../components/GraphQLError";
import NotLoggedIn from "../components/NotLoggedIn";
import UserEmailList from "../components/UserEmailList";
import UserGreeting from "../components/UserGreeting";
import { isErr, unwrapErr, unwrapOk } from "../result";
const UserAccount: React.FC<{ id: string }> = ({ id }) => {
return (
<div className="grid grid-cols-1 gap-4">
<UserGreeting userId={id} />
<UserEmailList userId={id} />
</div>
);

View File

@@ -20,7 +20,6 @@ import CompatSessionList from "../components/CompatSessionList";
import GraphQLError from "../components/GraphQLError";
import NotLoggedIn from "../components/NotLoggedIn";
import OAuth2SessionList from "../components/OAuth2SessionList";
import UserGreeting from "../components/UserGreeting";
import { isErr, unwrapErr, unwrapOk } from "../result";
const Home: React.FC = () => {
@@ -32,7 +31,6 @@ const Home: React.FC = () => {
return (
<>
<UserGreeting userId={currentUserId} />
<div className="mt-4 grid gap-8">
<OAuth2SessionList userId={currentUserId} />
<CompatSessionList userId={currentUserId} />