Compare commits
2 Commits
eaef7f304c
...
945bd5d357
Author | SHA1 | Date | |
---|---|---|---|
945bd5d357 | |||
daba03c2e8 |
@ -18,6 +18,7 @@
|
|||||||
"@mui/material-nextjs": "^6.3.1",
|
"@mui/material-nextjs": "^6.3.1",
|
||||||
"@mui/x-charts": "^7.23.2",
|
"@mui/x-charts": "^7.23.2",
|
||||||
"@tailwindcss/typography": "^0.5.16",
|
"@tailwindcss/typography": "^0.5.16",
|
||||||
|
"@toolpad/core": "^0.11.0",
|
||||||
"@vercel/speed-insights": "^1.1.0",
|
"@vercel/speed-insights": "^1.1.0",
|
||||||
"animate.css": "^4.1.1",
|
"animate.css": "^4.1.1",
|
||||||
"axios": "^1.7.9",
|
"axios": "^1.7.9",
|
||||||
@ -51,6 +52,8 @@
|
|||||||
"@eslint/eslintrc": "^3.2.0"
|
"@eslint/eslintrc": "^3.2.0"
|
||||||
},
|
},
|
||||||
"trustedDependencies": [
|
"trustedDependencies": [
|
||||||
"@vercel/speed-insights"
|
"@vercel/speed-insights",
|
||||||
|
"esbuild",
|
||||||
|
"sharp"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ export function CapAppBar() {
|
|||||||
<CapDrawer width={drawerWidth} open={open} onClose={() => setOpen(false)} />
|
<CapDrawer width={drawerWidth} open={open} onClose={() => setOpen(false)} />
|
||||||
|
|
||||||
<AppBarScroll elevation={0}>
|
<AppBarScroll elevation={0}>
|
||||||
<AppBar position="sticky" elevation={0} color="transparent" className="backdrop-blur-md">
|
<AppBar position="sticky" elevation={0} color="transparent" className="backdrop-blur-md z-10">
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<IconButton
|
<IconButton
|
||||||
size="large"
|
size="large"
|
||||||
|
@ -16,10 +16,11 @@ import Image from 'next/image'
|
|||||||
|
|
||||||
import ExploreIcon from '@mui/icons-material/Explore'
|
import ExploreIcon from '@mui/icons-material/Explore'
|
||||||
import PhotoLibraryIcon from '@mui/icons-material/PhotoLibrary'
|
import PhotoLibraryIcon from '@mui/icons-material/PhotoLibrary'
|
||||||
|
import AppsIcon from '@mui/icons-material/Apps'
|
||||||
import NextLink from 'next/link'
|
import NextLink from 'next/link'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
|
|
||||||
interface NavLink {
|
export interface NavLink {
|
||||||
title: string
|
title: string
|
||||||
icon?: JSX.Element
|
icon?: JSX.Element
|
||||||
href: string
|
href: string
|
||||||
@ -39,6 +40,11 @@ export function CapDrawer({ width, open, onClose }: { width: number; open: boole
|
|||||||
icon: <PhotoLibraryIcon />,
|
icon: <PhotoLibraryIcon />,
|
||||||
href: '/attachments',
|
href: '/attachments',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'Matrix',
|
||||||
|
icon: <AppsIcon />,
|
||||||
|
href: '/matrix',
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const additionalLinks: NavLink[] = [
|
const additionalLinks: NavLink[] = [
|
||||||
@ -46,6 +52,10 @@ export function CapDrawer({ width, open, onClose }: { width: number; open: boole
|
|||||||
title: 'Terms & Conditions',
|
title: 'Terms & Conditions',
|
||||||
href: '/terms',
|
href: '/terms',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'SN Console',
|
||||||
|
href: '/console',
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -87,7 +97,7 @@ export function CapDrawer({ width, open, onClose }: { width: number; open: boole
|
|||||||
))}
|
))}
|
||||||
</List>
|
</List>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Box sx={{ display: 'flex', flexWrap: 'wrap', px: 2, py: 1.5 }}>
|
<Box sx={{ display: 'flex', flexWrap: 'wrap', px: 2, py: 1.5, gap: 1 }}>
|
||||||
{additionalLinks.map((l) => (
|
{additionalLinks.map((l) => (
|
||||||
<NextLink passHref href={l.href} key={l.href}>
|
<NextLink passHref href={l.href} key={l.href}>
|
||||||
<Link variant="body2" color={'textSecondary'} fontSize={13}>
|
<Link variant="body2" color={'textSecondary'} fontSize={13}>
|
||||||
|
63
src/components/layouts/ConsoleLayout.tsx
Normal file
63
src/components/layouts/ConsoleLayout.tsx
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import { checkAuthenticatedClient, redirectToLogin } from '@/services/auth'
|
||||||
|
import { JSX, useEffect } from 'react'
|
||||||
|
import { DashboardLayout, Navigation } from '@toolpad/core'
|
||||||
|
import { Box, Stack, Typography } from '@mui/material'
|
||||||
|
import NextLink from 'next/link'
|
||||||
|
|
||||||
|
import HomeIcon from '@mui/icons-material/Home'
|
||||||
|
import AppsIcon from '@mui/icons-material/Apps'
|
||||||
|
|
||||||
|
export function ConsoleLayout({ children }: { children: JSX.Element }) {
|
||||||
|
useEffect(() => {
|
||||||
|
if (!checkAuthenticatedClient()) redirectToLogin()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const navigation: Navigation = [
|
||||||
|
{
|
||||||
|
segment: '',
|
||||||
|
title: 'Home',
|
||||||
|
icon: <HomeIcon />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
segment: 'console/matrix',
|
||||||
|
title: 'Matrix',
|
||||||
|
icon: <AppsIcon />,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DashboardLayout
|
||||||
|
navigation={navigation}
|
||||||
|
branding={{
|
||||||
|
homeUrl: '/console',
|
||||||
|
}}
|
||||||
|
slots={{
|
||||||
|
appTitle(_) {
|
||||||
|
return (
|
||||||
|
<Stack direction="row" alignItems="center" spacing={2}>
|
||||||
|
<NextLink passHref href="/console">
|
||||||
|
<Typography variant="h6">Solar Network Console</Typography>
|
||||||
|
</NextLink>
|
||||||
|
</Stack>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
toolbarActions(_) {
|
||||||
|
return <Box />
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
sidebarExpandedWidth={300}
|
||||||
|
defaultSidebarCollapsed
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</DashboardLayout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getConsoleStaticProps(original: any) {
|
||||||
|
if (original.props.title) {
|
||||||
|
original.props.title = 'Console | ' + original.props.title
|
||||||
|
}
|
||||||
|
original.props.showAppBar = false
|
||||||
|
|
||||||
|
return original
|
||||||
|
}
|
@ -4,6 +4,7 @@ import { Box, createTheme, CssBaseline, ThemeProvider } from '@mui/material'
|
|||||||
import { Roboto } from 'next/font/google'
|
import { Roboto } from 'next/font/google'
|
||||||
import { CapAppBar } from '@/components/CapAppBar'
|
import { CapAppBar } from '@/components/CapAppBar'
|
||||||
import { PagesProgressBar as ProgressBar } from 'next-nprogress-bar'
|
import { PagesProgressBar as ProgressBar } from 'next-nprogress-bar'
|
||||||
|
import { AppProvider } from '@toolpad/core/nextjs'
|
||||||
import { useUserStore } from '@/services/user'
|
import { useUserStore } from '@/services/user'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import Head from 'next/head'
|
import Head from 'next/head'
|
||||||
@ -56,20 +57,22 @@ export default function App({ Component, pageProps }: AppProps) {
|
|||||||
<link rel="apple-touch-icon" href="/apple-icon.png" type="image/png" />
|
<link rel="apple-touch-icon" href="/apple-icon.png" type="image/png" />
|
||||||
</Head>
|
</Head>
|
||||||
|
|
||||||
<ThemeProvider theme={siteTheme}>
|
<AppProvider>
|
||||||
<CssBaseline />
|
<ThemeProvider theme={siteTheme}>
|
||||||
<ProgressBar
|
<CssBaseline />
|
||||||
height="4px"
|
<ProgressBar
|
||||||
color={siteTheme.palette.primary.main}
|
height="4px"
|
||||||
options={{ showSpinner: false }}
|
color={siteTheme.palette.primary.main}
|
||||||
shallowRouting
|
options={{ showSpinner: false }}
|
||||||
/>
|
shallowRouting
|
||||||
|
/>
|
||||||
|
|
||||||
<CapAppBar />
|
{(pageProps.showAppBar ?? true) && <CapAppBar />}
|
||||||
<Box sx={{ minHeight: 'calc(100vh - 64px)' }}>
|
<Box sx={{ minHeight: 'calc(100vh - 64px)' }}>
|
||||||
<Component {...pageProps} />
|
<Component {...pageProps} />
|
||||||
</Box>
|
</Box>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
|
</AppProvider>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
51
src/pages/console/index.tsx
Normal file
51
src/pages/console/index.tsx
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { ConsoleLayout, getConsoleStaticProps } from '@/components/layouts/ConsoleLayout'
|
||||||
|
import { Typography, Container, Box, Grid2 as Grid, Card, CardContent, CardActionArea } from '@mui/material'
|
||||||
|
import NextLink from 'next/link'
|
||||||
|
|
||||||
|
import DynamicFormIcon from '@mui/icons-material/DynamicForm'
|
||||||
|
import AppsIcon from '@mui/icons-material/Apps'
|
||||||
|
|
||||||
|
export function getStaticProps() {
|
||||||
|
return getConsoleStaticProps({
|
||||||
|
props: {
|
||||||
|
title: 'Welcome',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ConsoleLanding() {
|
||||||
|
return (
|
||||||
|
<ConsoleLayout>
|
||||||
|
<Container sx={{ py: 16, display: 'flex', flexDirection: 'column', gap: 8 }}>
|
||||||
|
<Box>
|
||||||
|
<DynamicFormIcon sx={{ fontSize: 64, mb: 2 }} />
|
||||||
|
<Typography variant="subtitle2">Welcome to the</Typography>
|
||||||
|
<Typography variant="h3" component="h1">
|
||||||
|
Console
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="subtitle1">of the Solar Network</Typography>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Grid container columns={{ xs: 2, sm: 2, md: 3, lg: 4 }} spacing={4}>
|
||||||
|
<Grid size={1}>
|
||||||
|
<NextLink passHref href="/console/matrix">
|
||||||
|
<CardActionArea>
|
||||||
|
<Card sx={{ width: '100%' }}>
|
||||||
|
<CardContent>
|
||||||
|
<AppsIcon sx={{ fontSize: 32, mb: 1.5 }} />
|
||||||
|
<Typography variant="h5" gutterBottom>
|
||||||
|
Matrix
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body1">
|
||||||
|
Publish and versioning your application with Matrix Marketplace.
|
||||||
|
</Typography>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</CardActionArea>
|
||||||
|
</NextLink>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Container>
|
||||||
|
</ConsoleLayout>
|
||||||
|
)
|
||||||
|
}
|
66
src/pages/console/matrix/index.tsx
Normal file
66
src/pages/console/matrix/index.tsx
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import { ConsoleLayout, getConsoleStaticProps } from '@/components/layouts/ConsoleLayout'
|
||||||
|
import { MaProduct } from '@/services/matrix/product'
|
||||||
|
import { sni } from '@/services/network'
|
||||||
|
import { Typography, Container, Box, Button, Grid2 as Grid, Card, CardActionArea, CardContent } from '@mui/material'
|
||||||
|
import NextLink from 'next/link'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
export async function getStaticProps() {
|
||||||
|
return getConsoleStaticProps({
|
||||||
|
props: {
|
||||||
|
title: 'Matrix Marketplace',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function MatrixMarketplace() {
|
||||||
|
const [products, setProducts] = useState<MaProduct[]>([])
|
||||||
|
|
||||||
|
async function fetchProducts() {
|
||||||
|
const { data: resp } = await sni.get<{ data: MaProduct[] }>('/cgi/ma/products/created', {
|
||||||
|
params: {
|
||||||
|
take: 10,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
setProducts(resp.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchProducts()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConsoleLayout>
|
||||||
|
<Container sx={{ py: 16, display: 'flex', flexDirection: 'column', gap: 4 }}>
|
||||||
|
<Typography variant="h3" component="h1">
|
||||||
|
Matrix Marketplace
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Grid container columns={{ xs: 2, sm: 2, md: 3, lg: 4 }} spacing={4}>
|
||||||
|
{products.map((p) => (
|
||||||
|
<Grid size={1} key={p.id}>
|
||||||
|
<NextLink passHref href="/console/matrix">
|
||||||
|
<CardActionArea>
|
||||||
|
<Card sx={{ width: '100%' }}>
|
||||||
|
<CardContent>
|
||||||
|
<Typography variant="h5" gutterBottom>
|
||||||
|
{p.name}
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body1">{p.description}</Typography>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</CardActionArea>
|
||||||
|
</NextLink>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Box>
|
||||||
|
<NextLink passHref href="/console/matrix/products/new">
|
||||||
|
<Button variant="contained">Create a product</Button>
|
||||||
|
</NextLink>
|
||||||
|
</Box>
|
||||||
|
</Container>
|
||||||
|
</ConsoleLayout>
|
||||||
|
)
|
||||||
|
}
|
82
src/pages/console/matrix/products/new.tsx
Normal file
82
src/pages/console/matrix/products/new.tsx
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import { ConsoleLayout, getConsoleStaticProps } from '@/components/layouts/ConsoleLayout'
|
||||||
|
import { Typography, Container, Box, Button, TextField, Collapse, Alert } from '@mui/material'
|
||||||
|
import { useForm } from 'react-hook-form'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
import NextLink from 'next/link'
|
||||||
|
import { sni } from '@/services/network'
|
||||||
|
|
||||||
|
import ErrorIcon from '@mui/icons-material/Error'
|
||||||
|
|
||||||
|
export async function getStaticProps() {
|
||||||
|
return getConsoleStaticProps({
|
||||||
|
props: {
|
||||||
|
title: 'Matrix',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MatrixProductNewForm {
|
||||||
|
name: string
|
||||||
|
alias: string
|
||||||
|
description: string
|
||||||
|
introduction: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ProductNew() {
|
||||||
|
const { handleSubmit, register } = useForm<MatrixProductNewForm>()
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const [error, setError] = useState<string | null>(null)
|
||||||
|
const [busy, setBusy] = useState<boolean>(false)
|
||||||
|
|
||||||
|
async function onSubmit(data: any) {
|
||||||
|
try {
|
||||||
|
setBusy(true)
|
||||||
|
await sni.post('/cgi/ma/products', data)
|
||||||
|
router.push('/console/matrix')
|
||||||
|
} catch (err: any) {
|
||||||
|
setError(err.toString())
|
||||||
|
} finally {
|
||||||
|
setBusy(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConsoleLayout>
|
||||||
|
<Container sx={{ py: 16, display: 'flex', flexDirection: 'column', gap: 4 }}>
|
||||||
|
<Typography variant="h3" component="h1">
|
||||||
|
Create a product
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<Box display="flex" flexDirection="column" maxWidth="sm" gap={2.5}>
|
||||||
|
<Collapse in={!!error} sx={{ width: '100%' }}>
|
||||||
|
<Alert icon={<ErrorIcon fontSize="inherit" />} severity="error">
|
||||||
|
{error}
|
||||||
|
</Alert>
|
||||||
|
</Collapse>
|
||||||
|
|
||||||
|
<TextField label="Name" {...register('name')} />
|
||||||
|
|
||||||
|
<TextField label="Alias" {...register('alias')} />
|
||||||
|
|
||||||
|
<TextField minRows={3} maxRows={3} multiline label="Description" {...register('description')} />
|
||||||
|
|
||||||
|
<TextField minRows={5} multiline label="Introduction" {...register('introduction')} />
|
||||||
|
|
||||||
|
<Box sx={{ mt: 5 }} display="flex" gap={2}>
|
||||||
|
<Button variant="contained" type="submit" disabled={busy}>
|
||||||
|
Create
|
||||||
|
</Button>
|
||||||
|
<NextLink passHref href="/console/matrix">
|
||||||
|
<Button disabled={busy}>Cancel</Button>
|
||||||
|
</NextLink>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</form>
|
||||||
|
</Container>
|
||||||
|
</ConsoleLayout>
|
||||||
|
)
|
||||||
|
}
|
11
src/pages/matrix/index.tsx
Normal file
11
src/pages/matrix/index.tsx
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { Typography, Container } from '@mui/material'
|
||||||
|
|
||||||
|
export default function MatrixMarketplace() {
|
||||||
|
return (
|
||||||
|
<Container sx={{ py: 24, display: 'flex', flexDirection: 'column', gap: 32 }}>
|
||||||
|
<Typography variant="h3" component="h1">
|
||||||
|
Matrix Marketplace
|
||||||
|
</Typography>
|
||||||
|
</Container>
|
||||||
|
)
|
||||||
|
}
|
25
src/services/matrix/product.ts
Normal file
25
src/services/matrix/product.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
export interface MaProduct {
|
||||||
|
id: number
|
||||||
|
created_at: Date
|
||||||
|
updated_at: Date
|
||||||
|
deleted_at?: Date
|
||||||
|
icon: string
|
||||||
|
name: string
|
||||||
|
alias: string
|
||||||
|
description: string
|
||||||
|
previews: string[]
|
||||||
|
tags: string[]
|
||||||
|
meta: MaProductMeta
|
||||||
|
releases: null
|
||||||
|
account_id: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MaProductMeta {
|
||||||
|
id: number
|
||||||
|
created_at: Date
|
||||||
|
updated_at: Date
|
||||||
|
deleted_at?: Date
|
||||||
|
introduction: string
|
||||||
|
attachments: string[]
|
||||||
|
product_id: number
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user