Skip to content

Commit

Permalink
Add close button to error bar (#126)
Browse files Browse the repository at this point in the history
* Error bar close button

* Two changes: refactor to remove useEffect, and report CSS changes to demo (#129)

* refactor to remove useEffect

* report CSS changes to the components demo

* Export ErrorBar for reuse

---------

Co-authored-by: Sylvain Lesage <[email protected]>
  • Loading branch information
platypii and severo authored Dec 12, 2024
1 parent 4100653 commit 2a62e7a
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 26 deletions.
4 changes: 2 additions & 2 deletions apps/hyparquet-demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
"dependencies": {
"@hyparam/components": "0.1.10",
"hightable": "0.7.2",
"hyparquet": "1.6.3",
"hyparquet-compressors": "0.1.4",
"hyparquet": "1.6.4",
"hyparquet-compressors": "1.0.0",
"react": "18.3.1",
"react-dom": "18.3.1"
},
Expand Down
26 changes: 24 additions & 2 deletions apps/hyparquet-demo/src/Layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { cn } from '@hyparam/components'
import { ReactNode, useEffect } from 'react'
import { ReactNode, useEffect, useState } from 'react'

interface LayoutProps {
children: ReactNode
Expand All @@ -20,9 +20,21 @@ interface LayoutProps {
* @returns {ReactNode}
*/
export default function Layout({ children, className, progress, error }: LayoutProps): ReactNode {
const [showError, setShowError] = useState(false)
const errorMessage = error?.toString()
if (error) console.error(error)

// Reset error visibility when error prop changes
useEffect(() => {
if (error) {
setShowError(true)
console.error(error)
} else {
setShowError(false)
}
}, [error])

// Update title
useEffect(() => {
document.title = 'hyparquet demo - apache parquet file viewer online'
}, [])
Expand All @@ -32,7 +44,17 @@ export default function Layout({ children, className, progress, error }: LayoutP
<div className={cn('content', className)}>
{children}
</div>
<div className={cn('error-bar', error && 'show-error')}>{errorMessage}</div>
<div className={cn('error-bar', showError && 'show-error')}>
<div className='error-content'>
<span>{errorMessage}</span>
<button
aria-label='Close error message'
className='close-button'
onClick={() => { setShowError(false) }}>
&times;
</button>
</div>
</div>
</div>
{progress !== undefined && progress < 1 &&
<div className={'progress-bar'} role='progressbar'>
Expand Down
41 changes: 38 additions & 3 deletions apps/hyparquet-demo/src/index.css
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
* {
box-sizing: border-box;
font-family: 'Mulish', 'Helvetica Neue', Helvetica, Arial, sans-serif;
margin: 0;
padding: 0;
}
body {
display: flex;
font-family: sans-serif;
font-family: 'Mulish', 'Helvetica Neue', Helvetica, Arial, sans-serif;
height: 100vh;
width: 100vw;
}
Expand Down Expand Up @@ -156,15 +155,51 @@ main,
padding: 0;
background-color: #dd111199;
font-family: monospace;
overflow-y: auto;
overflow: hidden;
transition: max-height 0.3s;
white-space: pre-wrap;
}
.show-error {
max-height: 30%;
}
.error-content {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 100%;
overflow-y: auto;
padding: 10px;
}

/* error bar close button */
.close-button,
.close-button:active,
.close-button:focus,
.close-button:focus-visible,
.close-button:hover {
background: none;
border: none;
border-radius: 4px;
padding: 0 8px;
cursor: pointer;
color: #333;
font-size: 30px;
display: flex;
align-items: center;
justify-content: center;
transition: background-color 0.2s;
}
button.close-button:active {
background-color: rgba(0, 0, 0, 0.2);
}
button.close-button:focus {
background-color: rgba(0, 0, 0, 0.1);
outline: 2px solid #a44;
}
button.close-button:hover {
background-color: rgba(0, 0, 0, 0.1);
}

.top-header {
align-items: center;
background: linear-gradient(to right, #353540, #24202b);
Expand Down
38 changes: 37 additions & 1 deletion packages/cli/public/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -176,15 +176,51 @@ main {
padding: 0;
background-color: #dd111199;
font-family: monospace;
overflow-y: auto;
overflow: hidden;
transition: max-height 0.3s;
white-space: pre-wrap;
}
.show-error {
max-height: 30%;
}
.error-content {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 100%;
overflow-y: auto;
padding: 10px;
}

/* error bar close button */
.close-button,
.close-button:active,
.close-button:focus,
.close-button:focus-visible,
.close-button:hover {
background: none;
border: none;
border-radius: 4px;
padding: 0 8px;
cursor: pointer;
color: #333;
font-size: 30px;
display: flex;
align-items: center;
justify-content: center;
transition: background-color 0.2s;
}
button.close-button:active {
background-color: rgba(0, 0, 0, 0.2);
}
button.close-button:focus {
background-color: rgba(0, 0, 0, 0.1);
outline: 2px solid #a44;
}
button.close-button:hover {
background-color: rgba(0, 0, 0, 0.1);
}

/* file list */
.file-list {
flex: 1;
Expand Down
38 changes: 37 additions & 1 deletion packages/components/demo/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -170,15 +170,51 @@ main {
padding: 0;
background-color: #dd111199;
font-family: monospace;
overflow-y: auto;
overflow: hidden;
transition: max-height 0.3s;
white-space: pre-wrap;
}
.show-error {
max-height: 30%;
}
.error-content {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 100%;
overflow-y: auto;
padding: 10px;
}

/* error bar close button */
.close-button,
.close-button:active,
.close-button:focus,
.close-button:focus-visible,
.close-button:hover {
background: none;
border: none;
border-radius: 4px;
padding: 0 8px;
cursor: pointer;
color: #333;
font-size: 30px;
display: flex;
align-items: center;
justify-content: center;
transition: background-color 0.2s;
}
button.close-button:active {
background-color: rgba(0, 0, 0, 0.2);
}
button.close-button:focus {
background-color: rgba(0, 0, 0, 0.1);
outline: 2px solid #a44;
}
button.close-button:hover {
background-color: rgba(0, 0, 0, 0.1);
}

/* file list */
.file-list {
flex: 1;
Expand Down
18 changes: 9 additions & 9 deletions packages/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,30 +40,30 @@
},
"dependencies": {
"hightable": "0.7.2",
"hyparquet": "1.6.3",
"hyparquet-compressors": "0.1.4"
"hyparquet": "1.6.4",
"hyparquet-compressors": "1.0.0"
},
"peerDependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@eslint/js": "9.16.0",
"@testing-library/react": "16.0.1",
"@types/node": "22.10.1",
"@types/react": "18.3.12",
"@types/react-dom": "18.3.1",
"@testing-library/react": "16.1.0",
"@types/node": "22.10.2",
"@types/react": "19.0.1",
"@types/react-dom": "19.0.2",
"@vitejs/plugin-react": "4.3.4",
"@vitest/coverage-v8": "2.1.8",
"eslint": "9.16.0",
"eslint-plugin-react": "7.37.2",
"eslint-plugin-react-hooks": "5.0.0",
"eslint-plugin-react-hooks": "5.1.0",
"eslint-plugin-react-refresh": "0.4.16",
"globals": "15.13.0",
"jsdom": "25.0.1",
"typescript": "5.7.2",
"typescript-eslint": "8.17.0",
"vite": "5.4.11",
"typescript-eslint": "8.18.0",
"vite": "6.0.3",
"vitest": "2.1.8"
}
}
33 changes: 27 additions & 6 deletions packages/components/src/components/Layout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ReactNode, useEffect } from 'react'
import { ReactNode, useEffect, useState } from 'react'
import { cn } from '../lib/utils.js'

interface LayoutProps {
Expand All @@ -21,20 +21,17 @@ interface LayoutProps {
* @param props.title - page title
*/
export default function Layout({ children, className, progress, error, title }: LayoutProps) {
const errorMessage = error?.toString()
if (error) console.error(error)

// Update title
useEffect(() => {
document.title = title ? `${title} - hyperparam` : 'hyperparam'
}, [title])

return <main className='main'>
<Sidebar />
<div className='content-container'>
<div className={cn('content', className)}>
{children}
</div>
<div className={cn('error-bar', error !== undefined && 'show-error')}>{errorMessage}</div>
<ErrorBar error={error}></ErrorBar>
</div>
{progress !== undefined && progress < 1 &&
<div className={'progress-bar'} role='progressbar'>
Expand All @@ -53,3 +50,27 @@ function Sidebar() {
export function Spinner({ className }: { className: string }) {
return <div className={cn('spinner', className)}></div>
}

export function ErrorBar({ error }: { error?: Error }) {
const [showError, setShowError] = useState(error !== undefined)
const [prevError, setPrevError] = useState(error)

if (error) console.error(error)
/// Reset error visibility when error prop changes
if (error !== prevError) {
setPrevError(error)
setShowError(error !== undefined)
}

return <div className={cn('error-bar', showError && 'show-error')}>
<div className='error-content'>
<span>{error?.toString()}</span>
<button
aria-label='Close error message'
className='close-button'
onClick={() => { setShowError(false) }}>
&times;
</button>
</div>
</div>
}
4 changes: 2 additions & 2 deletions packages/components/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import Breadcrumb, { BreadcrumbConfig } from './Breadcrumb.js'
import Cell, { CellConfig } from './Cell.js'
import File, { FileConfig } from './File.js'
import Folder, { FolderConfig } from './Folder.js'
import Layout, { Spinner } from './Layout.js'
import Layout, { ErrorBar, Spinner } from './Layout.js'
import Markdown from './Markdown.js'
import Page, { PageConfig } from './Page.js'
export * from './viewers/index.js'
export { Breadcrumb, Cell, File, Folder, Layout, Markdown, Page, Spinner }
export { Breadcrumb, Cell, ErrorBar, File, Folder, Layout, Markdown, Page, Spinner }
export type { BreadcrumbConfig, CellConfig, FileConfig, FolderConfig, PageConfig }

0 comments on commit 2a62e7a

Please sign in to comment.