Skip to content

Commit

Permalink
feat: add collapsible section for secondary information (#839)
Browse files Browse the repository at this point in the history
  • Loading branch information
coderbyheart authored Oct 22, 2024
1 parent 8f3d09c commit c4faef7
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 68 deletions.
47 changes: 18 additions & 29 deletions src/components/ButtonPresses.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Ago } from '#components/Ago.js'
import { useDevice } from '#context/Device.js'
import { isButtonPress, toButtonPress } from '#proto/lwm2m.js'
import { ChevronDownSquareIcon, CircleStop } from 'lucide-preact'
import { ChevronDownSquareIcon } from 'lucide-preact'

import './ButtonPresses.css'

Expand All @@ -11,35 +11,24 @@ export const ButtonPresses = () => {
.filter(isButtonPress)
.map(toButtonPress)[0]

if (buttonPress === undefined) return null
if (Date.now() - buttonPress.ts.getTime() > 60 * 1000) return null

return (
<>
<p class="d-flex">
<CircleStop strokeWidth={1} class="me-2" />
<span>
<span>Press the button on your device to receive them here.</span>
{buttonPress !== undefined &&
Date.now() - buttonPress.ts.getTime() < 60 * 1000 && (
<span class="d-flex">
<small
class="d-flex hot"
key={`button-${buttonPress.ts.getTime()}`}
>
<ChevronDownSquareIcon strokeWidth={1} class="me-1" />
<span data-testid="button-press">
Button <strong>#{buttonPress.id}</strong> pressed
</span>
</small>
<small class="text-muted ms-2">
<Ago
date={buttonPress.ts}
key={buttonPress.ts.toISOString()}
withSeconds
/>
</small>
</span>
)}
<p class="d-flex justify-content-between">
<small class="d-flex hot" key={`button-${buttonPress.ts.getTime()}`}>
<ChevronDownSquareIcon strokeWidth={1} class="me-1" />
<span data-testid="button-press">
Button <strong>#{buttonPress.id}</strong> pressed
</span>
</p>
</>
</small>
<small class="text-muted ms-2">
<Ago
date={buttonPress.ts}
key={buttonPress.ts.toISOString()}
withSeconds
/>
</small>
</p>
)
}
21 changes: 21 additions & 0 deletions src/components/Collapsible.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
section.collapsible > header {
display: flex;
justify-content: space-between;
align-items: flex-start;
}

section.collapsible > header > * {
margin: 0;
}

section.collapsible > header {
margin-bottom: 0.5rem;
}

section.collapsible.collapsed > header {
margin-bottom: 0;
}

section.collapsible > header > button {
padding: 0;
}
47 changes: 47 additions & 0 deletions src/components/Collapsible.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import cx from 'classnames'
import { HelpCircle, X } from 'lucide-preact'
import { nanoid } from 'nanoid'
import type { ComponentChildren } from 'preact'
import { useRef, useState } from 'preact/hooks'

import './Collapsible.css'

export const Collapsible = ({
children,
title,
collapsed,
icon,
class: className,
moreText,
}: {
children: ComponentChildren
title: ComponentChildren
collapsed?: boolean
icon?: ComponentChildren
class?: string
moreText?: string
}) => {
const [isCollapsed, setIsCollapsed] = useState<boolean>(collapsed ?? true)
const id = useRef(nanoid())

return (
<section
class={cx('collapsible', className, { collapsed: isCollapsed })}
id={id.current}
>
<header>
{title}
<button
type="button"
class="btn btn-link"
onClick={() => setIsCollapsed(!isCollapsed)}
title={isCollapsed ? (moreText ?? 'show more') : 'close'}
aria-controls={id.current}
>
{isCollapsed ? icon === undefined ? <HelpCircle /> : icon : <X />}
</button>
</header>
{!isCollapsed && <main>{children}</main>}
</section>
)
}
94 changes: 55 additions & 39 deletions src/model/PCA20065/Card.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Applied } from '#components/Applied.js'
import { ButtonPresses } from '#components/ButtonPresses.js'
import { Collapsible } from '#components/Collapsible.js'
import { LEDPattern } from '#components/LEDPattern.js'
import { ColorPicker } from '#components/colorpicker/ColorPicker.js'
import { RGBtoHEX } from '#components/colorpicker/RGBtoHEX.js'
Expand All @@ -12,7 +13,12 @@ import {
type LwM2MObjectInstance,
type RGBLED_14240,
} from '@hello.nrfcloud.com/proto-map/lwm2m'
import { Lightbulb, LightbulbOff } from 'lucide-preact'
import {
CircleStop,
Lightbulb,
LightbulbOff,
SendHorizonal,
} from 'lucide-preact'
import { useState } from 'preact/hooks'
import { isOff } from '../../utils/isOff.js'

Expand Down Expand Up @@ -83,51 +89,61 @@ export const Card = ({ model }: { model: Model }) => {
)}
{!ledColorPickerVisible && (
<>
<h3>Interact with your device</h3>
<p class="d-flex">
{desiredLEDColor !== undefined && !isOff(desiredLEDColor) && (
<Lightbulb
strokeWidth={2}
class="me-2"
color={RGBtoHEX(desiredLEDColor)}
/>
)}
{!userColor && <LightbulbOff strokeWidth={1} class="me-2" />}
<span>
Click the LED above to change the color on your device.
{desiredLEDColor !== undefined && (
<span>
<br />
<Applied
desired={{
r: desiredLEDColor.r,
g: desiredLEDColor.g,
b: desiredLEDColor.b,
}}
reported={
reportedLEDColor !== undefined
? {
r: reportedLEDColor.r,
g: reportedLEDColor.g,
b: reportedLEDColor.b,
}
: undefined
}
/>
</span>
)}
</span>
</p>
<ButtonPresses />
<Collapsible
icon={<SendHorizonal />}
title={<h3>Interact with your device</h3>}
class="mb-2"
>
<p class="d-flex">
{desiredLEDColor !== undefined && !isOff(desiredLEDColor) && (
<Lightbulb
strokeWidth={2}
class="me-2"
color={RGBtoHEX(desiredLEDColor)}
/>
)}
{!userColor && <LightbulbOff strokeWidth={1} class="me-2" />}
<span>
Click the LED above to change the color on your device.
{desiredLEDColor !== undefined && (
<span>
<br />
<Applied
desired={{
r: desiredLEDColor.r,
g: desiredLEDColor.g,
b: desiredLEDColor.b,
}}
reported={
reportedLEDColor !== undefined
? {
r: reportedLEDColor.r,
g: reportedLEDColor.g,
b: reportedLEDColor.b,
}
: undefined
}
/>
</span>
)}
</span>
</p>
<p class="d-flex">
<CircleStop strokeWidth={1} class="me-2" />
<span>
Press the button on your device to receive them here.
</span>
</p>
</Collapsible>
{!userColor && model.ledPattern !== undefined && (
<>
<h3>LED Pattern</h3>
<Collapsible title={<h3>LED Pattern</h3>}>
<p>
When no color is set by you, the device will display this
pattern to signal its current state:
</p>
<LEDPattern ledPattern={model.ledPattern} />
</>
</Collapsible>
)}
</>
)}
Expand Down

0 comments on commit c4faef7

Please sign in to comment.