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/319 new collection page #433

Merged
merged 32 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
11543e6
feat: initial routing and navigation
g-saracca Jul 8, 2024
a1c1fb7
feat(design system): refactor NavBarDropdownItem to accept as prop an…
g-saracca Jul 8, 2024
2af3e35
feat: items as Links to not refresh page
g-saracca Jul 8, 2024
16b4b52
feat(design system): hasValidation prop
g-saracca Jul 8, 2024
a9af066
feat: initial fields and form setup
g-saracca Jul 8, 2024
8eabb49
feat: field validations
g-saracca Jul 10, 2024
c3340a7
feat(design system): add size prop to Button component
g-saracca Jul 10, 2024
371be44
feat: default values and enhanced identifier/alias field
g-saracca Jul 10, 2024
42af6af
chore: change naming from create to new
g-saracca Jul 11, 2024
b7ffdb0
feat(design system): add autoFocus prop
g-saracca Jul 11, 2024
06c0275
feat (design system): new Stack component
g-saracca Jul 11, 2024
6ac67ad
feat: temporary sections and improvements
g-saracca Jul 11, 2024
77a3107
feat: add use case
g-saracca Jul 11, 2024
850b954
feat: WriteError handler
g-saracca Jul 11, 2024
4ddabd3
feat: show error in alerts and scroll to it
g-saracca Jul 11, 2024
399af84
test: fix role button
g-saracca Jul 11, 2024
dd80bf6
chore: remove unused useTranslation
g-saracca Jul 11, 2024
bdc5435
test: undefined as fallback as prop
g-saracca Jul 12, 2024
d8b1a91
feat: default values and not found page
g-saracca Jul 12, 2024
642b74e
feat: add skeleton
g-saracca Jul 12, 2024
83c9b49
feat: created state and alert
g-saracca Jul 12, 2024
c553178
feat: add stories
g-saracca Jul 12, 2024
bed48f5
feat: match spa collection route
g-saracca Jul 12, 2024
9ce7344
test: initial tests
g-saracca Jul 12, 2024
13b3d2d
test: finish component testing
g-saracca Jul 15, 2024
0247fe8
feat: e2e test and some translations
g-saracca Jul 15, 2024
a1f1184
Merge branch 'develop' into feature/319-new-collection-page
g-saracca Jul 15, 2024
4a3537c
chore: update changes from the style guide
g-saracca Jul 18, 2024
5b05380
chore: rename new to create, folders and files
g-saracca Jul 19, 2024
7475c7a
chore: rename index files to component name
g-saracca Jul 19, 2024
5dc39a1
fix import and prop missing on test breaking lint
g-saracca Jul 19, 2024
60a9260
feat: scroll to top on page render
g-saracca Jul 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ The environment is accessible through the following URLs:
> did not reflect the user's current location within the site, our new SPA design now includes this feature in the breadcrumbs.
> Additionally, we have aligned with best practices by positioning all breadcrumbs at the top, before anything else in the UI.
>
> We have also introduced action items as the last item of the breadcrumb, eg: Collection > Dataset Name > Edit Dataset Metadata
>
> This update gives users a clear indication of their current position within the application's hierarchy.
>
> ### Changes in Functionality & Behavior
Expand All @@ -200,11 +202,17 @@ The environment is accessible through the following URLs:
> search, whose search facets are reduced compared to other in-application searches. Therefore, if we find evidence that
> the assumption is incorrect, we will work on extending the search capabilities to support Solr.
>
> We have also introduced infinite scroll pagination here.
>
> #### Dataverses/Datasets list
>
> The original JSF Dataverses/Datasets list on the home page uses normal paging buttons at the bottom of the list.
> We have implemented infinite scrolling in this list, replacing the normal paging buttons, but the goal would be to be
> able to toggle between normal paging and infinite scrolling via a toggle setting or button.
>
> #### Create/Edit Collection Page Identifier Field
>
> A feature has been added to suggest an identifier to the user based on the collection name entered.

</details>

Expand Down
7 changes: 7 additions & 0 deletions packages/design-system/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
- **Select Multiple:** add is-invalid classname if isInvalid prop is true.
- **Card:** NEW card element to show header and body.
- **ProgressBar:** NEW progress bar element to show progress.
- **NavbarDropdownItem:** Now accepts `as` prop and takes `as` Element props.
- **FormInputGroup:** extend Props Interface to accept `hasValidation` prop to properly show rounded corners in an <InputGroup> with validation
- **Button:** extend Props Interface to accept `size` prop.
- **FormInput:** extend Props Interface to accept `autoFocus` prop.
- **FormTextArea:** extend Props Interface to accept `autoFocus` prop.
- **FormSelect:** extend Props Interface to accept `autoFocus` prop.
- **Stack:** NEW Stack element to manage layouts.

# [1.1.0](https://github.com/IQSS/dataverse-frontend/compare/@iqss/[email protected]...@iqss/[email protected]) (2024-03-12)

Expand Down
4 changes: 4 additions & 0 deletions packages/design-system/src/lib/components/button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import { Button as ButtonBS } from 'react-bootstrap'
import { IconName } from '../icon/IconName'
import { Icon } from '../icon/Icon'

type ButtonSize = 'sm' | 'lg'
type ButtonVariant = 'primary' | 'secondary' | 'link'
type ButtonType = 'button' | 'reset' | 'submit'

interface ButtonProps extends HTMLAttributes<HTMLButtonElement> {
size?: ButtonSize
variant?: ButtonVariant
disabled?: boolean
onClick?: (event: MouseEvent<HTMLButtonElement>) => void
Expand All @@ -18,6 +20,7 @@ interface ButtonProps extends HTMLAttributes<HTMLButtonElement> {
}

export function Button({
size,
variant = 'primary',
disabled = false,
onClick,
Expand All @@ -29,6 +32,7 @@ export function Button({
}: ButtonProps) {
return (
<ButtonBS
size={size}
className={withSpacing ? styles.spacing : ''}
variant={variant}
onClick={disabled ? undefined : onClick}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export interface FormInputProps extends React.HTMLAttributes<FormInputElement> {
disabled?: boolean
value?: string | number
required?: boolean
autoFocus?: boolean
}

export const FormInput = React.forwardRef(function FormInput(
Expand All @@ -24,6 +25,7 @@ export const FormInput = React.forwardRef(function FormInput(
disabled,
value,
required,
autoFocus,
...props
}: FormInputProps,
ref
Expand All @@ -39,6 +41,7 @@ export const FormInput = React.forwardRef(function FormInput(
disabled={disabled}
value={value}
required={required}
autoFocus={autoFocus}
ref={ref as React.ForwardedRef<HTMLInputElement>}
{...props}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,19 @@ export interface FormSelectProps
isInvalid?: boolean
isValid?: boolean
disabled?: boolean
autoFocus?: boolean
}

export const FormSelect = React.forwardRef(function FormSelect(
{ value, isInvalid, isValid, disabled, children, ...props }: PropsWithChildren<FormSelectProps>,
{
value,
isInvalid,
isValid,
disabled,
autoFocus,
children,
...props
}: PropsWithChildren<FormSelectProps>,
ref
) {
return (
Expand All @@ -21,6 +30,7 @@ export const FormSelect = React.forwardRef(function FormSelect(
isInvalid={isInvalid}
isValid={isValid}
disabled={disabled}
autoFocus={autoFocus}
ref={ref as React.ForwardedRef<HTMLSelectElement>}
{...props}>
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ export interface FormTextAreaProps extends Omit<React.HTMLAttributes<FormInputEl
isValid?: boolean
isInvalid?: boolean
value?: string
autoFocus?: boolean
}

export const FormTextArea = React.forwardRef(function FormTextArea(
{ name, disabled, isValid, isInvalid, value, ...props }: FormTextAreaProps,
{ name, disabled, isValid, isInvalid, value, autoFocus, ...props }: FormTextAreaProps,
ref
) {
return (
Expand All @@ -23,6 +24,7 @@ export const FormTextArea = React.forwardRef(function FormTextArea(
isValid={isValid}
isInvalid={isInvalid}
value={value}
autoFocus={autoFocus}
ref={ref as React.ForwardedRef<HTMLTextAreaElement>}
{...props}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,17 @@ import { ReactNode } from 'react'
import { InputGroup } from 'react-bootstrap'
import { FormInputGroupText } from './FormInputGroupText'

function FormInputGroup({ children }: { children: ReactNode }) {
return <InputGroup className="mb-3">{children}</InputGroup>
interface FormInputGroupProps {
children: ReactNode
hasValidation?: boolean
}

function FormInputGroup({ children, hasValidation }: FormInputGroupProps) {
return (
<InputGroup className="mb-3" hasValidation={hasValidation}>
{children}
</InputGroup>
)
}

FormInputGroup.Text = FormInputGroupText
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
import { NavDropdown } from 'react-bootstrap'
import { PropsWithChildren } from 'react'
import { ComponentPropsWithoutRef, ElementType, PropsWithChildren } from 'react'

interface NavbarDropdownItemProps {
href: string
type NavbarDropdownItemProps<T extends ElementType> = {
href?: string
onClick?: () => void
disabled?: boolean
}
as?: T
} & (T extends keyof JSX.IntrinsicElements ? JSX.IntrinsicElements[T] : ComponentPropsWithoutRef<T>)

export function NavbarDropdownItem({
export function NavbarDropdownItem<T extends ElementType = 'a'>({
href,
onClick,
disabled,
children
}: PropsWithChildren<NavbarDropdownItemProps>) {
children,
as,
...props
}: PropsWithChildren<NavbarDropdownItemProps<T>>) {
/* eslint-disable @typescript-eslint/no-explicit-any */
const Component: ElementType<any> | undefined = as

return (
<NavDropdown.Item href={href} onClick={onClick} disabled={disabled}>
<NavDropdown.Item href={href} onClick={onClick} disabled={disabled} as={Component} {...props}>
{children}
</NavDropdown.Item>
)
Expand Down
26 changes: 26 additions & 0 deletions packages/design-system/src/lib/components/stack/Stack.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { ComponentPropsWithoutRef, ElementType } from 'react'
import { Stack as StackBS } from 'react-bootstrap'

type StackProps<T extends ElementType> = {
direction?: 'horizontal' | 'vertical'
gap?: 0 | 1 | 2 | 3 | 4 | 5
as?: T
children: React.ReactNode
} & (T extends keyof JSX.IntrinsicElements ? JSX.IntrinsicElements[T] : ComponentPropsWithoutRef<T>)

export function Stack<T extends ElementType = 'div'>({
direction = 'vertical',
gap = 3,
as,
children,
...rest
}: StackProps<T>) {
/* eslint-disable @typescript-eslint/no-explicit-any */
const Component: ElementType<any> = as || 'div'

return (
<StackBS direction={direction} gap={gap} as={Component} {...rest}>
{children}
</StackBS>
)
}
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 @@ -27,3 +27,4 @@ export { RequiredInputSymbol } from './components/form/required-input-symbol/Req
export { SelectMultiple } from './components/select-multiple/SelectMultiple'
export { Card } from './components/card/Card'
export { ProgressBar } from './components/progress-bar/ProgressBar'
export { Stack } from './components/stack/Stack'
14 changes: 14 additions & 0 deletions packages/design-system/src/lib/stories/button/Button.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,20 @@ export const AllVariantsAtAGlance: Story = {
)
}

export const AllSizesAtAGlance: Story = {
render: () => (
<>
<Button withSpacing size="sm">
Small
</Button>
<Button withSpacing>Default size</Button>
<Button withSpacing size="lg">
Large size
</Button>
</>
)
}

export const Disabled: Story = {
render: () => (
<>
Expand Down
120 changes: 120 additions & 0 deletions packages/design-system/src/lib/stories/stack/Stack.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { CSSProperties } from 'react'
import type { Meta, StoryObj } from '@storybook/react'
import { Stack } from '../../components/stack/Stack'
import { Col } from '../../components/grid/Col'

/**
* ## Description
* Stacks are vertical by default and stacked items are full-width by default. Use the gap prop to add space between items.
*
* Use direction="horizontal" for horizontal layouts. Stacked items are vertically centered by default and only take up their necessary width.
*
* Use the gap prop to add space between items.
*/
const meta: Meta<typeof Stack> = {
tags: ['autodocs'],
title: 'Stack',
component: Stack
}

export default meta
type Story = StoryObj<typeof Stack>

const inlineStyles: CSSProperties = {
backgroundColor: '#337AB7',
color: 'white',
padding: '0.5rem'
}

export const VerticalStack: Story = {
render: () => (
<Stack>
<div style={inlineStyles}>Item 1</div>
<div style={inlineStyles}>Item 2</div>
<div style={inlineStyles}>Item 3</div>
</Stack>
)
}

/**
* Use direction="horizontal" for horizontal layouts.
* Stacked items are vertically centered by default and only take up their necessary width.
*/
export const HorizontalStack: Story = {
render: () => (
<Stack direction="horizontal">
<div style={inlineStyles}>Item 1</div>
<div style={inlineStyles}>Item 2</div>
<div style={inlineStyles}>Item 3</div>
</Stack>
)
}
/**
* By using Columns as childrens of the Stack, you can create a layout with columns that are full-width by default.
*/
export const HorizontalStackWithColumns: Story = {
render: () => (
<Stack direction="horizontal">
<Col style={inlineStyles}>Item 1</Col>
<Col style={inlineStyles}>Item 2</Col>
<Col style={inlineStyles}>Item 3</Col>
</Stack>
)
}
/**
* Gap 0 = 0
*
* Gap 1 = 0.25rem (4px)
*
* Gap 2 = 0.5rem (8px)
*
* Gap 3 = 1rem (16px)
*
* Gap 4 = 1.5rem (24px)
*
* Gap 5 = 3rem (48px)
*/
export const AllGaps: Story = {
render: () => (
<Stack gap={4}>
<Stack direction="horizontal" gap={0}>
<Col style={inlineStyles}>Item 1</Col>
<Col style={inlineStyles}>Item 2</Col>
</Stack>
<Stack direction="horizontal" gap={1}>
<Col style={inlineStyles}>Item 1</Col>
<Col style={inlineStyles}>Item 2</Col>
</Stack>
<Stack direction="horizontal" gap={2}>
<Col style={inlineStyles}>Item 1</Col>
<Col style={inlineStyles}>Item 2</Col>
</Stack>
<Stack direction="horizontal" gap={3}>
<Col style={inlineStyles}>Item 1</Col>
<Col style={inlineStyles}>Item 2</Col>
</Stack>
<Stack direction="horizontal" gap={4}>
<Col style={inlineStyles}>Item 1</Col>
<Col style={inlineStyles}>Item 2</Col>
</Stack>
<Stack direction="horizontal" gap={5}>
<Col style={inlineStyles}>Item 1</Col>
<Col style={inlineStyles}>Item 2</Col>
</Stack>
</Stack>
)
}

/**
* Use `as` prop to render the Stack as a different element.
* If you inspect the rendered HTML, you will see that the Stack is rendered as a section element.
*/
export const StackAsSection: Story = {
render: () => (
<Stack as="section">
<div style={inlineStyles}>Item 1</div>
<div style={inlineStyles}>Item 2</div>
<div style={inlineStyles}>Item 3</div>
</Stack>
)
}
Loading
Loading