Update UI layout and improve interface responsiveness
Browse files- src/App.tsx +23 -23
- src/Header.tsx +2 -2
- src/components/ModelReadme.tsx +9 -14
- src/components/PipelineSelector.tsx +18 -20
- src/components/Sidebar.tsx +15 -4
- src/components/pipelines/FeatureExtraction.tsx +1 -1
- src/components/pipelines/TextClassification.tsx +1 -1
- src/components/pipelines/TextGeneration.tsx +2 -2
- src/components/pipelines/ZeroShotClassification.tsx +1 -1
- src/contexts/ModelContext.tsx +1 -1
- tsconfig.json +2 -7
src/App.tsx
CHANGED
@@ -13,6 +13,7 @@ import { PipelineLayout } from './components/PipelineLayout'
|
|
13 |
|
14 |
function App() {
|
15 |
const [isSidebarOpen, setIsSidebarOpen] = useState(false)
|
|
|
16 |
const { pipeline, setModels, setModelInfo, modelInfo, setIsFetching } =
|
17 |
useModel()
|
18 |
|
@@ -34,38 +35,28 @@ function App() {
|
|
34 |
}, [setModels, setModelInfo, setIsFetching, pipeline])
|
35 |
|
36 |
return (
|
37 |
-
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
|
38 |
<Header />
|
39 |
<PipelineLayout>
|
40 |
-
<div className="flex h-[calc(100vh-4rem)]">
|
41 |
{/* Header is h-16 = 4rem */}
|
42 |
{/* Main Content */}
|
43 |
<main className="flex-1 overflow-auto">
|
44 |
-
<div className="h-full px-4 sm:px-6 lg:px-8 py-
|
45 |
{/* Mobile menu button */}
|
46 |
-
<div className="
|
47 |
-
<
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
Configuration
|
54 |
-
</button>
|
55 |
-
</div>
|
56 |
-
{/* Model README Button */}
|
57 |
-
<div className="mb-4">
|
58 |
-
{modelInfo?.readme && (
|
59 |
-
<ModelReadme
|
60 |
-
readme={modelInfo.readme}
|
61 |
-
modelName={modelInfo.name}
|
62 |
-
pipeline={pipeline}
|
63 |
-
/>
|
64 |
-
)}
|
65 |
-
</div>
|
66 |
</div>
|
67 |
{/* Pipeline Component */}
|
68 |
<div className="bg-white rounded-lg shadow-sm border overflow-hidden">
|
|
|
|
|
|
|
69 |
{pipeline === 'zero-shot-classification' && (
|
70 |
<ZeroShotClassification />
|
71 |
)}
|
@@ -79,9 +70,18 @@ function App() {
|
|
79 |
<Sidebar
|
80 |
isOpen={isSidebarOpen}
|
81 |
onClose={() => setIsSidebarOpen(false)}
|
|
|
82 |
/>
|
83 |
</div>
|
84 |
</PipelineLayout>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
</div>
|
86 |
)
|
87 |
}
|
|
|
13 |
|
14 |
function App() {
|
15 |
const [isSidebarOpen, setIsSidebarOpen] = useState(false)
|
16 |
+
const [isModalOpen, setIsModalOpen] = useState(false)
|
17 |
const { pipeline, setModels, setModelInfo, modelInfo, setIsFetching } =
|
18 |
useModel()
|
19 |
|
|
|
35 |
}, [setModels, setModelInfo, setIsFetching, pipeline])
|
36 |
|
37 |
return (
|
38 |
+
<div className="relative min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
|
39 |
<Header />
|
40 |
<PipelineLayout>
|
41 |
+
<div className=" flex h-[calc(100vh-4rem)]">
|
42 |
{/* Header is h-16 = 4rem */}
|
43 |
{/* Main Content */}
|
44 |
<main className="flex-1 overflow-auto">
|
45 |
+
<div className="h-full px-4 sm:px-6 lg:px-8 py-2 lg:pr-4 max-w-none">
|
46 |
{/* Mobile menu button */}
|
47 |
+
<div className="absolute right-0 top-16 lg:hidden mb-4">
|
48 |
+
<button
|
49 |
+
onClick={() => setIsSidebarOpen(true)}
|
50 |
+
className="items-center px-2 py-2 bg-white border border-gray-300 rounded-l-lg shadow-sm text-sm font-medium text-gray-700 hover:bg-gray-50"
|
51 |
+
>
|
52 |
+
<Settings className="w-5 h-5" />
|
53 |
+
</button>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
</div>
|
55 |
{/* Pipeline Component */}
|
56 |
<div className="bg-white rounded-lg shadow-sm border overflow-hidden">
|
57 |
+
<p className="text-xs text-gray-400 pl-4 pt-2 mb-[-20px]">
|
58 |
+
{modelInfo?.name}
|
59 |
+
</p>
|
60 |
{pipeline === 'zero-shot-classification' && (
|
61 |
<ZeroShotClassification />
|
62 |
)}
|
|
|
70 |
<Sidebar
|
71 |
isOpen={isSidebarOpen}
|
72 |
onClose={() => setIsSidebarOpen(false)}
|
73 |
+
setIsModalOpen={setIsModalOpen}
|
74 |
/>
|
75 |
</div>
|
76 |
</PipelineLayout>
|
77 |
+
{modelInfo?.readme && (
|
78 |
+
<ModelReadme
|
79 |
+
readme={modelInfo.readme}
|
80 |
+
modelName={modelInfo.name}
|
81 |
+
isModalOpen={isModalOpen}
|
82 |
+
setIsModalOpen={setIsModalOpen}
|
83 |
+
/>
|
84 |
+
)}
|
85 |
</div>
|
86 |
)
|
87 |
}
|
src/Header.tsx
CHANGED
@@ -23,7 +23,7 @@ function Header() {
|
|
23 |
</div>
|
24 |
</div>
|
25 |
</header>
|
26 |
-
)
|
27 |
}
|
28 |
|
29 |
-
export default Header
|
|
|
23 |
</div>
|
24 |
</div>
|
25 |
</header>
|
26 |
+
)
|
27 |
}
|
28 |
|
29 |
+
export default Header
|
src/components/ModelReadme.tsx
CHANGED
@@ -1,17 +1,20 @@
|
|
1 |
-
import { ExternalLink
|
2 |
-
import { useState } from 'react'
|
3 |
import Modal from './Modal'
|
4 |
import MarkdownRenderer from './MarkdownRenderer'
|
5 |
|
6 |
interface ModelReadmeProps {
|
7 |
readme: string
|
8 |
-
pipeline: string
|
9 |
modelName: string
|
|
|
|
|
10 |
}
|
11 |
|
12 |
-
const ModelReadme = ({
|
13 |
-
|
14 |
-
|
|
|
|
|
|
|
15 |
const title = (
|
16 |
<div className="flex items-center space-x-2">
|
17 |
<a
|
@@ -30,14 +33,6 @@ const ModelReadme = ({ readme, pipeline, modelName }: ModelReadmeProps) => {
|
|
30 |
|
31 |
return (
|
32 |
<>
|
33 |
-
<button
|
34 |
-
onClick={() => setIsModalOpen(true)}
|
35 |
-
className="flex items-center w-full px-3 py-2 text-sm text-gray-600 bg-gray-50 rounded-lg border border-gray-200 hover:bg-gray-100 transition-colors"
|
36 |
-
>
|
37 |
-
<FileText className="w-4 h-4 mr-2 flex-shrink-0" />
|
38 |
-
<span className="truncate">View README.md</span>
|
39 |
-
</button>
|
40 |
-
|
41 |
<Modal
|
42 |
isOpen={isModalOpen}
|
43 |
onClose={() => setIsModalOpen(false)}
|
|
|
1 |
+
import { ExternalLink } from 'lucide-react'
|
|
|
2 |
import Modal from './Modal'
|
3 |
import MarkdownRenderer from './MarkdownRenderer'
|
4 |
|
5 |
interface ModelReadmeProps {
|
6 |
readme: string
|
|
|
7 |
modelName: string
|
8 |
+
isModalOpen: boolean
|
9 |
+
setIsModalOpen: (isOpen: boolean) => void
|
10 |
}
|
11 |
|
12 |
+
const ModelReadme = ({
|
13 |
+
readme,
|
14 |
+
modelName,
|
15 |
+
isModalOpen,
|
16 |
+
setIsModalOpen
|
17 |
+
}: ModelReadmeProps) => {
|
18 |
const title = (
|
19 |
<div className="flex items-center space-x-2">
|
20 |
<a
|
|
|
33 |
|
34 |
return (
|
35 |
<>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
<Modal
|
37 |
isOpen={isModalOpen}
|
38 |
onClose={() => setIsModalOpen(false)}
|
src/components/PipelineSelector.tsx
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
import React from 'react'
|
2 |
import {
|
3 |
Listbox,
|
4 |
ListboxOption,
|
@@ -6,43 +6,41 @@ import {
|
|
6 |
ListboxOptions,
|
7 |
Transition
|
8 |
} from '@headlessui/react'
|
9 |
-
import { ChevronDown, Check } from 'lucide-react'
|
10 |
|
11 |
export const supportedPipelines = [
|
12 |
-
'text-classification',
|
13 |
-
'zero-shot-classification',
|
14 |
'text-generation',
|
15 |
-
'summarization',
|
16 |
'feature-extraction',
|
17 |
-
'
|
18 |
'image-classification',
|
19 |
-
'
|
|
|
20 |
'translation'
|
21 |
-
]
|
22 |
|
23 |
interface PipelineSelectorProps {
|
24 |
-
pipeline: string
|
25 |
-
setPipeline: (pipeline: string) => void
|
26 |
}
|
27 |
|
28 |
const PipelineSelector: React.FC<PipelineSelectorProps> = ({
|
29 |
pipeline,
|
30 |
setPipeline
|
31 |
}) => {
|
32 |
-
const selectedPipeline = pipeline
|
33 |
|
34 |
const formatPipelineName = (pipelineId: string) => {
|
35 |
return pipelineId
|
36 |
.split('-')
|
37 |
-
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
38 |
-
.join(' ')
|
39 |
-
}
|
40 |
|
41 |
return (
|
42 |
<div className="relative">
|
43 |
<Listbox value={selectedPipeline} onChange={setPipeline}>
|
44 |
<div className="relative">
|
45 |
-
<ListboxButton className="relative w-full cursor-default rounded-lg bg-white py-2 pl-3 pr-10 text-left focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 sm:text-
|
46 |
<span className="block truncate font-medium">
|
47 |
{formatPipelineName(selectedPipeline)}
|
48 |
</span>
|
@@ -53,7 +51,7 @@ const PipelineSelector: React.FC<PipelineSelectorProps> = ({
|
|
53 |
/>
|
54 |
</span>
|
55 |
</ListboxButton>
|
56 |
-
|
57 |
<Transition
|
58 |
enter="transition duration-100 ease-out"
|
59 |
enterFrom="transform scale-95 opacity-0"
|
@@ -62,7 +60,7 @@ const PipelineSelector: React.FC<PipelineSelectorProps> = ({
|
|
62 |
leaveFrom="transform scale-100 opacity-100"
|
63 |
leaveTo="transform scale-95 opacity-0"
|
64 |
>
|
65 |
-
<ListboxOptions className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base ring-1 ring-black ring-opacity-5 focus:outline-none
|
66 |
{supportedPipelines.map((p) => (
|
67 |
<ListboxOption
|
68 |
key={p}
|
@@ -96,7 +94,7 @@ const PipelineSelector: React.FC<PipelineSelectorProps> = ({
|
|
96 |
</div>
|
97 |
</Listbox>
|
98 |
</div>
|
99 |
-
)
|
100 |
-
}
|
101 |
|
102 |
-
export default PipelineSelector
|
|
|
1 |
+
import React from 'react'
|
2 |
import {
|
3 |
Listbox,
|
4 |
ListboxOption,
|
|
|
6 |
ListboxOptions,
|
7 |
Transition
|
8 |
} from '@headlessui/react'
|
9 |
+
import { ChevronDown, Check } from 'lucide-react'
|
10 |
|
11 |
export const supportedPipelines = [
|
|
|
|
|
12 |
'text-generation',
|
|
|
13 |
'feature-extraction',
|
14 |
+
'zero-shot-classification',
|
15 |
'image-classification',
|
16 |
+
'text-classification',
|
17 |
+
'summarization',
|
18 |
'translation'
|
19 |
+
]
|
20 |
|
21 |
interface PipelineSelectorProps {
|
22 |
+
pipeline: string
|
23 |
+
setPipeline: (pipeline: string) => void
|
24 |
}
|
25 |
|
26 |
const PipelineSelector: React.FC<PipelineSelectorProps> = ({
|
27 |
pipeline,
|
28 |
setPipeline
|
29 |
}) => {
|
30 |
+
const selectedPipeline = pipeline
|
31 |
|
32 |
const formatPipelineName = (pipelineId: string) => {
|
33 |
return pipelineId
|
34 |
.split('-')
|
35 |
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
36 |
+
.join(' ')
|
37 |
+
}
|
38 |
|
39 |
return (
|
40 |
<div className="relative">
|
41 |
<Listbox value={selectedPipeline} onChange={setPipeline}>
|
42 |
<div className="relative">
|
43 |
+
<ListboxButton className="relative w-full cursor-default rounded-lg bg-white py-2 pl-3 pr-10 text-left focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 text-sm xl:text-base border border-gray-300">
|
44 |
<span className="block truncate font-medium">
|
45 |
{formatPipelineName(selectedPipeline)}
|
46 |
</span>
|
|
|
51 |
/>
|
52 |
</span>
|
53 |
</ListboxButton>
|
54 |
+
|
55 |
<Transition
|
56 |
enter="transition duration-100 ease-out"
|
57 |
enterFrom="transform scale-95 opacity-0"
|
|
|
60 |
leaveFrom="transform scale-100 opacity-100"
|
61 |
leaveTo="transform scale-95 opacity-0"
|
62 |
>
|
63 |
+
<ListboxOptions className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-sm xl:text-base ring-1 ring-black ring-opacity-5 focus:outline-none">
|
64 |
{supportedPipelines.map((p) => (
|
65 |
<ListboxOption
|
66 |
key={p}
|
|
|
94 |
</div>
|
95 |
</Listbox>
|
96 |
</div>
|
97 |
+
)
|
98 |
+
}
|
99 |
|
100 |
+
export default PipelineSelector
|
src/components/Sidebar.tsx
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
import { X } from 'lucide-react'
|
2 |
import PipelineSelector from './PipelineSelector'
|
3 |
import ModelSelector from './ModelSelector'
|
4 |
import ModelInfo from './ModelInfo'
|
@@ -10,9 +10,10 @@ import ZeroShotClassificationConfig from './pipelines/ZeroShotClassificationConf
|
|
10 |
interface SidebarProps {
|
11 |
isOpen: boolean
|
12 |
onClose: () => void
|
|
|
13 |
}
|
14 |
|
15 |
-
const Sidebar = ({ isOpen, onClose }: SidebarProps) => {
|
16 |
const { pipeline, setPipeline } = useModel()
|
17 |
|
18 |
return (
|
@@ -51,7 +52,7 @@ const Sidebar = ({ isOpen, onClose }: SidebarProps) => {
|
|
51 |
<div className="flex-1 overflow-y-auto p-4 space-y-6">
|
52 |
{/* Pipeline Selection */}
|
53 |
<div className="space-y-3 flex flex-row items-center space-x-4 text-center">
|
54 |
-
<h3 className="text-lg font-semibold text-gray-900 w-2/5 mt-2">
|
55 |
Choose a Pipeline
|
56 |
</h3>
|
57 |
<div className="w-3/5">
|
@@ -71,8 +72,18 @@ const Sidebar = ({ isOpen, onClose }: SidebarProps) => {
|
|
71 |
</div>
|
72 |
|
73 |
{/* Model Info */}
|
74 |
-
<div className="flex items-center justify-center">
|
75 |
<ModelInfo />
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
</div>
|
77 |
|
78 |
<hr className="border-gray-200" />
|
|
|
1 |
+
import { FileText, X } from 'lucide-react'
|
2 |
import PipelineSelector from './PipelineSelector'
|
3 |
import ModelSelector from './ModelSelector'
|
4 |
import ModelInfo from './ModelInfo'
|
|
|
10 |
interface SidebarProps {
|
11 |
isOpen: boolean
|
12 |
onClose: () => void
|
13 |
+
setIsModalOpen: (isOpen: boolean) => void
|
14 |
}
|
15 |
|
16 |
+
const Sidebar = ({ isOpen, onClose, setIsModalOpen }: SidebarProps) => {
|
17 |
const { pipeline, setPipeline } = useModel()
|
18 |
|
19 |
return (
|
|
|
52 |
<div className="flex-1 overflow-y-auto p-4 space-y-6">
|
53 |
{/* Pipeline Selection */}
|
54 |
<div className="space-y-3 flex flex-row items-center space-x-4 text-center">
|
55 |
+
<h3 className="text-md xl:text-lg font-semibold text-gray-900 w-2/5 mt-2">
|
56 |
Choose a Pipeline
|
57 |
</h3>
|
58 |
<div className="w-3/5">
|
|
|
72 |
</div>
|
73 |
|
74 |
{/* Model Info */}
|
75 |
+
<div className="flex flex-col items-center justify-center">
|
76 |
<ModelInfo />
|
77 |
+
{/* Model README Button */}
|
78 |
+
<div className="mt-4 w-42">
|
79 |
+
<button
|
80 |
+
onClick={() => setIsModalOpen(true)}
|
81 |
+
className="flex items-center w-full px-3 py-2 text-sm text-gray-600 bg-gray-50 rounded-lg border border-gray-200 hover:bg-gray-100 transition-colors"
|
82 |
+
>
|
83 |
+
<FileText className="w-4 h-4 mr-2 flex-shrink-0" />
|
84 |
+
<span className="truncate">View README.md</span>
|
85 |
+
</button>
|
86 |
+
</div>
|
87 |
</div>
|
88 |
|
89 |
<hr className="border-gray-200" />
|
src/components/pipelines/FeatureExtraction.tsx
CHANGED
@@ -224,7 +224,7 @@ function FeatureExtraction() {
|
|
224 |
const busy = status !== 'ready' || isExtracting
|
225 |
|
226 |
return (
|
227 |
-
<div className="flex flex-col h-
|
228 |
<div className="flex items-center justify-between mb-4">
|
229 |
<h1 className="text-2xl font-bold">Feature Extraction (Embeddings)</h1>
|
230 |
<div className="flex gap-2">
|
|
|
224 |
const busy = status !== 'ready' || isExtracting
|
225 |
|
226 |
return (
|
227 |
+
<div className="flex flex-col h-full max-h-[92vh] w-full p-4">
|
228 |
<div className="flex items-center justify-between mb-4">
|
229 |
<h1 className="text-2xl font-bold">Feature Extraction (Embeddings)</h1>
|
230 |
<div className="flex gap-2">
|
src/components/pipelines/TextClassification.tsx
CHANGED
@@ -80,7 +80,7 @@ function TextClassification() {
|
|
80 |
}
|
81 |
|
82 |
return (
|
83 |
-
<div className="flex flex-col h-
|
84 |
<h1 className="text-2xl font-bold mb-4 flex-shrink-0">
|
85 |
Text Classification
|
86 |
</h1>
|
|
|
80 |
}
|
81 |
|
82 |
return (
|
83 |
+
<div className="flex flex-col h-full max-h-[92vh] w-full p-4">
|
84 |
<h1 className="text-2xl font-bold mb-4 flex-shrink-0">
|
85 |
Text Classification
|
86 |
</h1>
|
src/components/pipelines/TextGeneration.tsx
CHANGED
@@ -153,10 +153,10 @@ function TextGeneration() {
|
|
153 |
const hasChatTemplate = modelInfo?.hasChatTemplate
|
154 |
|
155 |
return (
|
156 |
-
<div className="flex flex-col h-[70vh] max-h-[
|
157 |
<div className="flex items-center justify-between mb-4">
|
158 |
<h1 className="text-2xl font-bold">
|
159 |
-
{hasChatTemplate ? 'Chat
|
160 |
</h1>
|
161 |
<div className="flex gap-2">
|
162 |
<button
|
|
|
153 |
const hasChatTemplate = modelInfo?.hasChatTemplate
|
154 |
|
155 |
return (
|
156 |
+
<div className="flex flex-col min-h-[70vh] h-full max-h-[92vh] w-full p-4">
|
157 |
<div className="flex items-center justify-between mb-4">
|
158 |
<h1 className="text-2xl font-bold">
|
159 |
+
Text Generation {hasChatTemplate ? '(Chat)' : ''}
|
160 |
</h1>
|
161 |
<div className="flex gap-2">
|
162 |
<button
|
src/components/pipelines/ZeroShotClassification.tsx
CHANGED
@@ -81,7 +81,7 @@ function ZeroShotClassification() {
|
|
81 |
const busy: boolean = status !== 'ready'
|
82 |
|
83 |
return (
|
84 |
-
<div className="flex flex-col h-full max-h-[
|
85 |
<div className="flex items-center justify-between mb-4">
|
86 |
<h1 className="text-2xl font-bold">Zero-Shot Classification</h1>
|
87 |
</div>
|
|
|
81 |
const busy: boolean = status !== 'ready'
|
82 |
|
83 |
return (
|
84 |
+
<div className="flex flex-col h-full max-h-[92vh] w-full p-4">
|
85 |
<div className="flex items-center justify-between mb-4">
|
86 |
<h1 className="text-2xl font-bold">Zero-Shot Classification</h1>
|
87 |
</div>
|
src/contexts/ModelContext.tsx
CHANGED
@@ -36,7 +36,7 @@ export function ModelProvider({ children }: { children: React.ReactNode }) {
|
|
36 |
const [models, setModels] = useState<ModelInfoResponse[]>(
|
37 |
[] as ModelInfoResponse[]
|
38 |
)
|
39 |
-
const [pipeline, setPipeline] = useState<string>('
|
40 |
const [selectedQuantization, setSelectedQuantization] =
|
41 |
useState<QuantizationType>('int8')
|
42 |
const [activeWorker, setActiveWorker] = useState<Worker | null>(null)
|
|
|
36 |
const [models, setModels] = useState<ModelInfoResponse[]>(
|
37 |
[] as ModelInfoResponse[]
|
38 |
)
|
39 |
+
const [pipeline, setPipeline] = useState<string>('feature-extraction') //text-generation
|
40 |
const [selectedQuantization, setSelectedQuantization] =
|
41 |
useState<QuantizationType>('int8')
|
42 |
const [activeWorker, setActiveWorker] = useState<Worker | null>(null)
|
tsconfig.json
CHANGED
@@ -1,12 +1,7 @@
|
|
1 |
{
|
2 |
"compilerOptions": {
|
3 |
"target": "es2020",
|
4 |
-
"lib": [
|
5 |
-
"dom",
|
6 |
-
"dom.iterable",
|
7 |
-
"esnext",
|
8 |
-
"WebWorker"
|
9 |
-
],
|
10 |
"allowJs": true,
|
11 |
"skipLibCheck": true,
|
12 |
"esModuleInterop": true,
|
@@ -22,4 +17,4 @@
|
|
22 |
"jsx": "react-jsx"
|
23 |
},
|
24 |
"include": ["src", "public/workers"]
|
25 |
-
}
|
|
|
1 |
{
|
2 |
"compilerOptions": {
|
3 |
"target": "es2020",
|
4 |
+
"lib": ["dom", "dom.iterable", "esnext", "WebWorker"],
|
|
|
|
|
|
|
|
|
|
|
5 |
"allowJs": true,
|
6 |
"skipLibCheck": true,
|
7 |
"esModuleInterop": true,
|
|
|
17 |
"jsx": "react-jsx"
|
18 |
},
|
19 |
"include": ["src", "public/workers"]
|
20 |
+
}
|