desktop/src/configurator/components/completed-led-strip.tsx

134 lines
4.3 KiB
TypeScript

import debug from 'debug';
import { isNil, lensPath, set, splitEvery, update } from 'ramda';
import { FC, useEffect, useMemo, useState } from 'react';
import tw, { css, styled } from 'twin.macro';
import { Borders, borders } from '../../constants/border';
import { useLedCount } from '../contents/led-count';
import { DisplayConfig, LedStripConfigOfBorders } from '../models/display-config';
import { LedStripConfig } from '../models/led-strip-config';
import { PixelRgb } from '../models/pixel-rgb';
import { ScreenshotDto } from '../models/screenshot.dto';
import { DraggableStrip } from './draggable-strip';
import { StyledPixel } from './styled-pixel';
export const logger = debug('app:completed-led-strip');
interface CompletedLedStripProps {
screenshots: ScreenshotDto[];
onDisplayConfigChange?: (value: DisplayConfig) => void;
}
type BorderLedStrip = {
pixels: PixelRgb[];
config: LedStripConfig | null;
};
const StyledContainer = styled.section(
({ rows, columns }: { rows: number; columns: number }) => [
tw`grid m-4 pb-2 items-center justify-items-center select-none`,
css`
grid-template-columns: repeat(${columns}, 1fr);
grid-template-rows: auto repeat(${rows}, 1fr);
`,
],
);
const StyledCompletedContainer = styled.section(
tw`dark:bg-transparent shadow-xl border-gray-500 border rounded-full flex flex-wrap justify-around items-center mb-2`,
css`
grid-column: 1 / -1;
justify-self: stretch;
`,
);
export const CompletedLedStrip: FC<CompletedLedStripProps> = ({
screenshots,
onDisplayConfigChange,
}) => {
const borderLedStrips: BorderLedStrip[] = useMemo(() => {
return screenshots.flatMap((ss) =>
borders.map((b) => ({
pixels: splitEvery(3, Array.from(ss.colors[b])) as PixelRgb[],
config: ss.config.led_strip_of_borders[b],
})),
);
}, [screenshots]);
const ledCount = useMemo(
() => borderLedStrips.reduce((prev, curr) => prev + curr.pixels.length, 0),
[borderLedStrips],
);
const { setLedCount } = useLedCount();
// setLedCount for context
useEffect(() => {
setLedCount(ledCount);
}, [ledCount, setLedCount]);
const [overrideBorderLedStrips, setOverrideBorderLedStrips] =
useState<BorderLedStrip[]>();
const completedPixels = useMemo(() => {
const completed: PixelRgb[] = new Array(ledCount).fill([0, 0, 0]);
(overrideBorderLedStrips ?? borderLedStrips).forEach(({ pixels, config }) => {
if (isNil(config)) {
return;
}
if (config.global_start_position <= config.global_end_position) {
pixels.forEach((color, i) => {
completed[config.global_start_position + i] = color;
});
} else {
pixels.forEach((color, i) => {
completed[config.global_start_position - i] = color;
});
}
});
return completed.map((color, i) => <StyledPixel rgb={color} key={i} />);
}, [ledCount, borderLedStrips, overrideBorderLedStrips]);
const strips = useMemo(() => {
return borderLedStrips.map(({ config, pixels }, index) =>
config ? (
<DraggableStrip
key={index}
{...{ config, pixels, index: index + 1 }}
onConfigChange={(c) => {
setOverrideBorderLedStrips(
update(index, { config: c, pixels }, borderLedStrips),
);
}}
onConfigFinish={(c) => {
const indexOfDisplay = Math.floor(index / borders.length);
const xLens = lensPath<LedStripConfigOfBorders, Borders>([
borders[index % borders.length],
]);
const displayConfig: DisplayConfig = {
...screenshots[indexOfDisplay].config,
led_strip_of_borders: set(
xLens,
c,
screenshots[indexOfDisplay].config.led_strip_of_borders,
),
};
onDisplayConfigChange?.(displayConfig);
}}
/>
) : (
<div key={index} />
),
);
}, [borderLedStrips, screenshots]);
useEffect(() => {
setOverrideBorderLedStrips(undefined);
}, [borderLedStrips]);
return (
<StyledContainer rows={screenshots.length * borders.length} columns={ledCount}>
<StyledCompletedContainer>{completedPixels}</StyledCompletedContainer>
{strips}
</StyledContainer>
);
};