import { useEffect, useMemo, useRef, useState } from 'preact/hooks' import config from '../../Config.js' import type { Project } from '../../contexts/index.js' import { disectFilePath, useLocale, useProject } from '../../contexts/index.js' import type { VersionId } from '../../services/index.js' import { DEFAULT_VERSION, parseSource } from '../../services/index.js' import { message, readZip } from '../../Utils.js' import { Btn, BtnMenu, FileUpload, Octicon, TextInput } from '../index.js' import { Modal } from '../Modal.js' interface Props { onClose: () => unknown, } export function ProjectCreation({ onClose }: Props) { const { locale } = useLocale() const { projects, createProject, changeProject, updateProject } = useProject() const [name, setName] = useState('') const [namespace, setNamespace] = useState('') const [version, setVersion] = useState(DEFAULT_VERSION) const [file, setFile] = useState(undefined) const [creating, setCreating] = useState(false) const onUpload = (file: File) => { if (file.type.match(/^application\/(x-)?zip(-compressed)?$/)) { if (name.length === 0) { setName(file.name .replace(/\.zip$/, '') .replaceAll(/[ _-]+/g, ' ')) } setFile(file) } } const projectUpdater = useRef(updateProject) useEffect(() => { projectUpdater.current = updateProject }, [updateProject]) const onCreate = () => { setCreating(true) createProject(name, namespace || undefined, version) changeProject(name) if (file) { readZip(file).then(async (entries) => { const project: Partial = { files: [] } await Promise.all(entries.map(async (entry) => { const file = disectFilePath(entry[0], version) if (file) { try { const text = await parseSource(entry[1], 'json') const data = JSON.parse(text) project.files!.push({ ...file, data }) return } catch (e) { console.warn(`Failed parsing ${file.type} ${file.id}: ${message(e)}`) } } if (project.unknownFiles === undefined) { project.unknownFiles = [] } project.unknownFiles.push({ path: entry[0], data: entry[1] }) })) projectUpdater.current(project) onClose() }).catch(() => { onClose() }) } else { onClose() } } const invalidName = useMemo(() => { return projects.map(p => p.name.trim().toLowerCase()).includes(name.trim().toLowerCase()) }, [projects, name]) const invalidNamespace = useMemo(() => { return !(namespace.length === 0 || namespace.match(/^(?:[a-z0-9._-]+:)?[a-z0-9/._-]+$/)) }, [namespace]) const versions = config.versions.map(v => v.id as VersionId).reverse() return

{locale('project.create')}

{!creating && invalidName &&
{Octicon.issue_opened}
}
{!creating && invalidNamespace &&
{Octicon.issue_opened}
}
{versions.map(v => setVersion(v)} /> )}
}