Header.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. import React from 'react';
  2. import { IconBrandGithub, IconHeart, IconLogout, IconMoon, IconSun } from '@tabler/icons';
  3. import Image from 'next/image';
  4. import clsx from 'clsx';
  5. import Link from 'next/link';
  6. import { useRouter } from 'next/router';
  7. import { getUrl } from '../../../core/helpers/url-helpers';
  8. import { useUIStore } from '../../../state/uiStore';
  9. import { NavBar } from '../NavBar';
  10. import { trpc } from '../../../utils/trpc';
  11. interface IProps {
  12. isUpdateAvailable?: boolean;
  13. }
  14. export const Header: React.FC<IProps> = ({ isUpdateAvailable }) => {
  15. const router = useRouter();
  16. const { setDarkMode } = useUIStore();
  17. const utils = trpc.useContext();
  18. const logout = trpc.auth.logout.useMutation({
  19. onSuccess: () => {
  20. localStorage.removeItem('token');
  21. utils.auth.me.invalidate();
  22. router.push('/login');
  23. },
  24. });
  25. return (
  26. <header className="navbar navbar-expand-md navbar-dark navbar-overlap d-print-none">
  27. <div className="container-xl">
  28. <button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbar-menu">
  29. <span className="navbar-toggler-icon" />
  30. </button>
  31. <Link href="/" passHref>
  32. <h1 className="navbar-brand d-none-navbar-horizontal pe-0 pe-md-3">
  33. <Image
  34. priority
  35. alt="Tipi logo"
  36. className={clsx('navbar-brand-image me-3')}
  37. width={100}
  38. height={100}
  39. src={getUrl('tipi.png')}
  40. style={{
  41. width: '30px',
  42. maxWidth: '30px',
  43. height: 'auto',
  44. }}
  45. />
  46. Tipi
  47. </h1>
  48. </Link>
  49. <div className="navbar-nav flex-row order-md-last">
  50. <div className="nav-item d-none d-lg-flex me-3">
  51. <div className="btn-list">
  52. <a href="https://github.com/meienberger/runtipi" target="_blank" rel="noreferrer" className="btn btn-dark">
  53. <IconBrandGithub data-testid="icon-github" className="me-1 icon" size={24} />
  54. Source code
  55. </a>
  56. <a href="https://github.com/meienberger/runtipi?sponsor=1" target="_blank" rel="noreferrer" className="btn btn-dark">
  57. <IconHeart className="me-1 icon text-pink" size={24} />
  58. Sponsor
  59. </a>
  60. </div>
  61. </div>
  62. <div className="d-flex">
  63. <div onClick={() => setDarkMode(true)} role="button" aria-hidden="true" className="nav-link px-0 hide-theme-dark cursor-pointer" data-tip="Dark mode">
  64. <IconMoon data-testid="icon-moon" size={24} />
  65. </div>
  66. <div onClick={() => setDarkMode(false)} aria-hidden="true" className="nav-link px-0 hide-theme-light cursor-pointer" data-tip="Light mode">
  67. <IconSun data-testid="icon-sun" size={24} />
  68. </div>
  69. <div onClick={() => logout.mutate()} tabIndex={0} onKeyPress={() => logout.mutate()} role="button" className="nav-link px-0 cursor-pointer" data-tip="Log out">
  70. <IconLogout size={24} />
  71. </div>
  72. </div>
  73. </div>
  74. <NavBar isUpdateAvailable={isUpdateAvailable} />
  75. </div>
  76. </header>
  77. );
  78. };