diff --git a/src/app/(main)/settings/teams/TeamsTable.js b/src/app/(main)/settings/teams/TeamsTable.js index 07199167..1f7f1da4 100644 --- a/src/app/(main)/settings/teams/TeamsTable.js +++ b/src/app/(main)/settings/teams/TeamsTable.js @@ -3,16 +3,17 @@ import useMessages from 'components/hooks/useMessages'; import useUser from 'components/hooks/useUser'; import { ROLES } from 'lib/constants'; import Link from 'next/link'; -import { Button, GridColumn, GridTable, Icon, Icons, Text } from 'react-basics'; +import { Button, GridColumn, GridTable, Icon, Icons, Text, useBreakpoint } from 'react-basics'; import TeamDeleteButton from './TeamDeleteButton'; import TeamLeaveButton from './TeamLeaveButton'; export function TeamsTable({ data = [] }) { const { formatMessage, labels } = useMessages(); const { user } = useUser(); + const breakpoint = useBreakpoint(); return ( - + {row => row.teamUser.find(({ role }) => role === ROLES.teamOwner)?.user?.username} diff --git a/src/app/(main)/settings/users/UsersTable.js b/src/app/(main)/settings/users/UsersTable.js index 6712e4a5..a0b5aba1 100644 --- a/src/app/(main)/settings/users/UsersTable.js +++ b/src/app/(main)/settings/users/UsersTable.js @@ -1,4 +1,4 @@ -import { Button, Text, Icon, Icons, GridTable, GridColumn } from 'react-basics'; +import { Button, Text, Icon, Icons, GridTable, GridColumn, useBreakpoint } from 'react-basics'; import { formatDistance } from 'date-fns'; import Link from 'next/link'; import { ROLES } from 'lib/constants'; @@ -9,22 +9,19 @@ import UserDeleteButton from './UserDeleteButton'; export function UsersTable({ data = [] }) { const { formatMessage, labels } = useMessages(); const { dateLocale } = useLocale(); + const breakpoint = useBreakpoint(); return ( - - - + + + {row => formatMessage( labels[Object.keys(ROLES).find(key => ROLES[key] === row.role)] || labels.unknown, ) } - + {row => formatDistance(new Date(row.createdAt), new Date(), { addSuffix: true, diff --git a/src/app/(main)/settings/websites/WebsitesDataTable.tsx b/src/app/(main)/settings/websites/WebsitesDataTable.tsx index cfdf147a..441ae56d 100644 --- a/src/app/(main)/settings/websites/WebsitesDataTable.tsx +++ b/src/app/(main)/settings/websites/WebsitesDataTable.tsx @@ -6,7 +6,6 @@ import useApi from 'components/hooks/useApi'; import DataTable from 'components/common/DataTable'; import useFilterQuery from 'components/hooks/useFilterQuery'; import useCache from 'store/cache'; -import { useBreakpoint } from 'react-basics'; export interface WebsitesDataTableProps { allowEdit?: boolean; @@ -25,7 +24,7 @@ function useWebsites({ includeTeams, onlyTeams }) { return useFilterQuery( ['websites', { includeTeams, onlyTeams, modified }], - params => { + (params: any) => { return get(`/users/${user?.id}/websites`, { includeTeams, onlyTeams, @@ -46,7 +45,6 @@ export function WebsitesDataTable({ children, }: WebsitesDataTableProps) { const queryResult = useWebsites({ includeTeams, onlyTeams }); - const breakpoint = useBreakpoint(); return ( @@ -57,7 +55,6 @@ export function WebsitesDataTable({ showActions={showActions} allowEdit={allowEdit} allowView={allowView} - cardMode={['xs', 'sm', 'md'].includes(breakpoint)} > {children} diff --git a/src/app/(main)/settings/websites/WebsitesTable.js b/src/app/(main)/settings/websites/WebsitesTable.js index ed663f6f..eef3f7d4 100644 --- a/src/app/(main)/settings/websites/WebsitesTable.js +++ b/src/app/(main)/settings/websites/WebsitesTable.js @@ -1,5 +1,5 @@ import Link from 'next/link'; -import { Button, Text, Icon, Icons, GridTable, GridColumn } from 'react-basics'; +import { Button, Text, Icon, Icons, GridTable, GridColumn, useBreakpoint } from 'react-basics'; import useMessages from 'components/hooks/useMessages'; import useUser from 'components/hooks/useUser'; @@ -9,14 +9,14 @@ export function WebsitesTable({ showActions, allowEdit, allowView, - cardMode, children, }) { const { formatMessage, labels } = useMessages(); const { user } = useUser(); + const breakpoint = useBreakpoint(); return ( - + {showTeam && ( diff --git a/src/app/share/[...id]/Footer.js b/src/app/share/[...id]/Footer.js index 3a07c12a..84d4162f 100644 --- a/src/app/share/[...id]/Footer.js +++ b/src/app/share/[...id]/Footer.js @@ -1,3 +1,4 @@ +'use client'; import { CURRENT_VERSION, HOMEPAGE_URL } from 'lib/constants'; import styles from './Footer.module.css'; diff --git a/src/app/share/[...id]/Footer.module.css b/src/app/share/[...id]/Footer.module.css index 348c92d8..5dc2d584 100644 --- a/src/app/share/[...id]/Footer.module.css +++ b/src/app/share/[...id]/Footer.module.css @@ -1,10 +1,10 @@ .footer { display: flex; flex-direction: row; + align-items: center; justify-content: flex-end; font-size: var(--font-size-sm); - line-height: 30px; - margin: 40px 0; + height: 100px; } .footer a { diff --git a/src/app/share/[...id]/Header.js b/src/app/share/[...id]/Header.js index ab9078ec..41e93f52 100644 --- a/src/app/share/[...id]/Header.js +++ b/src/app/share/[...id]/Header.js @@ -1,3 +1,4 @@ +'use client'; import { Icon, Text } from 'react-basics'; import Link from 'next/link'; import LanguageButton from 'components/input/LanguageButton'; diff --git a/src/app/share/[...id]/Header.module.css b/src/app/share/[...id]/Header.module.css index 26f30552..d353d79a 100644 --- a/src/app/share/[...id]/Header.module.css +++ b/src/app/share/[...id]/Header.module.css @@ -2,6 +2,7 @@ display: flex; flex-direction: row; align-items: center; + justify-content: space-between; width: 100%; height: 100px; } @@ -38,10 +39,3 @@ min-width: 100%; } } - -@media only screen and (max-width: 768px) { - .buttons, - .links { - display: none; - } -} diff --git a/src/app/share/[...id]/Share.js b/src/app/share/[...id]/Share.js index 618f66b7..99ba6407 100644 --- a/src/app/share/[...id]/Share.js +++ b/src/app/share/[...id]/Share.js @@ -1,13 +1,25 @@ 'use client'; -import WebsiteDetails from '../../(main)/websites/[id]/WebsiteDetails'; +import WebsiteDetails from 'app/(main)/websites/[id]/WebsiteDetails'; import useShareToken from 'components/hooks/useShareToken'; +import styles from './Share.module.css'; +import Page from 'components/layout/Page'; +import Header from './Header'; +import Footer from './Footer'; -export default function ({ shareId }) { - const shareToken = useShareToken(shareId); +export default function Share({ shareId }) { + const { shareToken, isLoading } = useShareToken(shareId); - if (!shareToken) { + if (isLoading || !shareToken) { return null; } - return ; + return ( +
+ +
+ +
+ +
+ ); } diff --git a/src/app/share/[...id]/Share.module.css b/src/app/share/[...id]/Share.module.css new file mode 100644 index 00000000..d985435c --- /dev/null +++ b/src/app/share/[...id]/Share.module.css @@ -0,0 +1,4 @@ +.container { + flex: 1; + min-height: calc(100vh - 200px); +} diff --git a/src/app/share/[...id]/page.tsx b/src/app/share/[...id]/page.tsx index b674d56a..ca154165 100644 --- a/src/app/share/[...id]/page.tsx +++ b/src/app/share/[...id]/page.tsx @@ -1,5 +1,5 @@ import Share from './Share'; export default function ({ params: { id } }) { - return ; + return ; } diff --git a/src/components/common/DataTable.module.css b/src/components/common/DataTable.module.css index c7cab642..e738c895 100644 --- a/src/components/common/DataTable.module.css +++ b/src/components/common/DataTable.module.css @@ -30,6 +30,9 @@ min-height: 70px; align-items: center; min-width: min-content; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } .body > div > div > div { diff --git a/src/components/hooks/useShareToken.js b/src/components/hooks/useShareToken.js index 3d6b9698..5062c73e 100644 --- a/src/components/hooks/useShareToken.js +++ b/src/components/hooks/useShareToken.js @@ -1,4 +1,3 @@ -import { useEffect } from 'react'; import useStore, { setShareToken } from 'store/app'; import useApi from './useApi'; @@ -6,23 +5,16 @@ const selector = state => state.shareToken; export function useShareToken(shareId) { const shareToken = useStore(selector); - const { get } = useApi(); + const { get, useQuery } = useApi(); + const { isLoading, error } = useQuery(['share', shareId], async () => { + const data = await get(`/share/${shareId}`); - async function loadToken(id) { - const data = await get(`/share/${id}`); + setShareToken(data); - if (data) { - setShareToken(data); - } - } + return data; + }); - useEffect(() => { - if (shareId) { - loadToken(shareId); - } - }, [shareId]); - - return shareToken; + return { shareToken, isLoading, error }; } export default useShareToken; diff --git a/src/components/input/LanguageButton.module.css b/src/components/input/LanguageButton.module.css index 3d4c0c56..cc5d649a 100644 --- a/src/components/input/LanguageButton.module.css +++ b/src/components/input/LanguageButton.module.css @@ -1,7 +1,6 @@ .menu { - display: flex; - flex-flow: row wrap; - min-width: 640px; + display: grid; + grid-template-columns: repeat(3, 1fr); padding: 10px; background: var(--base50); z-index: var(--z-index-popup); @@ -14,7 +13,7 @@ display: flex; align-items: center; justify-content: space-between; - min-width: calc(100% / 3); + min-width: 200px; border-radius: 5px; padding: 5px 10px; } @@ -32,3 +31,15 @@ .icon { color: var(--primary400); } + +@media screen and (max-width: 992px) { + .menu { + grid-template-columns: repeat(2, 1fr); + } +} + +@media screen and (max-width: 768px) { + .menu { + transform: translateX(40px); + } +} diff --git a/src/components/layout/Page.module.css b/src/components/layout/Page.module.css index b0387196..73f21979 100644 --- a/src/components/layout/Page.module.css +++ b/src/components/layout/Page.module.css @@ -3,6 +3,7 @@ display: flex; flex-direction: column; position: relative; + width: 100%; max-width: 1320px; min-height: calc(100vh - 60px); margin: 0 auto; diff --git a/src/pages/api/auth/login.ts b/src/pages/api/auth/login.ts index f3d3d4fd..0946ae75 100644 --- a/src/pages/api/auth/login.ts +++ b/src/pages/api/auth/login.ts @@ -15,6 +15,7 @@ import { } from 'next-basics'; import { getUserByUsername } from 'queries'; import * as yup from 'yup'; +import { ROLES } from 'lib/constants'; const log = debug('umami:auth'); @@ -62,7 +63,7 @@ export default async ( return ok(res, { token, - user: { id, username, role, createdAt }, + user: { id, username, role, createdAt, isAdmin: role === ROLES.admin }, }); } diff --git a/src/pages/api/users/index.ts b/src/pages/api/users/index.ts index 5eb26ea4..b6d81271 100644 --- a/src/pages/api/users/index.ts +++ b/src/pages/api/users/index.ts @@ -7,6 +7,7 @@ import { pageInfo } from 'lib/schema'; import { NextApiResponse } from 'next'; import { badRequest, hashPassword, methodNotAllowed, ok, unauthorized } from 'next-basics'; import { createUser, getUserByUsername, getUsers } from 'queries'; +import * as yup from 'yup'; export interface UsersRequestQuery extends SearchFilter {} export interface UsersRequestBody { @@ -16,7 +17,6 @@ export interface UsersRequestBody { role: Role; } -import * as yup from 'yup'; const schema = { GET: yup.object().shape({ ...pageInfo,