Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feat: update templates styles and feature (#6071)
Browse files Browse the repository at this point in the history
Recreate #5858;
The style and project creation features of Templates have been implemented.
![image](https://user-images.githubusercontent.com/52877578/227537458-ebb9fa24-ce2b-4235-8f34-1a371a8d1f64.png)
Nctdt authored and Akirathan committed Apr 26, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 7ab60b3 commit c3dbdae
Showing 4 changed files with 216 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -136,7 +136,7 @@ export const PLAY_ICON = (
width={21}
height={21}
rx={10.5}
stroke="#3E515F"
stroke="currentColor"
strokeOpacity={0.1}
strokeWidth={3}
/>
@@ -164,6 +164,25 @@ export const ARROW_UP_ICON = (
</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">
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@ import PermissionDisplay, * as permissionDisplay from './permissionDisplay'
import Ide from './ide'
import ProjectActionButton from './projectActionButton'
import Rows from './rows'
import Templates from './templates'
import TopBar from './topBar'

// =============
@@ -232,13 +233,6 @@ function Dashboard(props: DashboardProps) {
const directory = directoryStack[directoryStack.length - 1]
const parentDirectory = directoryStack[directoryStack.length - 2]

// The purpose of this effect is to enable search action.
react.useEffect(() => {
return () => {
// TODO
}
}, [searchVal])

/** React components for the name column. */
const nameRenderers: {
[Type in backend.AssetType]: (asset: backend.Asset<Type>) => JSX.Element
@@ -329,6 +323,63 @@ function Dashboard(props: DashboardProps) {
})()
}, [accessToken, directoryId])

const getNewProjectName = (templateName?: string | null): string => {
const prefix = `${templateName ?? 'New_Project'}_`
const projectNameTemplate = new RegExp(`^${prefix}(?<projectIndex>\\d+)$`)
let highestProjectIndex = 0
for (const projectAsset of projectAssets) {
let projectIndex = projectNameTemplate.exec(projectAsset.title)?.groups?.projectIndex
if (projectIndex) {
highestProjectIndex = Math.max(highestProjectIndex, parseInt(projectIndex, 10))
}
}
return `${prefix}${highestProjectIndex + 1}`
}

const handleCreateProject = async (templateName?: string | null) => {
const projectName = getNewProjectName(templateName)
switch (platform) {
case platformModule.Platform.cloud: {
const body: backend.CreateProjectRequestBody = {
projectName,
}
if (templateName) {
body.projectTemplateName = templateName.replace(/_/g, '').toLocaleLowerCase()
}
const projectAsset = await backendService.createProject(body)
setProjectAssets(oldProjectAssets => [
...oldProjectAssets,
{
type: backend.AssetType.project,
title: projectAsset.name,
id: projectAsset.projectId,
parentId: '',
permissions: [],
},
])
break
}
case platformModule.Platform.desktop: {
const result = await props.projectManager.createProject({
name: newtype.asNewtype<projectManagerModule.ProjectName>(projectName),
...(templateName ? { projectTemplate: templateName } : {}),
})
const newProject = result.result
setProjectAssets(oldProjectAssets => [
...oldProjectAssets,
{
type: backend.AssetType.project,
title: projectName,
id: newProject.projectId,
parentId: '',
permissions: [],
},
])
break
}
}
}

return (
<div className="text-primary text-xs" onClick={unsetModal}>
<div className={tab === Tab.dashboard ? '' : 'hidden'}>
@@ -345,9 +396,7 @@ function Dashboard(props: DashboardProps) {
searchVal={searchVal}
setSearchVal={setSearchVal}
/>
{/* This is a placeholder. When implementing a feature,
* please replace it with the actual element.*/}
<div id="templates" />
<Templates onTemplateClick={handleCreateProject} />
<div className="flex flex-row flex-nowrap">
<h1 className="text-xl font-bold mx-4 self-center">Drive</h1>
<div className="flex flex-row flex-nowrap mx-4">
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/** @file Renders the list of templates from which a project can be created. */
import * as svg from '../../components/svg'

// =================
// === Constants ===
// =================

/**
* Dash border spacing is not supported by native CSS.
* Therefore, use a background image to create the border.
* It is essentially an SVG image that was generated by the website.
* @see {@link https://kovart.github.io/dashed-border-generator}
*/
const BORDER = `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='15%2c 15' stroke-dashoffset='0' stroke-linecap='butt'/%3e%3c/svg%3e")`

// =================
// === Templates ===
// =================

/** Template metadata. */
interface Template {
title: string
description: string
id: string
}

/** All templates for creating projects that have contents. */
const TEMPLATES: Template[] = [
{
title: 'Colorado COVID',
id: 'Colorado_COVID',
description: 'Learn to glue multiple spreadsheets to analyses all your data at once.',
},
{
title: 'KMeans',
id: 'Kmeans',
description: 'Learn where to open a coffee shop to maximize your income.',
},
{
title: 'NASDAQ Returns',
id: 'NASDAQ_Returns',
description: 'Learn how to clean your data to prepare it for advanced analysis.',
},
{
title: 'Restaurants',
id: 'Orders',
description: 'Learn how to clean your data to prepare it for advanced analysis.',
},
{
title: 'Github Stars',
id: 'Stargazers',
description: 'Learn how to clean your data to prepare it for advanced analysis.',
},
]

// =======================
// === TemplatesRender ===
// =======================

/** Render all templates, and a button to create an empty project. */
interface TemplatesRenderProps {
// Later this data may be requested and therefore needs to be passed dynamically.
templates: Template[]
onTemplateClick: (name?: string | null) => void
}

function TemplatesRender(props: TemplatesRenderProps) {
const { templates, onTemplateClick } = props

/** The action button for creating an empty project. */
const CreateEmptyTemplate = (
<button
onClick={() => {
onTemplateClick()
}}
className="h-40 cursor-pointer"
>
<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>
<p className="font-semibold text-sm">New empty project</p>
</div>
</div>
</button>
)

return (
<>
{CreateEmptyTemplate}
{templates.map(template => (
<button
key={template.title}
className="h-40 cursor-pointer"
onClick={() => {
onTemplateClick(template.id)
}}
>
<div className="flex flex-col justify-end h-full w-full rounded-2xl overflow-hidden text-white text-left bg-cover bg-gray-500">
<div className="bg-black bg-opacity-30 px-4 py-2">
<h2 className="text-sm font-bold">{template.title}</h2>
<div className="text-xs h-16 text-ellipsis py-2">
{template.description}
</div>
</div>
</div>
</button>
))}
</>
)
}

// =================
// === Templates ===
// =================

/** The `TemplatesRender`'s container. */
interface TemplatesProps {
onTemplateClick: (name?: string | null) => void
}

function Templates(props: TemplatesProps) {
const { onTemplateClick } = props
return (
<div className="bg-white">
<div className="mx-auto py-2 px-4 sm:py-4 sm:px-6 lg:px-8">
<div className="grid gap-2 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5">
<TemplatesRender templates={TEMPLATES} onTemplateClick={onTemplateClick} />
</div>
</div>
</div>
)
}
export default Templates
4 changes: 4 additions & 0 deletions app/ide-desktop/lib/dashboard/src/tailwind.css
Original file line number Diff line number Diff line change
@@ -69,5 +69,9 @@ body {
.dasharray-100 {
stroke-dasharray: calc(12 * 6.2832) 0;
}

.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='15%2c 15' stroke-dashoffset='0' stroke-linecap='butt'/%3e%3c/svg%3e");
}
}
}

0 comments on commit c3dbdae

Please sign in to comment.