✨ Landing
This commit is contained in:
		| @@ -1,5 +1,5 @@ | |||||||
| appId: com.electron.app | appId: dev.solsynth.matrix | ||||||
| productName: matrix-terminal | productName: MatrixTerminal | ||||||
| directories: | directories: | ||||||
|   buildResources: build |   buildResources: build | ||||||
| files: | files: | ||||||
| @@ -12,7 +12,7 @@ files: | |||||||
| asarUnpack: | asarUnpack: | ||||||
|   - resources/** |   - resources/** | ||||||
| win: | win: | ||||||
|   executableName: matrix-terminal |   executableName: MatrixTerminal | ||||||
| nsis: | nsis: | ||||||
|   artifactName: ${name}-${version}-setup.${ext} |   artifactName: ${name}-${version}-setup.${ext} | ||||||
|   shortcutName: ${productName} |   shortcutName: ${productName} | ||||||
| @@ -33,7 +33,7 @@ linux: | |||||||
|     - AppImage |     - AppImage | ||||||
|     - snap |     - snap | ||||||
|     - deb |     - deb | ||||||
|   maintainer: electronjs.org |   maintainer: solsynth.dev | ||||||
|   category: Utility |   category: Utility | ||||||
| appImage: | appImage: | ||||||
|   artifactName: ${name}-${version}.${ext} |   artifactName: ${name}-${version}.${ext} | ||||||
|   | |||||||
| @@ -4,17 +4,17 @@ import react from '@vitejs/plugin-react' | |||||||
|  |  | ||||||
| export default defineConfig({ | export default defineConfig({ | ||||||
|   main: { |   main: { | ||||||
|     plugins: [externalizeDepsPlugin()] |     plugins: [externalizeDepsPlugin()], | ||||||
|   }, |   }, | ||||||
|   preload: { |   preload: { | ||||||
|     plugins: [externalizeDepsPlugin()] |     plugins: [externalizeDepsPlugin()], | ||||||
|   }, |   }, | ||||||
|   renderer: { |   renderer: { | ||||||
|     resolve: { |     resolve: { | ||||||
|       alias: { |       alias: { | ||||||
|         '@renderer': resolve('src/renderer/src') |         '@renderer': resolve('src/renderer/src'), | ||||||
|       } |       }, | ||||||
|  |     }, | ||||||
|  |     plugins: [react()], | ||||||
|   }, |   }, | ||||||
|     plugins: [react()] |  | ||||||
|   } |  | ||||||
| }) | }) | ||||||
|   | |||||||
| @@ -28,7 +28,9 @@ | |||||||
|     "@fontsource/roboto": "^5.1.1", |     "@fontsource/roboto": "^5.1.1", | ||||||
|     "@mui/icons-material": "^6.3.1", |     "@mui/icons-material": "^6.3.1", | ||||||
|     "@mui/material": "^6.3.1", |     "@mui/material": "^6.3.1", | ||||||
|     "electron-updater": "^6.3.9" |     "electron-updater": "^6.3.9", | ||||||
|  |     "react-router": "^7.1.1", | ||||||
|  |     "solar-js-sdk": "^0.1.2" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "@electron-toolkit/eslint-config-prettier": "^2.0.0", |     "@electron-toolkit/eslint-config-prettier": "^2.0.0", | ||||||
|   | |||||||
| @@ -12,14 +12,16 @@ function createWindow(): void { | |||||||
|     minHeight: 640, |     minHeight: 640, | ||||||
|     show: false, |     show: false, | ||||||
|     autoHideMenuBar: true, |     autoHideMenuBar: true, | ||||||
|  |     title: 'MatrixTerminal', | ||||||
|     ...(process.platform === 'linux' ? { icon } : {}), |     ...(process.platform === 'linux' ? { icon } : {}), | ||||||
|     webPreferences: { |     webPreferences: { | ||||||
|       preload: join(__dirname, '../preload/index.js'), |       preload: join(__dirname, '../preload/index.js'), | ||||||
|       sandbox: false |       sandbox: false, | ||||||
|     } |     }, | ||||||
|   }) |   }) | ||||||
|  |  | ||||||
|   mainWindow.on('ready-to-show', () => { |   mainWindow.on('ready-to-show', () => { | ||||||
|  |     mainWindow.title = 'MatrixTerminal' | ||||||
|     mainWindow.show() |     mainWindow.show() | ||||||
|   }) |   }) | ||||||
|  |  | ||||||
| @@ -42,7 +44,7 @@ function createWindow(): void { | |||||||
| // Some APIs can only be used after this event occurs. | // Some APIs can only be used after this event occurs. | ||||||
| app.whenReady().then(() => { | app.whenReady().then(() => { | ||||||
|   // Set app user model id for windows |   // Set app user model id for windows | ||||||
|   electronApp.setAppUserModelId('com.electron') |   electronApp.setAppUserModelId('dev.solsynth.matrix') | ||||||
|  |  | ||||||
|   // Default open or close DevTools by F12 in development |   // Default open or close DevTools by F12 in development | ||||||
|   // and ignore CommandOrControl + R in production. |   // and ignore CommandOrControl + R in production. | ||||||
|   | |||||||
| @@ -2,11 +2,11 @@ | |||||||
| <html> | <html> | ||||||
|   <head> |   <head> | ||||||
|     <meta charset="UTF-8" /> |     <meta charset="UTF-8" /> | ||||||
|     <title>Electron</title> |     <title>MatrixTerminal</title> | ||||||
|     <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP --> |     <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP --> | ||||||
|     <meta |     <meta | ||||||
|       http-equiv="Content-Security-Policy" |       http-equiv="Content-Security-Policy" | ||||||
|       content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:" |       content="connect-src 'self' * 'unsafe-eval'" | ||||||
|     /> |     /> | ||||||
|   </head> |   </head> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,8 +1,20 @@ | |||||||
| import { CssBaseline, ThemeProvider, createTheme } from '@mui/material' | import { CssBaseline, ThemeProvider, createTheme } from '@mui/material' | ||||||
|  | import { BrowserRouter, Route, Routes } from 'react-router' | ||||||
|  | import { MaAppBar } from '@renderer/components/MaAppBar' | ||||||
|  | import Landing from '@renderer/pages/Landing' | ||||||
|  |  | ||||||
|  | import { useUserStore } from 'solar-js-sdk' | ||||||
|  | import { useEffect } from 'react' | ||||||
|  |  | ||||||
| function App(): JSX.Element { | function App(): JSX.Element { | ||||||
|   // const ipcHandle = (): void => window.electron.ipcRenderer.send('ping') |   // const ipcHandle = (): void => window.electron.ipcRenderer.send('ping') | ||||||
|  |  | ||||||
|  |   const userStore = useUserStore() | ||||||
|  |  | ||||||
|  |   useEffect(() => { | ||||||
|  |     userStore.fetchUser() | ||||||
|  |   }, []) | ||||||
|  |  | ||||||
|   const appTheme = createTheme({ |   const appTheme = createTheme({ | ||||||
|     cssVariables: true, |     cssVariables: true, | ||||||
|     colorSchemes: { |     colorSchemes: { | ||||||
| @@ -21,8 +33,15 @@ function App(): JSX.Element { | |||||||
|  |  | ||||||
|   return ( |   return ( | ||||||
|     <ThemeProvider theme={appTheme}> |     <ThemeProvider theme={appTheme}> | ||||||
|  |       <BrowserRouter> | ||||||
|         <CssBaseline /> |         <CssBaseline /> | ||||||
|       <span className="text-2xl">Hello, World!</span> |  | ||||||
|  |         <MaAppBar /> | ||||||
|  |  | ||||||
|  |         <Routes> | ||||||
|  |           <Route path="/" element={<Landing />} /> | ||||||
|  |         </Routes> | ||||||
|  |       </BrowserRouter> | ||||||
|     </ThemeProvider> |     </ThemeProvider> | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										56
									
								
								src/renderer/src/components/MaAppBar.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/renderer/src/components/MaAppBar.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | |||||||
|  | import { | ||||||
|  |   AppBar, | ||||||
|  |   Toolbar, | ||||||
|  |   IconButton, | ||||||
|  |   Typography, | ||||||
|  |   Drawer, | ||||||
|  |   List, | ||||||
|  |   ListItem, | ||||||
|  |   ListItemButton, | ||||||
|  |   ListItemIcon, | ||||||
|  |   ListItemText, | ||||||
|  | } from '@mui/material' | ||||||
|  | import { useState } from 'react' | ||||||
|  |  | ||||||
|  | import GamepadIcon from '@mui/icons-material/Gamepad' | ||||||
|  |  | ||||||
|  | export function MaAppBar(): JSX.Element { | ||||||
|  |   const [open, setOpen] = useState(false) | ||||||
|  |  | ||||||
|  |   return ( | ||||||
|  |     <> | ||||||
|  |       <Drawer open={open} onClose={() => setOpen(false)} sx={{ width: '320px' }}> | ||||||
|  |         <List sx={{ width: '320px' }}> | ||||||
|  |           {['Inbox', 'Starred', 'Send email', 'Drafts'].map((text) => ( | ||||||
|  |             <ListItem key={text} disablePadding> | ||||||
|  |               <ListItemButton> | ||||||
|  |                 <ListItemIcon> | ||||||
|  |                   <GamepadIcon /> | ||||||
|  |                 </ListItemIcon> | ||||||
|  |                 <ListItemText primary={text} /> | ||||||
|  |               </ListItemButton> | ||||||
|  |             </ListItem> | ||||||
|  |           ))} | ||||||
|  |         </List> | ||||||
|  |       </Drawer> | ||||||
|  |  | ||||||
|  |       <AppBar position="static"> | ||||||
|  |         <Toolbar> | ||||||
|  |           <IconButton | ||||||
|  |             size="large" | ||||||
|  |             edge="start" | ||||||
|  |             color="inherit" | ||||||
|  |             aria-label="menu" | ||||||
|  |             sx={{ mr: 2 }} | ||||||
|  |             onClick={() => setOpen(true)} | ||||||
|  |           > | ||||||
|  |             <GamepadIcon /> | ||||||
|  |           </IconButton> | ||||||
|  |           <Typography variant="h6" component="div" sx={{ flexGrow: 1 }}> | ||||||
|  |             Matrix | ||||||
|  |           </Typography> | ||||||
|  |         </Toolbar> | ||||||
|  |       </AppBar> | ||||||
|  |     </> | ||||||
|  |   ) | ||||||
|  | } | ||||||
| @@ -8,5 +8,5 @@ import App from './App' | |||||||
| ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( | ||||||
|   <React.StrictMode> |   <React.StrictMode> | ||||||
|     <App /> |     <App /> | ||||||
|   </React.StrictMode> |   </React.StrictMode>, | ||||||
| ) | ) | ||||||
|   | |||||||
							
								
								
									
										81
									
								
								src/renderer/src/pages/Landing.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/renderer/src/pages/Landing.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | |||||||
|  | import { | ||||||
|  |   Box, | ||||||
|  |   Container, | ||||||
|  |   Typography, | ||||||
|  |   Grid2 as Grid, | ||||||
|  |   Card, | ||||||
|  |   CardContent, | ||||||
|  |   CardMedia, | ||||||
|  |   CardActionArea, | ||||||
|  |   Avatar, | ||||||
|  | } from '@mui/material' | ||||||
|  | import { useEffect, useState } from 'react' | ||||||
|  | import { MaProduct, getAttachmentUrl, sni } from 'solar-js-sdk' | ||||||
|  |  | ||||||
|  | export default function Landing(): JSX.Element { | ||||||
|  |   const [products, setProducts] = useState<MaProduct[]>([]) | ||||||
|  |  | ||||||
|  |   async function fetchProducts(): Promise<void> { | ||||||
|  |     const { data: resp } = await sni.get<{ data: MaProduct[] }>('/cgi/ma/products', { | ||||||
|  |       params: { | ||||||
|  |         take: 10, | ||||||
|  |       }, | ||||||
|  |     }) | ||||||
|  |     setProducts(resp.data) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   useEffect(() => { | ||||||
|  |     fetchProducts() | ||||||
|  |   }, []) | ||||||
|  |  | ||||||
|  |   return ( | ||||||
|  |     <Container sx={{ py: 8, display: 'flex', flexDirection: 'column', gap: 2 }}> | ||||||
|  |       <Box> | ||||||
|  |         <Typography variant="h4" component="div" sx={{ mb: 2 }}> | ||||||
|  |           Matrix Marketplace | ||||||
|  |         </Typography> | ||||||
|  |       </Box> | ||||||
|  |  | ||||||
|  |       <Grid container columns={{ xs: 1, sm: 2, md: 3 }} spacing={2}> | ||||||
|  |         {products.map((p) => ( | ||||||
|  |           <Grid size={1} key={p.id}> | ||||||
|  |             <Card> | ||||||
|  |               <CardActionArea> | ||||||
|  |                 {p.previews && ( | ||||||
|  |                   <CardMedia | ||||||
|  |                     sx={{ aspectRatio: 16 / 5 }} | ||||||
|  |                     image={getAttachmentUrl(p.previews[0])} | ||||||
|  |                     title="green iguana" | ||||||
|  |                   /> | ||||||
|  |                 )} | ||||||
|  |                 <CardContent> | ||||||
|  |                   {p.icon && ( | ||||||
|  |                     <Avatar | ||||||
|  |                       variant="rounded" | ||||||
|  |                       src={getAttachmentUrl(p.icon)} | ||||||
|  |                       sx={{ | ||||||
|  |                         width: 48, | ||||||
|  |                         height: 48, | ||||||
|  |                         border: 1, | ||||||
|  |                         borderColor: 'divider', | ||||||
|  |                         borderRadius: 4, | ||||||
|  |                         mb: 0.75, | ||||||
|  |                         mx: '-4px', | ||||||
|  |                       }} | ||||||
|  |                     /> | ||||||
|  |                   )} | ||||||
|  |                   <Typography variant="h5" component="div"> | ||||||
|  |                     {p.name} | ||||||
|  |                   </Typography> | ||||||
|  |                   <Typography variant="body2" component="div"> | ||||||
|  |                     {p.description} | ||||||
|  |                   </Typography> | ||||||
|  |                 </CardContent> | ||||||
|  |               </CardActionArea> | ||||||
|  |             </Card> | ||||||
|  |           </Grid> | ||||||
|  |         ))} | ||||||
|  |       </Grid> | ||||||
|  |     </Container> | ||||||
|  |   ) | ||||||
|  | } | ||||||
| @@ -6,4 +6,3 @@ module.exports = { | |||||||
|   }, |   }, | ||||||
|   plugins: [], |   plugins: [], | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user