Compare commits
	
		
			2 Commits
		
	
	
		
			eaef7f304c
			...
			945bd5d357
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 945bd5d357 | |||
| daba03c2e8 | 
@@ -18,6 +18,7 @@
 | 
			
		||||
    "@mui/material-nextjs": "^6.3.1",
 | 
			
		||||
    "@mui/x-charts": "^7.23.2",
 | 
			
		||||
    "@tailwindcss/typography": "^0.5.16",
 | 
			
		||||
    "@toolpad/core": "^0.11.0",
 | 
			
		||||
    "@vercel/speed-insights": "^1.1.0",
 | 
			
		||||
    "animate.css": "^4.1.1",
 | 
			
		||||
    "axios": "^1.7.9",
 | 
			
		||||
@@ -51,6 +52,8 @@
 | 
			
		||||
    "@eslint/eslintrc": "^3.2.0"
 | 
			
		||||
  },
 | 
			
		||||
  "trustedDependencies": [
 | 
			
		||||
    "@vercel/speed-insights"
 | 
			
		||||
    "@vercel/speed-insights",
 | 
			
		||||
    "esbuild",
 | 
			
		||||
    "sharp"
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,7 @@ export function CapAppBar() {
 | 
			
		||||
      <CapDrawer width={drawerWidth} open={open} onClose={() => setOpen(false)} />
 | 
			
		||||
 | 
			
		||||
      <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>
 | 
			
		||||
            <IconButton
 | 
			
		||||
              size="large"
 | 
			
		||||
 
 | 
			
		||||
@@ -16,10 +16,11 @@ import Image from 'next/image'
 | 
			
		||||
 | 
			
		||||
import ExploreIcon from '@mui/icons-material/Explore'
 | 
			
		||||
import PhotoLibraryIcon from '@mui/icons-material/PhotoLibrary'
 | 
			
		||||
import AppsIcon from '@mui/icons-material/Apps'
 | 
			
		||||
import NextLink from 'next/link'
 | 
			
		||||
import { useRouter } from 'next/router'
 | 
			
		||||
 | 
			
		||||
interface NavLink {
 | 
			
		||||
export interface NavLink {
 | 
			
		||||
  title: string
 | 
			
		||||
  icon?: JSX.Element
 | 
			
		||||
  href: string
 | 
			
		||||
@@ -39,6 +40,11 @@ export function CapDrawer({ width, open, onClose }: { width: number; open: boole
 | 
			
		||||
      icon: <PhotoLibraryIcon />,
 | 
			
		||||
      href: '/attachments',
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      title: 'Matrix',
 | 
			
		||||
      icon: <AppsIcon />,
 | 
			
		||||
      href: '/matrix',
 | 
			
		||||
    },
 | 
			
		||||
  ]
 | 
			
		||||
 | 
			
		||||
  const additionalLinks: NavLink[] = [
 | 
			
		||||
@@ -46,6 +52,10 @@ export function CapDrawer({ width, open, onClose }: { width: number; open: boole
 | 
			
		||||
      title: 'Terms & Conditions',
 | 
			
		||||
      href: '/terms',
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      title: 'SN Console',
 | 
			
		||||
      href: '/console',
 | 
			
		||||
    },
 | 
			
		||||
  ]
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
@@ -87,7 +97,7 @@ export function CapDrawer({ width, open, onClose }: { width: number; open: boole
 | 
			
		||||
          ))}
 | 
			
		||||
        </List>
 | 
			
		||||
        <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) => (
 | 
			
		||||
            <NextLink passHref href={l.href} key={l.href}>
 | 
			
		||||
              <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 { CapAppBar } from '@/components/CapAppBar'
 | 
			
		||||
import { PagesProgressBar as ProgressBar } from 'next-nprogress-bar'
 | 
			
		||||
import { AppProvider } from '@toolpad/core/nextjs'
 | 
			
		||||
import { useUserStore } from '@/services/user'
 | 
			
		||||
import { useEffect } from 'react'
 | 
			
		||||
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" />
 | 
			
		||||
      </Head>
 | 
			
		||||
 | 
			
		||||
      <ThemeProvider theme={siteTheme}>
 | 
			
		||||
        <CssBaseline />
 | 
			
		||||
        <ProgressBar
 | 
			
		||||
          height="4px"
 | 
			
		||||
          color={siteTheme.palette.primary.main}
 | 
			
		||||
          options={{ showSpinner: false }}
 | 
			
		||||
          shallowRouting
 | 
			
		||||
        />
 | 
			
		||||
      <AppProvider>
 | 
			
		||||
        <ThemeProvider theme={siteTheme}>
 | 
			
		||||
          <CssBaseline />
 | 
			
		||||
          <ProgressBar
 | 
			
		||||
            height="4px"
 | 
			
		||||
            color={siteTheme.palette.primary.main}
 | 
			
		||||
            options={{ showSpinner: false }}
 | 
			
		||||
            shallowRouting
 | 
			
		||||
          />
 | 
			
		||||
 | 
			
		||||
        <CapAppBar />
 | 
			
		||||
        <Box sx={{ minHeight: 'calc(100vh - 64px)' }}>
 | 
			
		||||
          <Component {...pageProps} />
 | 
			
		||||
        </Box>
 | 
			
		||||
      </ThemeProvider>
 | 
			
		||||
          {(pageProps.showAppBar ?? true) && <CapAppBar />}
 | 
			
		||||
          <Box sx={{ minHeight: 'calc(100vh - 64px)' }}>
 | 
			
		||||
            <Component {...pageProps} />
 | 
			
		||||
          </Box>
 | 
			
		||||
        </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
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user