mirror of
https://github.com/Sonny93/my-links.git
synced 2025-12-10 07:25:35 +00:00
feat: add basic admin dashboard
This commit is contained in:
@@ -2,6 +2,7 @@ import type Link from '#models/link';
|
||||
import styled from '@emotion/styled';
|
||||
import LinkItem from '~/components/dashboard/link/link_item';
|
||||
import { NoLink } from '~/components/dashboard/link/no_item';
|
||||
import { sortByCreationDate } from '~/lib/array';
|
||||
|
||||
const LinkListStyle = styled.ul({
|
||||
height: '100%',
|
||||
@@ -23,11 +24,9 @@ export default function LinkList({ links }: { links: Link[] }) {
|
||||
|
||||
return (
|
||||
<LinkListStyle>
|
||||
{links
|
||||
.sort((a, b) => (a.created_at > b.created_at ? 1 : -1))
|
||||
.map((link) => (
|
||||
<LinkItem link={link} key={link.id} showUserControls />
|
||||
))}
|
||||
{sortByCreationDate(links).map((link) => (
|
||||
<LinkItem link={link} key={link.id} showUserControls />
|
||||
))}
|
||||
</LinkListStyle>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { Item, ItemLink } from '~/components/dashboard/side_nav/nav_item';
|
||||
import UserCard from '~/components/dashboard/side_nav/user_card';
|
||||
import ModalSettings from '~/components/settings/modal';
|
||||
import useActiveCollection from '~/hooks/use_active_collection';
|
||||
import useUser from '~/hooks/use_user';
|
||||
import { rgba } from '~/lib/color';
|
||||
import { appendCollectionId } from '~/lib/navigation';
|
||||
|
||||
@@ -19,7 +20,7 @@ const SideMenu = styled.nav({
|
||||
flexDirection: 'column',
|
||||
});
|
||||
|
||||
const AdminButton = styled(Item)(({ theme }) => ({
|
||||
const AdminButton = styled(ItemLink)(({ theme }) => ({
|
||||
color: theme.colors.lightRed,
|
||||
'&:hover': {
|
||||
backgroundColor: `${rgba(theme.colors.lightRed, 0.1)}!important`,
|
||||
@@ -43,15 +44,18 @@ const AddButton = styled(ItemLink)(({ theme }) => ({
|
||||
const SearchButton = AddButton.withComponent(Item);
|
||||
|
||||
export default function SideNavigation() {
|
||||
const { user } = useUser();
|
||||
const { t } = useTranslation('common');
|
||||
const { activeCollection } = useActiveCollection();
|
||||
return (
|
||||
<SideMenu>
|
||||
<div css={{ paddingInline: '10px' }}>
|
||||
<UserCard />
|
||||
<AdminButton>
|
||||
<IoShieldHalfSharp /> {t('admin')}
|
||||
</AdminButton>
|
||||
{user!.isAdmin && (
|
||||
<AdminButton href={route('admin.dashboard').url}>
|
||||
<IoShieldHalfSharp /> {t('admin')}
|
||||
</AdminButton>
|
||||
)}
|
||||
<ModalSettings openItem={SettingsButton} />
|
||||
<SearchModal openItem={SearchButton} />
|
||||
<AddButton
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import dayjs from 'dayjs';
|
||||
import { ChangeEvent } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { LS_LANG_KEY } from '~/constants';
|
||||
@@ -9,6 +10,7 @@ export default function LangSelector() {
|
||||
const onToggleLanguageClick = ({
|
||||
target,
|
||||
}: ChangeEvent<HTMLSelectElement>) => {
|
||||
dayjs.locale(target.value);
|
||||
i18n.changeLanguage(target.value);
|
||||
localStorage.setItem(LS_LANG_KEY, target.value);
|
||||
};
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
import dayjs from 'dayjs';
|
||||
import { ReactNode } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import ContextThemeProvider from '~/components/layouts/_theme_layout';
|
||||
import DarkThemeContextProvider from '~/contexts/dark_theme_context';
|
||||
|
||||
const BaseLayout = ({ children }: { children: ReactNode }) => (
|
||||
<DarkThemeContextProvider>
|
||||
<ContextThemeProvider>{children}</ContextThemeProvider>
|
||||
</DarkThemeContextProvider>
|
||||
);
|
||||
|
||||
export default BaseLayout;
|
||||
export default function BaseLayout({ children }: { children: ReactNode }) {
|
||||
const { i18n } = useTranslation();
|
||||
dayjs.locale(i18n.language);
|
||||
return (
|
||||
<DarkThemeContextProvider>
|
||||
<ContextThemeProvider>{children}</ContextThemeProvider>
|
||||
</DarkThemeContextProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -109,5 +109,35 @@ function GlobalStyles() {
|
||||
},
|
||||
});
|
||||
|
||||
return <Global styles={[cssReset, documentStyle, scrollbarStyle]} />;
|
||||
const tableStyle = css({
|
||||
table: {
|
||||
height: 'auto',
|
||||
width: '100%',
|
||||
borderCollapse: 'collapse',
|
||||
borderRadius: localTheme.border.radius,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
|
||||
th: {
|
||||
textAlign: 'center',
|
||||
fontWeight: 400,
|
||||
backgroundColor: localTheme.colors.secondary,
|
||||
},
|
||||
|
||||
'td, th': {
|
||||
padding: '0.45em',
|
||||
},
|
||||
|
||||
'th, td': {
|
||||
whiteSpace: 'nowrap',
|
||||
},
|
||||
|
||||
'tr:nth-of-type(even)': {
|
||||
backgroundColor: localTheme.colors.secondary,
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<Global styles={[cssReset, documentStyle, scrollbarStyle, tableStyle]} />
|
||||
);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,10 @@ const NavList = styled(UnstyledList)<NavbarListDirection>(
|
||||
})
|
||||
);
|
||||
|
||||
const AdminLink = styled(Link)(({ theme }) => ({
|
||||
color: theme.colors.lightRed,
|
||||
}));
|
||||
|
||||
const UserCard = styled.div({
|
||||
padding: '0.25em 0.5em',
|
||||
display: 'flex',
|
||||
@@ -68,6 +72,13 @@ export default function Navbar() {
|
||||
</li>
|
||||
{isAuthenticated && !!user ? (
|
||||
<>
|
||||
{user.isAdmin && (
|
||||
<li>
|
||||
<AdminLink href={route('admin.dashboard').url}>
|
||||
{t('admin')}
|
||||
</AdminLink>
|
||||
</li>
|
||||
)}
|
||||
<li>
|
||||
<Link href={route('dashboard').url}>Dashboard</Link>
|
||||
</li>
|
||||
|
||||
Reference in New Issue
Block a user