Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/381 implement lazy loading #394

Closed
wants to merge 12 commits into from
1 change: 1 addition & 0 deletions packages/design-system/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
- **SelectMultiple:** NEW multiple selector for occasions when you can choose more than one option.
- **FormSelectMultiple:** The new multiple selector is added to the "FormGroup" components.
- **DropdownButtonItem:** extend Props Interface to accept `as` prop.
- **Spinner:** New Spinner component.
- **Accordion:** ability to forward react ref.
- **DynamicFieldsButtons:** Removed from design system.
- **FormGroupWithMultipleFields:** remove withDynamicFields prop and remove logic to handle adding or removing fields.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ $tooltip-max-width: 500px;
// Pagination
@import "bootstrap/scss/pagination";

// Spinner
@import "bootstrap/scss/spinners";

// Navbar

$navbar-light-brand-color: $dv-brand-color;
Expand Down
35 changes: 35 additions & 0 deletions packages/design-system/src/lib/components/spinner/Spinner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { ElementType } from 'react'
import { Spinner as SpinnerBS } from 'react-bootstrap'

type SpinnerVariant =
| 'primary'
| 'secondary'
| 'success'
| 'danger'
| 'warning'
| 'info'
| 'light'
| 'dark'
type SpinnerAnimations = 'border' | 'grow'

interface SpinnerProps {
variant?: SpinnerVariant
animation?: SpinnerAnimations
size?: 'sm'
role?: string
as?: ElementType
}

export const Spinner = ({
variant = 'primary',
animation,
size,
role = 'status',
as
}: SpinnerProps) => {
return (
<SpinnerBS variant={variant} animation={animation} size={size} role={role} as={as}>
<span className="visually-hidden">Loading...</span>
</SpinnerBS>
)
}
1 change: 1 addition & 0 deletions packages/design-system/src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ export { IconName } from './components/icon/IconName'
export { Tooltip } from './components/tooltip/Tooltip'
export { Pagination } from './components/pagination/Pagination'
export { RequiredInputSymbol } from './components/form/required-input-symbol/RequiredInputSymbol'
export { Spinner } from './components/spinner/Spinner'
export { SelectMultiple } from './components/select-multiple/SelectMultiple'
64 changes: 64 additions & 0 deletions packages/design-system/src/lib/stories/spinner/Spinner.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import type { Meta, StoryObj } from '@storybook/react'

import { Spinner } from '../../components/spinner/Spinner'

/**
* ## Description
* The Spinner component is used to indicate a loading state.
*/
const meta: Meta<typeof Spinner> = {
title: 'Spinner',
component: Spinner,
tags: ['autodocs'],
parameters: {
layout: 'centered'
}
}

export default meta
type Story = StoryObj<typeof Spinner>

export const Default: Story = {
render: () => <Spinner variant="primary" />
}

export const AllBorderVariantsAtAGlance: Story = {
render: () => (
<div style={{ display: 'flex', gap: '1rem', alignItems: 'center' }}>
<Spinner animation="border" variant="primary" />
<Spinner animation="border" variant="secondary" />
<Spinner animation="border" variant="success" />
<Spinner animation="border" variant="danger" />
<Spinner animation="border" variant="warning" />
<Spinner animation="border" variant="info" />
<Spinner animation="border" variant="light" />
<Spinner animation="border" variant="dark" />
</div>
)
}

export const AllGrowVariantsAtAGlance: Story = {
render: () => (
<div style={{ display: 'flex', gap: '1rem', alignItems: 'center' }}>
<Spinner animation="grow" variant="primary" />
<Spinner animation="grow" variant="secondary" />
<Spinner animation="grow" variant="success" />
<Spinner animation="grow" variant="danger" />
<Spinner animation="grow" variant="warning" />
<Spinner animation="grow" variant="info" />
<Spinner animation="grow" variant="light" />
<Spinner animation="grow" variant="dark" />
</div>
)
}

export const AllSizesAtAGlance: Story = {
render: () => (
<div style={{ display: 'flex', gap: '1rem', alignItems: 'center' }}>
<Spinner animation="border" variant="primary" size="sm" />
<Spinner animation="border" variant="primary" />
<Spinner animation="grow" variant="primary" size="sm" />
<Spinner animation="grow" variant="primary" />
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Spinner } from '../../../src/lib/components/spinner/Spinner'

describe('Spinner', () => {
it('renders correctly', () => {
cy.mount(<Spinner />)

cy.findAllByRole('status').should('exist')
})
})
77 changes: 65 additions & 12 deletions src/Router.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,42 @@
import { lazy, Suspense } from 'react'
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
import { Layout } from './sections/layout/Layout'
import { Route } from './sections/Route.enum'
import { DatasetFactory } from './sections/dataset/DatasetFactory'
import { PageNotFound } from './sections/page-not-found/PageNotFound'
import { CreateDatasetFactory } from './sections/create-dataset/CreateDatasetFactory'
import { FileFactory } from './sections/file/FileFactory'
import { CollectionFactory } from './sections/collection/CollectionFactory'
import { UploadDatasetFilesFactory } from './sections/upload-dataset-files/UploadDatasetFilesFactory'
import { DatasetNonNumericVersion } from './dataset/domain/models/Dataset'
import { AppLoader } from './sections/shared/layout/AppLoader/AppLoader'
import { PageNotFound } from './sections/page-not-found/PageNotFound'

const DatasetPage = lazy(() =>
import('./sections/dataset/DatasetFactory').then(({ DatasetFactory }) => ({
default: () => DatasetFactory.create()
}))
)

const CreateDatasetPage = lazy(() =>
import('./sections/create-dataset/CreateDatasetFactory').then(({ CreateDatasetFactory }) => ({
default: () => CreateDatasetFactory.create()
}))
)

const FilePage = lazy(() =>
import('./sections/file/FileFactory').then(({ FileFactory }) => ({
default: () => FileFactory.create()
}))
)

const CollectionPage = lazy(() =>
import('./sections/collection/CollectionFactory').then(({ CollectionFactory }) => ({
default: () => CollectionFactory.create()
}))
)

const UploadDatasetFilesPage = lazy(() =>
import('./sections/upload-dataset-files/UploadDatasetFilesFactory').then(
({ UploadDatasetFilesFactory }) => ({
default: () => UploadDatasetFilesFactory.create()
})
)
)

const router = createBrowserRouter(
[
Expand All @@ -18,27 +47,51 @@ const router = createBrowserRouter(
children: [
{
path: Route.HOME,
element: CollectionFactory.create()
element: (
<Suspense fallback={<AppLoader />}>
<CollectionPage />
</Suspense>
)
},
{
path: Route.COLLECTIONS,
element: CollectionFactory.create()
element: (
<Suspense fallback={<AppLoader />}>
<CollectionPage />
</Suspense>
)
},
{
path: Route.DATASETS,
element: DatasetFactory.create()
element: (
<Suspense fallback={<AppLoader />}>
<DatasetPage />
</Suspense>
)
},
{
path: Route.CREATE_DATASET,
element: CreateDatasetFactory.create()
element: (
<Suspense fallback={<AppLoader />}>
<CreateDatasetPage />
</Suspense>
)
},
{
path: Route.UPLOAD_DATASET_FILES,
element: UploadDatasetFilesFactory.create()
element: (
<Suspense fallback={<AppLoader />}>
<UploadDatasetFilesPage />
</Suspense>
)
},
{
path: Route.FILES,
element: FileFactory.create()
element: (
<Suspense fallback={<AppLoader />}>
<FilePage />
</Suspense>
)
}
]
}
Expand Down
3 changes: 2 additions & 1 deletion src/assets/variables.scss
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
$footer-height: 256px;
$body-available-height: calc(100vh - $footer-height);
$body-available-height: calc(100vh - $footer-height);
$header-height: 64px;
8 changes: 4 additions & 4 deletions src/sections/layout/Layout.module.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@import "src/assets/variables";
@import 'src/assets/variables';

.body-container {
min-height: $body-available-height;
margin-top: 64px;
}
min-height: $body-available-height;
margin-top: $header-height;
}
7 changes: 7 additions & 0 deletions src/sections/shared/layout/AppLoader/AppLoader.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@import 'src/assets/variables';

.app-loader {
display: grid;
place-content: center;
min-height: $body-available-height;
}
10 changes: 10 additions & 0 deletions src/sections/shared/layout/AppLoader/AppLoader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Spinner } from '@iqss/dataverse-design-system'
import styles from './AppLoader.module.scss'

export const AppLoader = () => {
return (
<section className={styles['app-loader']}>
<Spinner />
</section>
)
}
Loading