Extract SVGs to files (#7076)

* Extract SVGs to individual files

Probably not working for cloud frontend (`watch-dashboard`, `build-dashboard`) yet

Dynamic SVGs were not extracted out

* Make file SVGs work for `watch-dashboard` and `build-dashboard`

* Document SVG loaders

* Address QA issues
This commit is contained in:
somebody1234 2023-06-23 18:47:04 +10:00 committed by GitHub
parent 64204a1b3c
commit 74527eaa8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 396 additions and 384 deletions

View File

@ -28,7 +28,7 @@ const NAME = 'enso'
* `yargs` and `react-hot-toast` are modules we explicitly want the default imports of.
* `node:process` is here because `process.on` does not exist on the namespace import. */
const DEFAULT_IMPORT_ONLY_MODULES =
'node:process|chalk|string-length|yargs|yargs\\u002Fyargs|sharp|to-ico|connect|morgan|serve-static|create-servers|electron-is-dev|fast-glob|esbuild-plugin-.+|opener|tailwindcss.*'
'node:process|chalk|string-length|yargs|yargs\\u002Fyargs|sharp|to-ico|connect|morgan|serve-static|create-servers|electron-is-dev|fast-glob|esbuild-plugin-.+|opener|tailwindcss.*|enso-assets.*'
const ALLOWED_DEFAULT_IMPORT_MODULES = `${DEFAULT_IMPORT_ONLY_MODULES}|postcss|react-hot-toast`
const OUR_MODULES = 'enso-content-config|enso-common|enso-common\\u002Fsrc\\u002Fdetect'
const RELATIVE_MODULES =

View File

@ -0,0 +1,4 @@
<svg height="24" width="24" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
viewBox="0 0 24 24" stroke="currentColor" xmlns="http://www.w3.org/2000/svg">
<path d="M13 9l3 3m0 0l-3 3m3-3H8m13 0a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>

After

Width:  |  Height:  |  Size: 267 B

View File

@ -0,0 +1,3 @@
<svg width="8" height="8" viewBox="-1 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="m0 0 6 4-6 4V0Z" fill="#3e515fe5" fill-opacity="0.7" />
</svg>

After

Width:  |  Height:  |  Size: 168 B

View File

@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="21" height="21" x="1.5" y="1.5" rx="10.5" stroke="#3e515fe5" stroke-opacity="0.1" stroke-width="3" />
<path d="M12 17a1.5 1.5 0 0 1-1.5-1.5V12h3v3.5A1.5 1.5 0 0 1 12 17Z" fill="#3e515fe5" />
<path d="M8.943 12a1 1 0 0 1-.814-1.581l3.057-4.28a1 1 0 0 1 1.628 0l3.056 4.28A1 1 0 0 1 15.057 12H8.943Z"
fill="#3e515fe5" />
</svg>

After

Width:  |  Height:  |  Size: 454 B

View File

@ -0,0 +1,5 @@
<svg height="24" width="24" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
viewBox="0 0 24 24" stroke="currentColor" xmlns="http://www.w3.org/2000/svg">
<path
d="M16 12a4 4 0 10-8 0 4 4 0 008 0zm0 0v1.5a2.5 2.5 0 005 0V12a9 9 0 10-9 9m4.5-1.206a8.959 8.959 0 01-4.5 1.207" />
</svg>

After

Width:  |  Height:  |  Size: 327 B

View File

@ -0,0 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="1" width="12" height="3" fill="#767676" />
<rect x="2" y="6" width="12" height="3" fill="#767676" />
<rect x="2" y="11" width="12" height="3" fill="#767676" />
</svg>

After

Width:  |  Height:  |  Size: 289 B

View File

@ -0,0 +1,7 @@
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="12" fill="#3e515fe5" fill-opacity="0.1" />
<g opacity="0.66" transform="rotate(45 12 12)">
<rect x="11" y="6" width="2" height="12" fill="#3e515fe5" />
<rect x="6" y="11" width="12" height="2" fill="#3e515fe5" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 375 B

View File

@ -0,0 +1,4 @@
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.5 16A2.9 2.9 0 1 1 8 10.5 4 4 0 0 1 15.5 11 2 2 0 0 1 17.5 12 1.9 1.9 0 1 1 18.5 16"
fill="#3e515fe5" />
</svg>

After

Width:  |  Height:  |  Size: 231 B

View File

@ -0,0 +1,5 @@
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M3.5 18.5a1 1 0 0 1 0-2h3.5v-1.5h-3.5a1 1 0 0 1-1-1v-7a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-3.5v1.5h3.5a1 1 0 0 1 0 2ZM4 14a.5.5 0 0 1-.5-.5v-6a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-.5.5ZM17.3 18.5a1 1 0 0 1-1-1v-10.5a1 1 0 0 1 1-1h3a1 1 0 0 1 1 1v10.5a1 1 0 0 1-1 1ZM17.3 9a.3.3 0 1 1 0-.6h3a.3.3 0 1 1 0 .6ZM18.8 16a.7.7 0 1 1 0-1.4.7.7 0 1 1 0 1.4Z"
fill="#3e515fe5" fill-rule="evenodd" />
</svg>

After

Width:  |  Height:  |  Size: 545 B

View File

@ -0,0 +1,4 @@
<svg height="24" width="24" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
viewBox="0 0 24 24" stroke="currentColor" xmlns="http://www.w3.org/2000/svg">
<path d="M18 9v3m0 0v3m0-3h3m-3 0h-3m-2-5a4 4 0 11-8 0 4 4 0 018 0zM3 20a6 6 0 0112 0v1H3v-1z" />
</svg>

After

Width:  |  Height:  |  Size: 294 B

View File

@ -0,0 +1,4 @@
<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
<rect width="100%" height="100%" fill="none" rx="16" ry="16" stroke="#3e515f" stroke-width="4"
stroke-dasharray="11 11" stroke-linecap="butt" />
</svg>

After

Width:  |  Height:  |  Size: 231 B

View File

@ -0,0 +1,5 @@
<svg height="32" width="32" viewBox="2 2 20 20" xmlns="http://www.w3.org/2000/svg">
<path
d="M6 20a10 10 0 0 1 6 -18 10 10 0 0 1 6 18 6 6 0 0 0 -4 -5 4.3 4.3 0 0 0 -2 -8 4.3 4.3 0 0 0 -2 8 6 6 0 0 0 -4 5"
fill="#888888" />
</svg>

After

Width:  |  Height:  |  Size: 249 B

View File

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="-2 -2 20 20" xmlns="http://www.w3.org/2000/svg">
<path
d="M0 7h16v6a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V7Zm0-4h14a2 2 0 0 1 2 2v1H0V3Zm0 0c0-1.1.9-2 2-2h4a2 2 0 0 1 2 2H0Z"
fill="#3e515fe5" fill-opacity="0.4" />
</svg>

After

Width:  |  Height:  |  Size: 269 B

View File

@ -0,0 +1,3 @@
<svg height="16" width="16" viewBox="-1-1 12 12" xmlns="http://www.w3.org/2000/svg">
<path d="M1 3l4 4 4-4" fill="transparent" stroke="#3e515fe5" stroke-linecap="round" />
</svg>

After

Width:  |  Height:  |  Size: 182 B

View File

@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="3" y="12" width="10" height="18" rx="2" transform="rotate(-90 3 12)" fill="#3e515fe5"
fill-opacity="0.2" />
<path d="M11.5 7C12.33 7 13 7.67 13 8.5L13 15L10 15L10 8.5C10 7.67 10.67 7 11.5 7Z" fill="#3e515fe5" />
<path d="M16 15L11.5 21L7.00003 15L16 15Z" fill="#3e515fe5" />
</svg>

After

Width:  |  Height:  |  Size: 406 B

View File

@ -0,0 +1,4 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill="#f9fafb" fill-opacity="0.7" fill-rule="evenodd"
d="M9 0A9 9 0 1 1 9 18 9 9 0 1 1 9 0M7.5 3.5H10.5L10 10.5H8L7.5 3.5ZM8 12L10 12 10 14 8 14" />
</svg>

After

Width:  |  Height:  |  Size: 269 B

View File

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path
d="M6.5 3h8v2a2 2 0 0 0 2 2h2v13a1 1 0 0 1 -1 1h-11a1 1 0 0 1 -1 -1v-16a1 1 0 0 1 1 -1ZM15 3v2a1.5 1.5 0 0 0 1.5 1.5h2"
fill="#3e515fe5" />
</svg>

After

Width:  |  Height:  |  Size: 256 B

View File

@ -0,0 +1,4 @@
<svg height="24" width="24" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
viewBox="0 0 24 24" stroke="currentColor" xmlns="http://www.w3.org/2000/svg">
<path d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1" />
</svg>

After

Width:  |  Height:  |  Size: 302 B

View File

@ -0,0 +1,4 @@
<svg height="24" width="24" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
viewBox="0 0 24 24" stroke="currentColor" xmlns="http://www.w3.org/2000/svg">
<path d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
</svg>

After

Width:  |  Height:  |  Size: 310 B

View File

@ -0,0 +1,6 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.5">
<path d="M11.4142 10L15.6569 14.2426L14.2426 15.6569L10 11.4142L11.4142 10Z" fill="#3e515fe5" />
<circle cx="7" cy="7" r="5" stroke="#3e515fe5" stroke-width="2" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 313 B

View File

@ -0,0 +1,17 @@
{
"name": "enso-assets",
"type": "module",
"version": "1.0.0",
"author": {
"name": "Enso Team",
"email": "contact@enso.org"
},
"homepage": "https://github.com/enso-org/enso/tree/develop/app/ide-desktop/lib/assets",
"repository": {
"type": "git",
"url": "git@github.com:enso-org/enso.git"
},
"bugs": {
"url": "https://github.com/enso-org/enso/issues"
}
}

View File

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="m10.04 7.34 6 3.85a1 1 0 0 1 0 1.68l-6 3.85a1 1 0 0 1-1.54-.84v-7.7a1 1 0 0 1 1.54-.84Z"
fill="#3e515fe5" />
<rect x="1.5" y="1.5" width="21" height="21" rx="10.5" stroke="#3e515fe5" stroke-opacity="0.1" stroke-width="3" />
</svg>

After

Width:  |  Height:  |  Size: 351 B

View File

@ -0,0 +1,7 @@
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="12" fill="#3e515fe5" fill-opacity="0.1" />
<g opacity="0.66">
<rect x="11" y="6" width="2" height="12" fill="#3e515fe5" />
<rect x="6" y="11" width="12" height="2" fill="#3e515fe5" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 346 B

View File

@ -0,0 +1,4 @@
<svg width="80" height="80" viewBox="0 0 24 24" fill="none" stroke-width="0.5" stroke="#3e515fe5"
xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v6m3-3H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>

After

Width:  |  Height:  |  Size: 255 B

View File

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path
d="M10.3 13a4 4 0 1 1 0-2h10a1 1 0 0 1 1 1v3a1 1 0 0 1-2 0v-2h-2v2a1 1 0 0 1-2 0v-2ZM3.5 12a1 1 0 1 1 2 0a1 1 0 1 1-2 0"
fill="#3e515fe5" fill-rule="evenodd" />
</svg>

After

Width:  |  Height:  |  Size: 277 B

View File

@ -0,0 +1,4 @@
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<ellipse cx="8" cy="8" rx="8" ry="7.5" fill="white" />
<path d="M4.17269e-05 16.5L2 10.5L5.50006 14L4.17269e-05 16.5Z" fill="white" />
</svg>

After

Width:  |  Height:  |  Size: 245 B

View File

@ -0,0 +1,7 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="3" y="14" width="12" height="17" rx="2" transform="rotate(-90 3 14)" fill="#3e515fe5"
fill-opacity="0.2" />
<path d="M11.5 21C10.6716 21 10 20.3284 10 19.5L10 11L13 11L13 19.5C13 20.33 12.33 21 11.5 21Z"
fill="#3e515fe5" />
<path d="M7 11L11.5 5L16 11L7 11Z" fill="#3e515fe5" />
</svg>

After

Width:  |  Height:  |  Size: 418 B

View File

@ -106,7 +106,8 @@ export function bundlerOptions(args: Arguments) {
'.css': 'copy',
'.map': 'copy',
'.wasm': 'copy',
'.svg': 'copy',
// The `file` loader copies the file, and replaces the import with the path to the file.
'.svg': 'file',
'.png': 'copy',
'.ttf': 'copy',
},

View File

@ -33,8 +33,7 @@ async function bundle() {
path.resolve(THIS_PATH, 'src', 'index.html'),
path.resolve(THIS_PATH, 'src', 'index.tsx')
)
// eslint-disable-next-line @typescript-eslint/naming-convention
opts.loader = { '.html': 'copy' }
opts.loader['.html'] = 'copy'
await esbuild.build(opts)
return
} catch (error) {

View File

@ -112,6 +112,16 @@ export function bundlerOptions(args: Arguments) {
entryPoints: [path.resolve(THIS_PATH, 'src', 'tailwind.css')],
outdir: outputPath,
outbase: 'src',
loader: {
// The CSS file needs to import a single SVG as a data URL.
// For `bundle.ts` and `watch.ts`, `index.js` also includes various SVG icons
// which need to be bundled.
// The `dataurl` loader replaces the import with the file, as a data URL. Using the
// `file` loader, which copies the file and replaces the import with the path,
// is an option, however this loader avoids adding extra files to the bundle.
// eslint-disable-next-line @typescript-eslint/naming-convention
'.svg': 'dataurl',
},
plugins: [
esbuildPluginNodeModules.NodeModulesPolyfillPlugin(),
esbuildPluginTime(),

View File

@ -3,6 +3,10 @@
import * as react from 'react'
import * as router from 'react-router-dom'
import ArrowRightIcon from 'enso-assets/arrow_right.svg'
import AtIcon from 'enso-assets/at.svg'
import GoBackIcon from 'enso-assets/go_back.svg'
import * as app from '../../components/app'
import * as auth from '../providers/auth'
import * as svg from '../../components/svg'
@ -46,8 +50,9 @@ function ForgotPassword() {
E-Mail Address:
</label>
<div className="relative">
<SvgIcon svg={svg.AT} />
<SvgIcon>
<svg.SvgMask src={AtIcon} />
</SvgIcon>
<Input
id="email"
type="email"
@ -68,7 +73,9 @@ function ForgotPassword() {
}
>
<span className="mr-2 uppercase">Send link</span>
<span>{svg.RIGHT_ARROW}</span>
<span>
<svg.SvgMask src={ArrowRightIcon} />
</span>
</button>
</div>
</form>
@ -81,7 +88,9 @@ function ForgotPassword() {
'text-center'
}
>
<span>{svg.GO_BACK}</span>
<span>
<svg.SvgMask src={GoBackIcon} />
</span>
<span className="ml-2">Go back to login</span>
</router.Link>
</div>

View File

@ -2,6 +2,11 @@
import * as react from 'react'
import * as router from 'react-router-dom'
import ArrowRightIcon from 'enso-assets/arrow_right.svg'
import AtIcon from 'enso-assets/at.svg'
import CreateAccountIcon from 'enso-assets/create_account.svg'
import LockIcon from 'enso-assets/lock.svg'
import * as fontawesomeIcons from '@fortawesome/free-brands-svg-icons'
import * as app from '../../components/app'
@ -52,7 +57,7 @@ function Login() {
}}
className="relative mt-6 border rounded-md py-2 text-sm text-gray-800 bg-gray-100 hover:bg-gray-200"
>
<FontAwesomeIcon icon={fontawesomeIcons.faGithub} />
<FontAwesomeIcon icon={fontawesomeIcons.faGoogle} />
<span>Login with Google</span>
</button>
<button
@ -87,8 +92,9 @@ function Login() {
E-Mail Address:
</label>
<div className="relative">
<SvgIcon svg={svg.AT} />
<SvgIcon>
<svg.SvgMask src={AtIcon} />
</SvgIcon>
<Input
required
id="email"
@ -108,8 +114,9 @@ function Login() {
Password:
</label>
<div className="relative">
<SvgIcon svg={svg.LOCK} />
<SvgIcon>
<svg.SvgMask src={LockIcon} />
</SvgIcon>
<Input
required={true}
id="password"
@ -143,7 +150,9 @@ function Login() {
}
>
<span className="mr-2 uppercase">Login</span>
<span>{svg.RIGHT_ARROW}</span>
<span>
<svg.SvgMask src={ArrowRightIcon} />
</span>
</button>
</div>
</form>
@ -156,7 +165,9 @@ function Login() {
'text-xs text-center'
}
>
<span>{svg.CREATE_ACCOUNT}</span>
<span>
<svg.SvgMask src={CreateAccountIcon} />
</span>
<span className="ml-2">You don&apos;t have an account?</span>
</router.Link>
</div>

View File

@ -3,6 +3,11 @@ import * as react from 'react'
import * as router from 'react-router-dom'
import toast from 'react-hot-toast'
import AtIcon from 'enso-assets/at.svg'
import CreateAccountIcon from 'enso-assets/create_account.svg'
import GoBackIcon from 'enso-assets/go_back.svg'
import LockIcon from 'enso-assets/lock.svg'
import * as app from '../../components/app'
import * as auth from '../providers/auth'
import * as svg from '../../components/svg'
@ -58,8 +63,9 @@ function Registration() {
E-Mail Address:
</label>
<div className="relative">
<SvgIcon svg={svg.AT} />
<SvgIcon>
<svg.SvgMask src={AtIcon} />
</SvgIcon>
<Input
id="email"
type="email"
@ -78,8 +84,9 @@ function Registration() {
Password:
</label>
<div className="relative">
<SvgIcon svg={svg.LOCK} />
<SvgIcon>
<svg.SvgMask src={LockIcon} />
</SvgIcon>
<Input
required
id="password"
@ -101,8 +108,9 @@ function Registration() {
Confirm Password:
</label>
<div className="relative">
<SvgIcon svg={svg.LOCK} />
<SvgIcon>
<svg.SvgMask src={LockIcon} />
</SvgIcon>
<Input
required
id="password_confirmation"
@ -125,7 +133,9 @@ function Registration() {
}
>
<span className="mr-2 uppercase">Register</span>
<span>{svg.CREATE_ACCOUNT}</span>
<span>
<svg.SvgMask src={CreateAccountIcon} />
</span>
</button>
</div>
</form>
@ -138,7 +148,9 @@ function Registration() {
'text-sm text-center'
}
>
<span>{svg.GO_BACK}</span>
<span>
<svg.SvgMask src={GoBackIcon} />
</span>
<span className="ml-2">Already have an account?</span>
</router.Link>
</div>

View File

@ -4,6 +4,11 @@ import * as react from 'react'
import * as router from 'react-router-dom'
import toast from 'react-hot-toast'
import ArrowRightIcon from 'enso-assets/arrow_right.svg'
import AtIcon from 'enso-assets/at.svg'
import GoBackIcon from 'enso-assets/go_back.svg'
import LockIcon from 'enso-assets/lock.svg'
import * as app from '../../components/app'
import * as auth from '../providers/auth'
import * as svg from '../../components/svg'
@ -72,8 +77,9 @@ function ResetPassword() {
E-Mail Address:
</label>
<div className="relative">
<SvgIcon svg={svg.AT} />
<SvgIcon>
<svg.SvgMask src={AtIcon} />
</SvgIcon>
<Input
id="email"
type="email"
@ -92,8 +98,9 @@ function ResetPassword() {
Confirmation Code:
</label>
<div className="relative">
<SvgIcon svg={svg.LOCK} />
<SvgIcon>
<svg.SvgMask src={LockIcon} />
</SvgIcon>
<Input
id="code"
type="text"
@ -112,8 +119,9 @@ function ResetPassword() {
New Password:
</label>
<div className="relative">
<SvgIcon svg={svg.LOCK} />
<SvgIcon>
<svg.SvgMask src={LockIcon} />
</SvgIcon>
<Input
id="new_password"
type="password"
@ -134,8 +142,9 @@ function ResetPassword() {
Confirm New Password:
</label>
<div className="relative">
<SvgIcon svg={svg.LOCK} />
<SvgIcon>
<svg.SvgMask src={LockIcon} />
</SvgIcon>
<Input
id="new_password_confirm"
type="password"
@ -156,7 +165,9 @@ function ResetPassword() {
}
>
<span className="mr-2 uppercase">Reset</span>
<span>{svg.RIGHT_ARROW}</span>
<span>
<svg.SvgMask src={ArrowRightIcon} />
</span>
</button>
</div>
</form>
@ -169,7 +180,9 @@ function ResetPassword() {
'text-center'
}
>
<span>{svg.GO_BACK}</span>
<span>
<svg.SvgMask src={GoBackIcon} />
</span>
<span className="ml-2">Go back to login</span>
</router.Link>
</div>

View File

@ -2,6 +2,9 @@
* registration. */
import * as react from 'react'
import ArrowRightIcon from 'enso-assets/arrow_right.svg'
import AtIcon from 'enso-assets/at.svg'
import * as auth from '../providers/auth'
import * as backendProvider from '../../providers/backend'
import * as svg from '../../components/svg'
@ -41,7 +44,9 @@ function SetUsername() {
>
<div className="flex flex-col mb-6">
<div className="relative">
<SvgIcon svg={svg.AT} />
<SvgIcon>
<svg.SvgMask src={AtIcon} />
</SvgIcon>
<Input
id="username"
@ -63,7 +68,9 @@ function SetUsername() {
}
>
<span className="mr-2 uppercase">Set username</span>
<span>{svg.RIGHT_ARROW}</span>
<span>
<svg.SvgMask src={ArrowRightIcon} />
</span>
</button>
</div>
</form>

View File

@ -1,24 +1,20 @@
/** @file Styled wrapper around SVG images. */
import * as React from 'react'
// ===============
// === SvgIcon ===
// ===============
/** Props for a {@link SvgIcon}. */
export interface SvgIconProps {
svg: JSX.Element
}
export interface SvgIconProps extends React.PropsWithChildren {}
/** A fixed-size container for a SVG image. */
function SvgIcon(props: SvgIconProps) {
const { children } = props
return (
<div
className={
'inline-flex items-center justify-center absolute left-0 top-0 h-full w-10 ' +
'text-gray-400'
}
>
<span>{props.svg}</span>
<div className="inline-flex items-center justify-center absolute left-0 top-0 h-full w-10 text-gray-400">
<span>{children}</span>
</div>
)
}

View File

@ -4,273 +4,10 @@
* the `svg` files when building for Electron. Once the build scripts have been adapted to allow for
* for this, the contents of this file should be moved back to standalone SVG files. */
// =================
// === Constants ===
// =================
export const AT = (
<Svg path="M16 12a4 4 0 10-8 0 4 4 0 008 0zm0 0v1.5a2.5 2.5 0 005 0V12a9 9 0 10-9 9m4.5-1.206a8.959 8.959 0 01-4.5 1.207" />
)
export const LOCK = (
<Svg path="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
)
export const RIGHT_ARROW = <Svg path="M13 9l3 3m0 0l-3 3m3-3H8m13 0a9 9 0 11-18 0 9 9 0 0118 0z" />
export const CREATE_ACCOUNT = (
<Svg path="M18 9v3m0 0v3m0-3h3m-3 0h-3m-2-5a4 4 0 11-8 0 4 4 0 018 0zM3 20a6 6 0 0112 0v1H3v-1z" />
)
export const GO_BACK = (
<Svg path="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1" />
)
// ===================================
// === SVGs with custom formatting ===
// ===================================
/** Icon used to indicate a warning. */
export const EXCLAMATION_ICON = (
<svg width={18} height={18} viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fill="#f9fafb"
fillOpacity={0.7}
fillRule="evenodd"
d="M9 0A9 9 0 1 1 9 18 9 9 0 1 1 9 0M7.5 3.5H10.5L10 10.5H8L7.5 3.5ZM8 12L10 12 10 14 8 14"
/>
</svg>
)
/** Icon representing a file being uploaded. */
export const UPLOAD_ICON = (
<svg width={24} height={24} viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect
x={3}
y={14}
width={12}
height={17}
rx={2}
transform="rotate(-90 3 14)"
fill="currentColor"
fillOpacity={0.2}
/>
<path
d="M11.5 21C10.6716 21 10 20.3284 10 19.5L10 11L13 11L13 19.5C13 20.33 12.33 21 11.5 21Z"
fill="currentColor"
/>
<path d="M7 11L11.5 5L16 11L7 11Z" fill="currentColor" />
</svg>
)
/** Icon representing a file being downloaded. */
export const DOWNLOAD_ICON = (
<svg width={24} height={24} viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect
x={3}
y={12}
width={10}
height={18}
rx={2}
transform="rotate(-90 3 12)"
fill="currentColor"
fillOpacity={0.2}
/>
<path
d="M11.5 7C12.33 7 13 7.67 13 8.5L13 15L10 15L10 8.5C10 7.67 10.67 7 11.5 7Z"
fill="currentColor"
/>
<path d="M16 15L11.5 21L7.00003 15L16 15Z" fill="currentColor" />
</svg>
)
/** Icon representing a directory. */
export const DIRECTORY_ICON = (
<svg width={24} height={24} viewBox="-2 -2 20 20">
<path
d="M0 7h16v6a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V7Zm0-4h14a2 2 0 0 1 2 2v1H0V3Zm0 0c0-1.1.9-2 2-2h4a2 2 0 0 1 2 2H0Z"
fill="currentColor"
fillOpacity={0.4}
/>
</svg>
)
/** Icon representing a secret. */
export const SECRET_ICON = (
<svg width={24} height={24} viewBox="0 0 24 24">
<path
d="M10.3 13a4 4 0 1 1 0-2h10a1 1 0 0 1 1 1v3a1 1 0 0 1-2 0v-2h-2v2a1 1 0 0 1-2 0v-2ZM3.5 12a1 1 0 1 1 2 0a1 1 0 1 1-2 0"
fill="currentColor"
fillRule="evenodd"
/>
</svg>
)
/** Icon representing a file whose filetype does not have an associated icon. */
export const FILE_ICON = (
<svg width={24} height={24} viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path
d="M6.5 3h8v2a2 2 0 0 0 2 2h2v13a1 1 0 0 1 -1 1h-11a1 1 0 0 1 -1 -1v-16a1 1 0 0 1 1 -1ZM15 3v2a1.5 1.5 0 0 0 1.5 1.5h2"
fill="currentColor"
/>
</svg>
)
/** Icon typically indicating that the item on the right is a child of the item on the left. */
export const SMALL_RIGHT_ARROW_ICON = (
<svg width={8} height={8} viewBox="-1 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="m0 0 6 4-6 4V0Z" fill="currentColor" fillOpacity={0.7} />
</svg>
)
/** Displayed when a project is ready to start. */
export const PLAY_ICON = (
<svg width={24} height={24} viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="m10.04 7.34 6 3.85a1 1 0 0 1 0 1.68l-6 3.85a1 1 0 0 1-1.54-.84v-7.7a1 1 0 0 1 1.54-.84Z"
fill="currentColor"
/>
<rect
x={1.5}
y={1.5}
width={21}
height={21}
rx={10.5}
stroke="currentColor"
strokeOpacity={0.1}
strokeWidth={3}
/>
</svg>
)
/** Displayed when a project is ready for opening an IDE. */
export const ARROW_UP_ICON = (
<svg width={24} height={24} viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect
width={21}
height={21}
x={1.5}
y={1.5}
rx={10.5}
stroke="currentColor"
strokeOpacity={0.1}
strokeWidth={3}
/>
<path d="M12 17a1.5 1.5 0 0 1-1.5-1.5V12h3v3.5A1.5 1.5 0 0 1 12 17Z" fill="currentColor" />
<path
d="M8.943 12a1 1 0 0 1-.814-1.581l3.057-4.28a1 1 0 0 1 1.628 0l3.056 4.28A1 1 0 0 1 15.057 12H8.943Z"
fill="currentColor"
/>
</svg>
)
/** `+`-shaped icon representing creation of an item. */
export const ADD_ICON = (
<svg width={18} height={18} viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx={12} cy={12} r={12} fill="currentColor" fillOpacity={0.1} />
<g opacity={0.66}>
<rect x={11} y={6} width={2} height={12} fill="currentColor" />
<rect x={6} y={11} width={12} height={2} fill="currentColor" />
</g>
</svg>
)
/** An icon representing creation of an item. */
export const CIRCLED_PLUS_ICON = (
<svg
xmlns="http://www.w3.org/2000/svg"
width={80}
height={80}
viewBox="0 0 24 24"
fill="none"
strokeWidth={0.5}
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M12 9v6m3-3H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
)
/** Icon with three bars. */
export const BARS_ICON = (
<svg width={16} height={16} viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x={2} y={1} width={12} height={3} fill="#767676" />
<rect x={2} y={6} width={12} height={3} fill="#767676" />
<rect x={2} y={11} width={12} height={3} fill="#767676" />
</svg>
)
/** Icon indicating a search input. */
export const MAGNIFYING_GLASS_ICON = (
<svg width={16} height={16} viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity={0.5}>
<path
d="M11.4142 10L15.6569 14.2426L14.2426 15.6569L10 11.4142L11.4142 10Z"
fill="currentColor"
/>
<circle cx={7} cy={7} r={5} stroke="currentColor" strokeWidth={2} />
</g>
</svg>
)
/** Icon indicating a chat dialog. */
export const SPEECH_BUBBLE_ICON = (
<svg width={16} height={17} viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<ellipse cx={8} cy={8} rx={8} ry={7.5} fill="white" />
<path d="M4.17269e-05 16.5L2 10.5L5.50006 14L4.17269e-05 16.5Z" fill="white" />
</svg>
)
/** `x`-shaped icon representing the closing of a window. */
export const CLOSE_ICON = (
<svg width={18} height={18} viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx={12} cy={12} r={12} fill="currentColor" fillOpacity={0.1} />
<g opacity={0.66} transform="rotate(45 12 12)">
<rect x={11} y={6} width={2} height={12} fill="currentColor" />
<rect x={6} y={11} width={12} height={2} fill="currentColor" />
</g>
</svg>
)
export const CLOUD_ICON = (
<svg width={18} height={18} viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M6.5 16A2.9 2.9 0 1 1 8 10.5 4 4 0 0 1 15.5 11 2 2 0 0 1 17.5 12 1.9 1.9 0 1 1 18.5 16"
fill="currentColor"
/>
</svg>
)
export const COMPUTER_ICON = (
<svg width={18} height={18} viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M3.5 18.5a1 1 0 0 1 0-2h3.5v-1.5h-3.5a1 1 0 0 1-1-1v-7a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1h-3.5v1.5h3.5a1 1 0 0 1 0 2ZM4 14a.5.5 0 0 1-.5-.5v-6a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-.5.5ZM17.3 18.5a1 1 0 0 1-1-1v-10.5a1 1 0 0 1 1-1h3a1 1 0 0 1 1 1v10.5a1 1 0 0 1-1 1ZM17.3 9a.3.3 0 1 1 0-.6h3a.3.3 0 1 1 0 .6ZM18.8 16a.7.7 0 1 1 0-1.4.7.7 0 1 1 0 1.4Z"
fill="currentColor"
fillRule="evenodd"
/>
</svg>
)
/** An icon representing a user without a profile picture. */
export const DEFAULT_USER_ICON = (
<svg height={32} width={32} viewBox="2 2 20 20" xmlns="http://www.w3.org/2000/svg">
<path
d="M6 20a10 10 0 0 1 6 -18 10 10 0 0 1 6 18 6 6 0 0 0 -4 -5 4.3 4.3 0 0 0 -2 -8 4.3 4.3 0 0 0 -2 8 6 6 0 0 0 -4 5"
fill="#888888"
/>
</svg>
)
/** An icon representing a menu that can be expanded downwards. */
export const DOWN_CARET_ICON = (
<svg height={16} width={16} viewBox="-1-1 12 12" xmlns="http://www.w3.org/2000/svg">
<path d="M1 3l4 4 4-4" fill="transparent" stroke="currentColor" strokeLinecap="round" />
</svg>
)
/** Props for a {@link Spinner}. */
export interface SpinnerProps {
size: number
@ -352,31 +89,33 @@ export function StopIcon(props: StopIconProps) {
)
}
// ===========
// === Svg ===
// ===========
// ===============
// === SvgMask ===
// ===============
/** Props for a {@link Svg}. */
export interface SvgProps {
path: string
/** Props for a {@link SvgMask}. */
export interface SvgMaskProps {
/** The URL of the SVG to use as the mask. */
src: string
}
/** Component for rendering SVG icons.
*
* @param props - Extra props for the SVG path. The `props.data` field in particular contains the
* SVG path data. */
function Svg(props: SvgProps) {
/** Use an SVG as a mask. This lets the SVG use the text color (`currentColor`). */
export function SvgMask(props: SvgMaskProps) {
const { src } = props
const urlSrc = `url(${JSON.stringify(src)})`
return (
<svg
className="h-6 w-6"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
viewBox="0 0 24 24"
stroke="currentColor"
<div
style={{
backgroundColor: 'currentcolor',
mask: urlSrc,
// The names come from a third-party API and cannot be changed.
// eslint-disable-next-line @typescript-eslint/naming-convention
WebkitMask: urlSrc,
}}
>
<path d={props.path} />
</svg>
{/* This is required for this component to have the right size. */}
<img src={src} className="opacity-0" />
</div>
)
}

View File

@ -1,8 +1,10 @@
/** @file Managing the logic and displaying the UI for the password change function. */
import * as react from 'react'
import toast from 'react-hot-toast'
import ArrowRightIcon from 'enso-assets/arrow_right.svg'
import LockIcon from 'enso-assets/lock.svg'
import * as auth from '../../authentication/providers/auth'
import * as modalProvider from '../../providers/modal'
import * as svg from '../../components/svg'
@ -10,6 +12,7 @@ import * as validation from '../validation'
import Input from './input'
import Modal from './modal'
import SvgIcon from './svgIcon'
// ==========================
// === ResetPasswordModal ===
@ -61,10 +64,9 @@ function ChangePasswordModal() {
Old Password:
</label>
<div className="relative">
<div className="inline-flex items-center justify-center absolute left-0 top-0 h-full w-10 text-gray-400">
{svg.LOCK}
</div>
<SvgIcon>
<svg.SvgMask src={LockIcon} />
</SvgIcon>
<Input
autoFocus
required
@ -88,10 +90,9 @@ function ChangePasswordModal() {
New Password:
</label>
<div className="relative">
<div className="inline-flex items-center justify-center absolute left-0 top-0 h-full w-10 text-gray-400">
{svg.LOCK}
</div>
<SvgIcon>
<svg.SvgMask src={LockIcon} />
</SvgIcon>
<Input
required
id="new_password"
@ -114,10 +115,9 @@ function ChangePasswordModal() {
Confirm New Password:
</label>
<div className="relative">
<div className="inline-flex items-center justify-center absolute left-0 top-0 h-full w-10 text-gray-400">
{svg.LOCK}
</div>
<SvgIcon>
<svg.SvgMask src={LockIcon} />
</SvgIcon>
<Input
required
id="confirm_new_password"
@ -136,7 +136,9 @@ function ChangePasswordModal() {
className="flex items-center justify-center focus:outline-none text-white text-sm sm:text-base bg-blue-600 hover:bg-blue-700 rounded py-2 w-full transition duration-150 ease-in"
>
<span className="mr-2 uppercase">Reset</span>
<span>{svg.RIGHT_ARROW}</span>
<span>
<svg.SvgMask src={ArrowRightIcon} />
</span>
</button>
</div>
</form>

View File

@ -2,8 +2,9 @@
import * as react from 'react'
import toast from 'react-hot-toast'
import CloseIcon from 'enso-assets/close.svg'
import * as modalProvider from '../../providers/modal'
import * as svg from '../../components/svg'
import Modal from './modal'
@ -58,7 +59,7 @@ function ConfirmDeleteModal(props: ConfirmDeleteModalProps) {
className="relative bg-white shadow-soft rounded-lg w-96 p-2"
>
<button type="button" className="absolute right-0 top-0 m-2" onClick={unsetModal}>
{svg.CLOSE_ICON}
<img src={CloseIcon} />
</button>
Are you sure you want to delete the {assetType} '{name}'?
<div className="m-1">

View File

@ -4,8 +4,9 @@
import * as react from 'react'
import CloseIcon from 'enso-assets/close.svg'
import * as modalProvider from '../../providers/modal'
import * as svg from '../../components/svg'
import Modal from './modal'
@ -46,7 +47,7 @@ function CreateForm(props: CreateFormProps) {
}}
>
<button type="button" className="absolute right-0 m-2" onClick={unsetModal}>
{svg.CLOSE_ICON}
<img src={CloseIcon} />
</button>
<h2 className="inline-block font-semibold m-2">{title}</h2>
{children}

View File

@ -3,6 +3,14 @@
import * as react from 'react'
import toast from 'react-hot-toast'
import ArrowRightSmallIcon from 'enso-assets/arrow_right_small.svg'
import DefaultUserIcon from 'enso-assets/default_user.svg'
import DirectoryIcon from 'enso-assets/directory.svg'
import DownloadIcon from 'enso-assets/download.svg'
import PlusIcon from 'enso-assets/plus.svg'
import SecretIcon from 'enso-assets/secret.svg'
import UploadIcon from 'enso-assets/upload.svg'
import * as common from 'enso-common'
import * as backendModule from '../backend'
@ -14,7 +22,6 @@ import * as localBackend from '../localBackend'
import * as newtype from '../../newtype'
import * as projectManager from '../projectManager'
import * as remoteBackendModule from '../remoteBackend'
import * as svg from '../../components/svg'
import * as uploadMultipleFiles from '../../uploadMultipleFiles'
import * as authProvider from '../../authentication/providers/auth'
@ -602,7 +609,7 @@ function Dashboard(props: DashboardProps) {
enterDirectory(directoryAsset)
}}
>
{svg.DIRECTORY_ICON} <span className="px-2">{directoryAsset.title}</span>
<img src={DirectoryIcon} /> <span className="px-2">{directoryAsset.title}</span>
</div>
),
[backendModule.AssetType.secret]: secret => (
@ -622,7 +629,7 @@ function Dashboard(props: DashboardProps) {
}
}}
>
{svg.SECRET_ICON} <span className="px-2">{secret.title}</span>
<img src={SecretIcon} /> <span className="px-2">{secret.title}</span>
</div>
),
[backendModule.AssetType.file]: file => (
@ -642,7 +649,7 @@ function Dashboard(props: DashboardProps) {
}
}}
>
{fileInfo.fileIcon()} <span className="px-2">{file.title}</span>
<img src={fileInfo.fileIcon()} /> <span className="px-2">{file.title}</span>
</div>
),
}
@ -663,7 +670,7 @@ function Dashboard(props: DashboardProps) {
key={user.user.organization_id}
permissions={PERMISSION[user.permission]}
>
{svg.DEFAULT_USER_ICON}
<img src={DefaultUserIcon} />
</PermissionDisplay>
))}
</>
@ -756,7 +763,7 @@ function Dashboard(props: DashboardProps) {
}
}}
>
{svg.ADD_ICON}
<img src={PlusIcon} />
</button>
</div>
) : (
@ -995,7 +1002,7 @@ function Dashboard(props: DashboardProps) {
<button className="mx-2" onClick={exitDirectory}>
{parentDirectory?.title ?? '/'}
</button>
{svg.SMALL_RIGHT_ARROW_ICON}
<img src={ArrowRightSmallIcon} />
</>
)}
<span className="mx-2">{directory?.title ?? '/'}</span>
@ -1027,7 +1034,7 @@ function Dashboard(props: DashboardProps) {
))
}}
>
{svg.UPLOAD_ICON}
<img src={UploadIcon} />
</button>
<button
className={`mx-1 opacity-50`}
@ -1038,7 +1045,7 @@ function Dashboard(props: DashboardProps) {
/* TODO */
}}
>
{svg.DOWNLOAD_ICON}
<img src={DownloadIcon} />
</button>
</div>
{EXPERIMENTAL.columnModeSwitcher && (

View File

@ -1,7 +1,7 @@
/** @file A label, which may be either user-defined, or a system warning message. */
import * as react from 'react'
import * as svg from '../../components/svg'
import ExclamationIcon from 'enso-assets/exclamation.svg'
// =============
// === Types ===
@ -28,8 +28,16 @@ const CSS_CLASS: Record<Status, string> = {
/** A mapping of label type to its corresponding icon. */
const STATUS_ICON: Record<Status, JSX.Element | null> = {
[Status.none]: null,
[Status.warning]: <div className="m-1">{svg.EXCLAMATION_ICON}</div>,
[Status.severeWarning]: <div className="m-1">{svg.EXCLAMATION_ICON}</div>,
[Status.warning]: (
<div className="m-1">
<img src={ExclamationIcon} />
</div>
),
[Status.severeWarning]: (
<div className="m-1">
<img src={ExclamationIcon} />
</div>
),
}
// =================

View File

@ -2,6 +2,9 @@
import * as react from 'react'
import toast from 'react-hot-toast'
import ArrowUpIcon from 'enso-assets/arrow_up.svg'
import PlayIcon from 'enso-assets/play.svg'
import * as backendModule from '../backend'
import * as backendProvider from '../../providers/backend'
import * as localBackend from '../localBackend'
@ -347,7 +350,7 @@ function ProjectActionButton(props: ProjectActionButtonProps) {
doOpenManually()
}}
>
{svg.PLAY_ICON}
<img src={PlayIcon} />
</button>
)
case backendModule.ProjectState.openInProgress:
@ -381,7 +384,7 @@ function ProjectActionButton(props: ProjectActionButtonProps) {
openIde()
}}
>
{svg.ARROW_UP_ICON}
<img src={ArrowUpIcon} />
</button>
</>
)

View File

@ -2,8 +2,9 @@
import * as react from 'react'
import toast from 'react-hot-toast'
import CloseIcon from 'enso-assets/close.svg'
import * as modalProvider from '../../providers/modal'
import * as svg from '../../components/svg'
import Input from './input'
import Modal from './modal'
@ -62,7 +63,7 @@ function RenameModal(props: RenameModalProps) {
className="relative bg-white shadow-soft rounded-lg w-96 p-2"
>
<button type="button" className="absolute right-0 top-0 m-2" onClick={unsetModal}>
{svg.CLOSE_ICON}
<img src={CloseIcon} />
</button>
What do you want to rename the {assetType} '{name}' to?
<div className="m-2">

View File

@ -0,0 +1,22 @@
/** @file Styled wrapper around SVG images. */
import * as React from 'react'
// ===============
// === SvgIcon ===
// ===============
/** Props for a {@link SvgIcon}. */
export interface SvgIconProps extends React.PropsWithChildren {}
/** A fixed-size container for a SVG image. */
function SvgIcon(props: SvgIconProps) {
const { children } = props
return (
<div className="inline-flex items-center justify-center absolute left-0 top-0 h-full w-10 text-gray-400">
<span>{children}</span>
</div>
)
}
export default SvgIcon

View File

@ -1,5 +1,5 @@
/** @file Renders the list of templates from which a project can be created. */
import * as svg from '../../components/svg'
import PlusCircledIcon from 'enso-assets/plus_circled.svg'
// =================
// === Templates ===
@ -78,7 +78,9 @@ function TemplatesRender(props: TemplatesRenderProps) {
>
<div className="flex h-full w-full border-dashed-custom rounded-2xl text-primary">
<div className="m-auto text-center">
<button>{svg.CIRCLED_PLUS_ICON}</button>
<button>
<img src={PlusCircledIcon} />
</button>
<p className="font-semibold text-sm">New empty project</p>
</div>
</div>

View File

@ -1,9 +1,15 @@
/** @file The top-bar of dashboard. */
import * as react from 'react'
import BarsIcon from 'enso-assets/bars.svg'
import CloudIcon from 'enso-assets/cloud.svg'
import ComputerIcon from 'enso-assets/computer.svg'
import DefaultUserIcon from 'enso-assets/default_user.svg'
import MagnifyingGlassIcon from 'enso-assets/magnifying_glass.svg'
import SpeechBubbleIcon from 'enso-assets/speech_bubble.svg'
import * as backendModule from '../backend'
import * as dashboard from './dashboard'
import * as svg from '../../components/svg'
import * as backendProvider from '../../providers/backend'
import * as modalProvider from '../../providers/modal'
@ -63,7 +69,7 @@ function TopBar(props: TopBarProps) {
: 'opacity-50'
} rounded-full px-1.5 py-1`}
>
{svg.COMPUTER_ICON}
<img src={ComputerIcon} />
</button>
<button
onClick={() => {
@ -75,7 +81,7 @@ function TopBar(props: TopBarProps) {
: 'opacity-50'
} rounded-full px-1.5 py-1`}
>
{svg.CLOUD_ICON}
<img src={CloudIcon} />
</button>
</div>
)}
@ -91,7 +97,9 @@ function TopBar(props: TopBarProps) {
>
{projectName ?? 'Dashboard'}
</span>
<div className="bg-white shadow-soft rounded-full px-1.5 py-1">{svg.BARS_ICON}</div>
<div className="bg-white shadow-soft rounded-full px-1.5 py-1">
<img src={BarsIcon} />
</div>
<span
className={`opacity-50 overflow-hidden transition-width nowrap ${
tab === dashboard.Tab.ide ? 'm-2 w-16' : 'w-0'
@ -101,7 +109,9 @@ function TopBar(props: TopBarProps) {
</span>
</div>
<div className="grow flex items-center bg-label rounded-full px-2">
<div>{svg.MAGNIFYING_GLASS_ICON}</div>
<div>
<img src={MagnifyingGlassIcon} />
</div>
<input
type="text"
size={1}
@ -119,7 +129,9 @@ function TopBar(props: TopBarProps) {
className="flex items-center bg-help rounded-full px-2.5 text-white mx-2"
>
<span className="whitespace-nowrap">help chat</span>
<div className="ml-2">{svg.SPEECH_BUBBLE_ICON}</div>
<div className="ml-2">
<img src={SpeechBubbleIcon} />
</div>
</a>
{/* User profile and menu. */}
<div className="transform w-8">
@ -130,7 +142,7 @@ function TopBar(props: TopBarProps) {
}}
className="rounded-full w-8 h-8 bg-cover cursor-pointer"
>
{svg.DEFAULT_USER_ICON}
<img src={DefaultUserIcon} />
</div>
</div>
</div>

View File

@ -2,11 +2,12 @@
import * as react from 'react'
import toast from 'react-hot-toast'
import CloseIcon from 'enso-assets/close.svg'
import * as backendModule from '../backend'
import * as backendProvider from '../../providers/backend'
import * as fileInfo from '../../fileInfo'
import * as modalProvider from '../../providers/modal'
import * as svg from '../../components/svg'
import Modal from './modal'
@ -67,7 +68,7 @@ function UploadFileModal(props: UploadFileModalProps) {
className="absolute right-0 top-0 m-2"
onClick={unsetModal}
>
{svg.CLOSE_ICON}
<img src={CloseIcon} />
</button>
<div className="m-2">
<label className="w-1/3" htmlFor="uploaded_file_name">

View File

@ -1,5 +1,5 @@
/** @file Utility functions for extracting and manipulating file information. */
import * as svg from './components/svg'
import FileIcon from 'enso-assets/file.svg'
// ================================
// === Extract file information ===
@ -12,7 +12,7 @@ export function fileExtension(fileName: string) {
/** Returns the appropriate icon for a specific file extension. */
export function fileIcon() {
return svg.FILE_ICON
return FileIcon
}
// ===================================

View File

@ -104,7 +104,7 @@ body {
}
.border-dashed-custom {
background-image: url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' fill='none' rx='16' ry='16' stroke='%233e515f' stroke-width='4' stroke-dasharray='11 11' stroke-linecap='butt'/%3e%3c/svg%3e");
background-image: url("enso-assets/dashed_border.svg");
}
}
}

View File

@ -29,8 +29,7 @@ OPTS.entryPoints.push(
)
OPTS.minify = false
OPTS.write = false
// eslint-disable-next-line @typescript-eslint/naming-convention
OPTS.loader = { '.html': 'copy' }
OPTS.loader['.html'] = 'copy'
OPTS.pure.splice(OPTS.pure.indexOf('assert'), 1)
;(OPTS.inject = OPTS.inject ?? []).push(path.resolve(THIS_PATH, '..', '..', 'debugGlobals.ts'))
OPTS.plugins.push({

View File

@ -5,13 +5,13 @@
"name": "Enso Team",
"email": "contact@enso.org"
},
"homepage": "https://github.com/enso-org/ide",
"homepage": "https://github.com/enso-org/enso/tree/develop/app/ide-desktop/lib/icons",
"repository": {
"type": "git",
"url": "git@github.com:enso-org/ide.git"
"url": "git@github.com:enso-org/enso.git"
},
"bugs": {
"url": "https://github.com/enso-org/ide/issues"
"url": "https://github.com/enso-org/enso/issues"
},
"scripts": {
"build": "node src/index.js"

View File

@ -6,6 +6,11 @@
// === Module declarations ===
// ===========================
declare module '*.svg' {
const PATH: string
export default PATH
}
// Required because this is a build artifact, which does not exist on a clean repository.
declare module '*/build.json' {
/** Build metadata generated by the build CLI. */

View File

@ -8,12 +8,13 @@
"name": "root",
"version": "1.0.0",
"workspaces": [
"lib/assets",
"lib/client",
"lib/common",
"lib/content",
"lib/content-config",
"lib/dashboard",
"lib/dashboard/src/authentication",
"lib/content-config",
"lib/esbuild-plugin-copy-directories",
"lib/icons"
],
@ -25,6 +26,10 @@
"eslint-plugin-jsdoc": "^40.0.2"
}
},
"lib/assets": {
"name": "enso-assets",
"version": "1.0.0"
},
"lib/client": {
"name": "enso",
"version": "0.0.0-dev",
@ -7447,6 +7452,10 @@
"resolved": "lib/client",
"link": true
},
"node_modules/enso-assets": {
"resolved": "lib/assets",
"link": true
},
"node_modules/enso-authentication": {
"resolved": "lib/dashboard/src/authentication",
"link": true
@ -20897,6 +20906,9 @@
}
}
},
"enso-assets": {
"version": "file:lib/assets"
},
"enso-authentication": {
"version": "file:lib/dashboard/src/authentication",
"requires": {

View File

@ -16,12 +16,13 @@
"name": "root",
"private": true,
"workspaces": [
"lib/assets",
"lib/client",
"lib/common",
"lib/content",
"lib/content-config",
"lib/dashboard",
"lib/dashboard/src/authentication",
"lib/content-config",
"lib/esbuild-plugin-copy-directories",
"lib/icons"
],