Make registry more responsive
Add dynamic route for clickable tiles Make copy url notification instead of alert Add achitecture to details
This commit is contained in:
		| @@ -1,6 +1,17 @@ | ||||
| import { useRouter } from 'next/router' | ||||
|  | ||||
| function App({ Component, pageProps, app }) { | ||||
|     const router = useRouter() | ||||
|  | ||||
|     const viewexample = (app) => { | ||||
|         router.push({ | ||||
|             pathname: '/addapp/[app]', | ||||
|             query: { app: btoa(app.name)} | ||||
|         }) | ||||
|     } | ||||
|      | ||||
|     return ( | ||||
|         <div className="w-[245px] h-[88px] transition-all relative cursor-pointer group flex p-2 items-center justify-center bg-slate-100/90 dark:bg-slate-900/90 shadow rounded hover:shadow-xl hover:bg-gradient-to-r hover:from-slate-900 hover:to-cyan-800 hover:text-white"> | ||||
|         <div onClick={() => viewexample(app)} className="w-[245px] h-[88px] transition-all relative cursor-pointer group flex p-2 items-center justify-center bg-slate-100/90 dark:bg-slate-900/90 shadow rounded hover:shadow-xl hover:bg-gradient-to-r hover:from-slate-900 hover:to-cyan-800 hover:text-white"> | ||||
|             <div className="w-full h-full"> | ||||
|                 <div className="show-grid flex h-full items-center"> | ||||
|                     <div className="kasmcard-img flex h-full mx-4 items-center justify-center"> | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| import Bubbles from '../components/Bubbles' | ||||
| import Link from 'next/link' | ||||
| import { useRouter } from "next/router"; | ||||
| import { NotificationManager } from 'react-notifications'; | ||||
|  | ||||
| export default function Header({ searchText, changeSearch }) { | ||||
|  | ||||
| @@ -11,13 +12,13 @@ export default function Header({ searchText, changeSearch }) { | ||||
|     textField.select() | ||||
|     document.execCommand('copy') | ||||
|     textField.remove() | ||||
|     alert('URL copied to clipboard') | ||||
|     NotificationManager.info('URL successfully copied to clipboard', 'Copy URL', 4000); | ||||
|   } | ||||
|   const listUrl = process.env.listUrl; | ||||
|   const router = useRouter(); | ||||
|  | ||||
|   return ( | ||||
|     <header className="relative font-light overflow-hidden bg-gradient-to-tr from-slate-900 to-cyan-800 p-32 py-8 text-white flex justify-between items-center"> | ||||
|     <header className="relative font-light overflow-hidden bg-gradient-to-tr from-slate-900 to-cyan-800 p-8 xl:px-32 text-white gap-5 md:gap-0 flex flex-wrap justify-center items-center"> | ||||
|       <Bubbles /> | ||||
|       <div className='relative z-10'> | ||||
|         <div className="text-3xl">{process.env.name}</div> | ||||
| @@ -45,8 +46,8 @@ export default function Header({ searchText, changeSearch }) { | ||||
|         </div> | ||||
|       </div> | ||||
|       <nav className='relative z-10 mx-12'> | ||||
|         <Link href="/" className={'p-4 rounded-full border border-solid' + (router.pathname == "/" ? ' border-white/30' : ' border-transparent')}>Library</Link> | ||||
|         <Link href="/addapp" className={'p-4 rounded-full border border-solid' + (router.pathname == "/addapp" ? ' bg-black/10 border-white/30' : ' border-transparent')}>Add App</Link> | ||||
|         <Link href="/" className={'p-4 inline-block rounded-full border border-solid' + (router.pathname == "/" ? ' border-white/30' : ' border-transparent')}>Library</Link> | ||||
|         <Link href="/addapp" className={'p-4 inline-block rounded-full border border-solid' + (router.pathname == "/addapp" ? ' bg-black/10 border-white/30' : ' border-transparent')}>Add App</Link> | ||||
|       </nav> | ||||
|       <div className="grow flex justify-center relative z-10"> | ||||
|         <div className='bg-black/10 shadow border border-1 border-white/30 rounded flex w-full max-w-md'> | ||||
| @@ -62,7 +63,7 @@ export default function Header({ searchText, changeSearch }) { | ||||
|         </div> | ||||
|  | ||||
|       </div> | ||||
|       <button className='p-4 relative z-10 px-5 bg-emerald-600 m-2 rounded items-center text-white/70 flex cursor-pointer' onClick={() => { copyToClipboard() }}> | ||||
|       <button className='p-4 relative z-10 px-5 bg-cyan-700 border-t border-white/20 border-solid hover:bg-slate-900 transition shadow-lg m-2 rounded items-center text-white/70 flex cursor-pointer' onClick={() => { copyToClipboard() }}> | ||||
|         <span className="mr-3">App Registry Link</span> | ||||
|         <svg style={{ height: '14px', fill: '#fff' }} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M224 0c-35.3 0-64 28.7-64 64V288c0 35.3 28.7 64 64 64H448c35.3 0 64-28.7 64-64V64c0-35.3-28.7-64-64-64H224zM64 160c-35.3 0-64 28.7-64 64V448c0 35.3 28.7 64 64 64H288c35.3 0 64-28.7 64-64V384H288v64H64V224h64V160H64z" /></svg> | ||||
|       </button> | ||||
|   | ||||
| @@ -2,6 +2,8 @@ | ||||
|  | ||||
| import Header from './header' | ||||
| import Footer from './footer' | ||||
| import 'react-notifications/lib/notifications.css'; | ||||
| import { NotificationContainer } from 'react-notifications'; | ||||
|  | ||||
| export default function Layout({ children, searchText, changeSearch }) { | ||||
|   return ( | ||||
| @@ -9,6 +11,7 @@ export default function Layout({ children, searchText, changeSearch }) { | ||||
|       <Header searchText={searchText} changeSearch={changeSearch} /> | ||||
|       <main>{children}</main> | ||||
|       <Footer /> | ||||
|       <NotificationContainer/> | ||||
|     </> | ||||
|   ) | ||||
| } | ||||
							
								
								
									
										76
									
								
								site/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										76
									
								
								site/package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -5,6 +5,7 @@ | ||||
|   "requires": true, | ||||
|   "packages": { | ||||
|     "": { | ||||
|       "name": "site", | ||||
|       "version": "0.1.0", | ||||
|       "dependencies": { | ||||
|         "file-saver": "^2.0.5", | ||||
| @@ -12,6 +13,7 @@ | ||||
|         "next": "13.0.0", | ||||
|         "react": "18.2.0", | ||||
|         "react-dom": "18.2.0", | ||||
|         "react-notifications": "^1.7.4", | ||||
|         "react-select": "^5.6.1" | ||||
|       }, | ||||
|       "devDependencies": { | ||||
| @@ -86,9 +88,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@babel/core/node_modules/json5": { | ||||
|       "version": "2.2.1", | ||||
|       "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", | ||||
|       "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", | ||||
|       "version": "2.2.3", | ||||
|       "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", | ||||
|       "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", | ||||
|       "peer": true, | ||||
|       "bin": { | ||||
|         "json5": "lib/cli.js" | ||||
| @@ -1532,6 +1534,11 @@ | ||||
|         "node": ">= 6" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/classnames": { | ||||
|       "version": "2.3.2", | ||||
|       "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", | ||||
|       "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" | ||||
|     }, | ||||
|     "node_modules/client-only": { | ||||
|       "version": "0.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", | ||||
| @@ -3015,9 +3022,9 @@ | ||||
|       "dev": true | ||||
|     }, | ||||
|     "node_modules/json5": { | ||||
|       "version": "1.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", | ||||
|       "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", | ||||
|       "version": "1.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", | ||||
|       "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "minimist": "^1.2.0" | ||||
| @@ -3801,6 +3808,28 @@ | ||||
|       "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", | ||||
|       "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" | ||||
|     }, | ||||
|     "node_modules/react-notifications": { | ||||
|       "version": "1.7.4", | ||||
|       "resolved": "https://registry.npmjs.org/react-notifications/-/react-notifications-1.7.4.tgz", | ||||
|       "integrity": "sha512-dsR7mUQfe8YdFLqVsjT0GFd4n26UWkzefdjMELfEVygjuuyU6ZZ0LpZhFHdfmraGeBFLWHNxygpGlHHituUyjQ==", | ||||
|       "dependencies": { | ||||
|         "acorn": "6.4.1", | ||||
|         "classnames": "^2.1.1", | ||||
|         "prop-types": "^15.5.10", | ||||
|         "react-transition-group": "^4.4.1" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/react-notifications/node_modules/acorn": { | ||||
|       "version": "6.4.1", | ||||
|       "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", | ||||
|       "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", | ||||
|       "bin": { | ||||
|         "acorn": "bin/acorn" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=0.4.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/react-select": { | ||||
|       "version": "5.6.1", | ||||
|       "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.6.1.tgz", | ||||
| @@ -4571,9 +4600,9 @@ | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "json5": { | ||||
|           "version": "2.2.1", | ||||
|           "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", | ||||
|           "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", | ||||
|           "version": "2.2.3", | ||||
|           "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", | ||||
|           "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", | ||||
|           "peer": true | ||||
|         }, | ||||
|         "semver": { | ||||
| @@ -5563,6 +5592,11 @@ | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "classnames": { | ||||
|       "version": "2.3.2", | ||||
|       "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", | ||||
|       "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" | ||||
|     }, | ||||
|     "client-only": { | ||||
|       "version": "0.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", | ||||
| @@ -6676,9 +6710,9 @@ | ||||
|       "dev": true | ||||
|     }, | ||||
|     "json5": { | ||||
|       "version": "1.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", | ||||
|       "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", | ||||
|       "version": "1.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", | ||||
|       "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "minimist": "^1.2.0" | ||||
| @@ -7203,6 +7237,24 @@ | ||||
|       "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", | ||||
|       "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" | ||||
|     }, | ||||
|     "react-notifications": { | ||||
|       "version": "1.7.4", | ||||
|       "resolved": "https://registry.npmjs.org/react-notifications/-/react-notifications-1.7.4.tgz", | ||||
|       "integrity": "sha512-dsR7mUQfe8YdFLqVsjT0GFd4n26UWkzefdjMELfEVygjuuyU6ZZ0LpZhFHdfmraGeBFLWHNxygpGlHHituUyjQ==", | ||||
|       "requires": { | ||||
|         "acorn": "6.4.1", | ||||
|         "classnames": "^2.1.1", | ||||
|         "prop-types": "^15.5.10", | ||||
|         "react-transition-group": "^4.4.1" | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "acorn": { | ||||
|           "version": "6.4.1", | ||||
|           "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", | ||||
|           "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==" | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "react-select": { | ||||
|       "version": "5.6.1", | ||||
|       "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.6.1.tgz", | ||||
|   | ||||
| @@ -14,6 +14,7 @@ | ||||
|     "next": "13.0.0", | ||||
|     "react": "18.2.0", | ||||
|     "react-dom": "18.2.0", | ||||
|     "react-notifications": "^1.7.4", | ||||
|     "react-select": "^5.6.1" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|   | ||||
| @@ -1,7 +1,9 @@ | ||||
| import Head from 'next/head' | ||||
| import { useState, useEffect } from 'react' | ||||
| import { useState, useEffect, useRef } from 'react' | ||||
| import { saveAs } from 'file-saver'; | ||||
| import CreatableSelect from 'react-select/creatable'; | ||||
| import Select from 'react-select'; | ||||
| import { useRouter } from 'next/router' | ||||
| 
 | ||||
| export default function AddApp() { | ||||
| 
 | ||||
| @@ -27,6 +29,10 @@ export default function AddApp() { | ||||
|     if (icon) { | ||||
|       folder.file(application.image_src, icon.file) | ||||
|     } | ||||
|     else if (inlineImage) { | ||||
|       const promise = fetch(inlineImage).then(response => response.blob()) | ||||
|       folder.file(application.image_src, promise) | ||||
|     } | ||||
|     zip.generateAsync({ type: "blob" }) | ||||
|       .then(function (content) { | ||||
|         // Force down of the Zip file
 | ||||
| @@ -34,36 +40,76 @@ export default function AddApp() { | ||||
|       }); | ||||
|   } | ||||
| 
 | ||||
|   const name = useRef(null); | ||||
|   const friendly_name = useRef(null); | ||||
|   const description = useRef(null); | ||||
| 
 | ||||
|   const [categories, setCategories] = useState(null) | ||||
|   const [architecture, setArchitecture] = useState(null) | ||||
|   const [icon, setIcon] = useState(null) | ||||
|   const [ext, setExt] = useState('png') | ||||
|   const [inlineImage, setInlineImage] = useState(null) | ||||
| 
 | ||||
|   const [application, setApplication] = useState({ | ||||
|     friendly_name: null, | ||||
|     image_src: null, | ||||
|     description: null, | ||||
|     name: null, | ||||
|     cores: 2, | ||||
|     memory: 2768, | ||||
|     cores: 1, | ||||
|     memory: 1024, | ||||
|     gpu_count: 0, | ||||
|     cpu_allocation_method: "Inherit", | ||||
|     docker_registry: "https://index.docker.io/v1/", | ||||
|     volume_mappings: "{}", | ||||
|     run_config: "{}", | ||||
|     exec_config: "{}", | ||||
|     categories: [], | ||||
|     require_gpu: false, | ||||
|     enabled: true, | ||||
|     restrict_to_network: false, | ||||
|     restrict_network_names: "[]", | ||||
|     allow_network_selection: false, | ||||
|     notes: null, | ||||
|     image_type: 'Container', | ||||
|   }) | ||||
| 
 | ||||
|   const router = useRouter() | ||||
|   const { app } = router.query | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     fetch('../../list.json') | ||||
|       .then((res) => res.json()) | ||||
|       .then((apps) => { | ||||
|         if (app && app[0]) { | ||||
|           const appDetails = apps.apps.find(el => el.name === atob(app[0])) | ||||
|           delete appDetails['sha'] | ||||
|           description.current.value = appDetails.description | ||||
|           name.current.value = appDetails.name | ||||
|           friendly_name.current.value = appDetails.friendly_name | ||||
|           if (appDetails.categories) { | ||||
|             let catMap = [] | ||||
|             appDetails.categories.map((e) => catMap.push({ | ||||
|               label: e, | ||||
|               value: e, | ||||
|             })) | ||||
|             setCategories(catMap) | ||||
|           } | ||||
|           if (appDetails.architecture) { | ||||
|             let archMap = [] | ||||
|             appDetails.architecture.map((e) => archMap.push({ | ||||
|               label: e, | ||||
|               value: e, | ||||
|             })) | ||||
|             setArchitecture(archMap) | ||||
|           } | ||||
| 
 | ||||
|           setInlineImage('../../icons/' + appDetails.image_src) | ||||
| 
 | ||||
|           setApplication({ | ||||
|             ...application, | ||||
|             ...appDetails | ||||
|           }) | ||||
|         } | ||||
|       }) | ||||
|   }, [app]) | ||||
| 
 | ||||
|   const displayApplication = () => { | ||||
|     return { | ||||
|       ...application, | ||||
|       categories: JSON.stringify(application.categories) | ||||
|       // categories: JSON.stringify(application.categories)
 | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| @@ -98,6 +144,26 @@ export default function AddApp() { | ||||
|     } | ||||
|     updateapp.categories = items.map(cat => cat.value) | ||||
|     setApplication(updateapp) | ||||
|     let catMap = [] | ||||
|     updateapp.categories.map((e) => catMap.push({ | ||||
|       label: e, | ||||
|       value: e, | ||||
|     })) | ||||
|     setCategories(catMap) | ||||
|   } | ||||
| 
 | ||||
|   const updateArchitecture = (items) => { | ||||
|     const updateapp = { | ||||
|       ...application | ||||
|     } | ||||
|     updateapp.architecture = items.map(arch => arch.value) | ||||
|     setApplication(updateapp) | ||||
|     let archMap = [] | ||||
|     updateapp.architecture.map((e) => archMap.push({ | ||||
|       label: e, | ||||
|       value: e, | ||||
|     })) | ||||
|     setArchitecture(archMap) | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
| @@ -154,7 +220,7 @@ export default function AddApp() { | ||||
|             <p className='mb-6 opacity-70'>Select the image to use, image will be renamed when it's downloaded.</p> | ||||
| 
 | ||||
|             <label className='mb-2 font-medium'>Friendly Name</label> | ||||
|             <input name="friendly_name" onChange={handleChange} className='mb-2 p-2 rounded-lg bg-slate-100 border border-solid border-slate-400' /> | ||||
|             <input ref={friendly_name} name="friendly_name" onChange={handleChange} className='mb-2 p-2 rounded-lg bg-slate-100 border border-solid border-slate-400' /> | ||||
|             <p className='mb-6 opacity-70'>This is the name that will show for users</p> | ||||
| 
 | ||||
|             <label className='mb-2 font-medium'>Categories</label> | ||||
| @@ -164,23 +230,38 @@ export default function AddApp() { | ||||
|               options={options} | ||||
|               onChange={updateCategories} | ||||
|               styles={customStyles} | ||||
|               value={categories} | ||||
|             /> | ||||
|             <p className='mb-6 mt-2 opacity-70'>You can select from the available option or create new ones.</p> | ||||
| 
 | ||||
|             <label className='mb-2 font-medium'>Description</label> | ||||
|             <input name="description" onChange={handleChange} className='mb-2 p-2 rounded-lg bg-slate-100 border border-solid border-slate-400' /> | ||||
|             <input ref={description} name="description" onChange={handleChange} className='mb-2 p-2 rounded-lg bg-slate-100 border border-solid border-slate-400' /> | ||||
|             <p className='mb-6 opacity-70'>A short description about the application</p> | ||||
| 
 | ||||
|             <label className='mb-2 font-medium'>Docker Image</label> | ||||
|             <input name="name" onChange={handleChange} className='mb-2 p-2 rounded-lg bg-slate-100 border border-solid border-slate-400' /> | ||||
|             <input ref={name} name="name" onChange={handleChange} className='mb-2 p-2 rounded-lg bg-slate-100 border border-solid border-slate-400' /> | ||||
|             <p className='mb-6 opacity-70'>The docker image to use, i.e. <code className='text-xs p-1 px-2 rounded bg-white/40'>kasmweb/filezilla:develop</code></p> | ||||
| 
 | ||||
|             <label className='mb-2 font-medium'>Architecture</label> | ||||
|             <Select | ||||
|               name="architecture" | ||||
|               isMulti | ||||
|               options={[ | ||||
|                 { value: 'amd64', label: 'amd64' }, | ||||
|                 { value: 'arm64', label: 'arm64' }, | ||||
|               ]} | ||||
|               onChange={updateArchitecture} | ||||
|               styles={customStyles} | ||||
|               value={architecture} | ||||
|             /> | ||||
|             <p className='mb-6 mt-2 opacity-70'>You can select from the available option or create new ones.</p> | ||||
| 
 | ||||
|           </div> | ||||
|         </div> | ||||
|         <div className='w-full lg:w-1/2 p-16 bg-slate-100'> | ||||
|           <App app={application} icon={icon} /> | ||||
|           <App app={application} icon={icon} inlineImage={inlineImage} /> | ||||
|           <pre className='my-8 overflow-y-auto text-xs'>{JSON.stringify(displayApplication(), null, 2)}</pre> | ||||
|           <button onClick={downloadZip} className='p-4 relative z-10 px-5 bg-emerald-600 m-2 rounded items-center text-white/70 flex cursor-pointer'>Download</button> | ||||
|           <button onClick={downloadZip} className='p-4 relative z-10 px-5 bg-cyan-700 border-t border-white/20 border-solid hover:bg-slate-900 transition m-2 rounded items-center text-white/70 flex cursor-pointer'>Download</button> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
| @@ -189,7 +270,7 @@ export default function AddApp() { | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| function App({ app, icon }) { | ||||
| function App({ app, icon, inlineImage }) { | ||||
| 
 | ||||
|   const [showDescription, setShowDescription] = useState(false); | ||||
| 
 | ||||
| @@ -217,16 +298,20 @@ function App({ app, icon }) { | ||||
|     <div className={"rounded-xl group w-full shadow max-w-xs relative overflow-hidden h-[100px] border border-solid flex flex-col justify-between bg-slate-300 border-slate-400/50"}> | ||||
|       <div className={"absolute top-0 left-0 right-0 h-[200px] transition-all" + (showDescription ? ' -translate-y-1/2' : '')}> | ||||
|         <div onClick={() => setShowDescription(true)} className={"h-[100px] p-4 relative overflow-hidden cursor-pointer"}> | ||||
|           <img className="h-[90px] group-hover:scale-150 transition-all absolute left-2 top-1" src={app.image_src} alt={app.friendly_name} /> | ||||
|           <img className="h-[90px] group-hover:scale-150 transition-all absolute left-2 top-1" src={app.image_src} onError={(e) => e.target.src = inlineImage} alt={app.friendly_name} /> | ||||
|           <div className="flex-col pl-28"> | ||||
|             <div className="font-bold">{app.friendly_name || 'Friendly Name'}</div> | ||||
|             <div className="text-xs mb-2 flex gap-2">{app.author || 'Unknown'} <span>{official()}</span></div> | ||||
|             <div className="text-xs mb-2 flex gap-2">{process.env.name || 'Unknown'} <span>{official()}</span></div> | ||||
|             <div className=" h-8"></div> | ||||
|           </div> | ||||
| 
 | ||||
|           <div className="absolute bottom-0 left-0 right-0 bg-slate-400/20 h-8 text-[10px] flex items-center justify-center"> | ||||
|             {app.categories.map(cat => ( | ||||
|               <span className="p-2 py-0 m-[1px] inline-block rounded bg-slate-300/90">{cat}</span> | ||||
|             {app.architecture && app.architecture.map((arch, index) => ( | ||||
|               <span key={'arch' + index} className="p-2 py-0 m-[1px] inline-block rounded bg-slate-400/70">{arch}</span> | ||||
|             ))} | ||||
| 
 | ||||
|             {app.categories.map((cat, index) => ( | ||||
|               <span key={'cat' + index} className="p-2 py-0 m-[1px] inline-block rounded bg-slate-300/90">{cat}</span> | ||||
|             ))} | ||||
|           </div> | ||||
|           {appExists && appExists.enabled === true && appExists.available === false && ( | ||||
| @@ -235,7 +320,7 @@ function App({ app, icon }) { | ||||
|         </div> | ||||
|         <div className="h-[100px] text-xs relative p-2 pl-4 flex"> | ||||
|           <button className="absolute right-2 top-2 bg-slate-100 rounded-full flex justify-center items-center h-6 w-6" onClick={() => setShowDescription(false)}> | ||||
|           <svg style={{ height: '14px'}} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M310.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L160 210.7 54.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L114.7 256 9.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 301.3 265.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L205.3 256 310.6 150.6z"/></svg>   | ||||
|             <svg style={{ height: '14px' }} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M310.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L160 210.7 54.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L114.7 256 9.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 301.3 265.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L205.3 256 310.6 150.6z" /></svg> | ||||
|           </button> | ||||
|           <div className="flex flex-col flex-grow"><div className="font-bold">{app.friendly_name}</div> {app.description}</div> | ||||
|           <div className="flex flex-col justify-end gap-1"> | ||||
| @@ -10,6 +10,10 @@ body { | ||||
|     font-weight: 400; | ||||
| } | ||||
|  | ||||
| .notification { | ||||
|   box-shadow: none!important; | ||||
| } | ||||
|  | ||||
| .bg-bubbles { | ||||
|     position: absolute; | ||||
|     top: 0; | ||||
|   | ||||
| @@ -610,6 +610,11 @@ acorn@^7.0.0: | ||||
|   resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" | ||||
|   integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== | ||||
|  | ||||
| acorn@6.4.1: | ||||
|   version "6.4.1" | ||||
|   resolved "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz" | ||||
|   integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== | ||||
|  | ||||
| ajv@^6.10.0, ajv@^6.12.4: | ||||
|   version "6.12.6" | ||||
|   resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" | ||||
| @@ -827,6 +832,11 @@ chokidar@^3.5.3: | ||||
|   optionalDependencies: | ||||
|     fsevents "~2.3.2" | ||||
|  | ||||
| classnames@^2.1.1: | ||||
|   version "2.3.2" | ||||
|   resolved "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz" | ||||
|   integrity sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw== | ||||
|  | ||||
| client-only@0.0.1: | ||||
|   version "0.0.1" | ||||
|   resolved "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz" | ||||
| @@ -1749,16 +1759,16 @@ json-stable-stringify-without-jsonify@^1.0.1: | ||||
|   integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== | ||||
|  | ||||
| json5@^1.0.1: | ||||
|   version "1.0.1" | ||||
|   resolved "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz" | ||||
|   integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== | ||||
|   version "1.0.2" | ||||
|   resolved "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz" | ||||
|   integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== | ||||
|   dependencies: | ||||
|     minimist "^1.2.0" | ||||
|  | ||||
| json5@^2.2.1: | ||||
|   version "2.2.1" | ||||
|   resolved "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz" | ||||
|   integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== | ||||
|   version "2.2.3" | ||||
|   resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" | ||||
|   integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== | ||||
|  | ||||
| "jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.2: | ||||
|   version "3.3.3" | ||||
| @@ -2164,7 +2174,7 @@ process-nextick-args@~2.0.0: | ||||
|   resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" | ||||
|   integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== | ||||
|  | ||||
| prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.8.1: | ||||
| prop-types@^15.5.10, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.8.1: | ||||
|   version "15.8.1" | ||||
|   resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" | ||||
|   integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== | ||||
| @@ -2201,7 +2211,17 @@ react-is@^16.13.1, react-is@^16.7.0: | ||||
|   resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" | ||||
|   integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== | ||||
|  | ||||
| react-select@*: | ||||
| react-notifications@^1.7.4: | ||||
|   version "1.7.4" | ||||
|   resolved "https://registry.npmjs.org/react-notifications/-/react-notifications-1.7.4.tgz" | ||||
|   integrity sha512-dsR7mUQfe8YdFLqVsjT0GFd4n26UWkzefdjMELfEVygjuuyU6ZZ0LpZhFHdfmraGeBFLWHNxygpGlHHituUyjQ== | ||||
|   dependencies: | ||||
|     acorn "6.4.1" | ||||
|     classnames "^2.1.1" | ||||
|     prop-types "^15.5.10" | ||||
|     react-transition-group "^4.4.1" | ||||
|  | ||||
| react-select@^5.6.1: | ||||
|   version "5.6.1" | ||||
|   resolved "https://registry.npmjs.org/react-select/-/react-select-5.6.1.tgz" | ||||
|   integrity sha512-dYNRswtxUHW+F1Sc0HnxO5ryecPIAsG0+Cwyq5EIXZJBxCxUG2hFfQz41tc++30/2ISuuPglDikc4hEb4NsiuA== | ||||
| @@ -2216,7 +2236,7 @@ react-select@*: | ||||
|     react-transition-group "^4.3.0" | ||||
|     use-isomorphic-layout-effect "^1.1.2" | ||||
|  | ||||
| react-transition-group@^4.3.0: | ||||
| react-transition-group@^4.3.0, react-transition-group@^4.4.1: | ||||
|   version "4.4.5" | ||||
|   resolved "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz" | ||||
|   integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g== | ||||
|   | ||||
		Reference in New Issue
	
	Block a user