Compare commits

..

No commits in common. "bd025d6d7164c0db0b93f7f1ff714357f38cb810" and "a7137f0d510d003ecd41538285d678a5199047e0" have entirely different histories.

7 changed files with 71 additions and 158 deletions

View File

@ -4,7 +4,6 @@ import { invoke } from '@tauri-apps/api/tauri';
import './App.css'; import './App.css';
import { Configurator } from './configurator/configurator'; import { Configurator } from './configurator/configurator';
import { ButtonSwitch } from './commons/components/button'; import { ButtonSwitch } from './commons/components/button';
import { fillParentCss } from './styles/fill-parent';
type Mode = 'Flowing' | 'Follow' | null; type Mode = 'Flowing' | 'Follow' | null;
@ -41,7 +40,7 @@ function App() {
); );
return ( return (
<div css={[fillParentCss]} tw="box-border flex flex-col"> <div>
<div tw="flex justify-between"> <div tw="flex justify-between">
{ledStripColors.map((it) => ( {ledStripColors.map((it) => (
<span tw="h-8 flex-auto" style={{ backgroundColor: it }}></span> <span tw="h-8 flex-auto" style={{ backgroundColor: it }}></span>
@ -56,7 +55,7 @@ function App() {
))} ))}
</div> </div>
<div tw="flex gap-5 justify-center"> <div tw="flex gap-5 justify-center ">
<ButtonSwitch onClick={() => takeSnapshot()}>Take Snapshot</ButtonSwitch> <ButtonSwitch onClick={() => takeSnapshot()}>Take Snapshot</ButtonSwitch>
<ButtonSwitch onClick={() => getLedStripColors()}>Get Colors</ButtonSwitch> <ButtonSwitch onClick={() => getLedStripColors()}>Get Colors</ButtonSwitch>
<ButtonSwitch onClick={() => switchCurrentMode('Flowing')}> <ButtonSwitch onClick={() => switchCurrentMode('Flowing')}>
@ -65,7 +64,7 @@ function App() {
<ButtonSwitch onClick={() => switchCurrentMode('Follow')}>Follow</ButtonSwitch> <ButtonSwitch onClick={() => switchCurrentMode('Follow')}>Follow</ButtonSwitch>
</div> </div>
<div css={[fillParentCss]}> <div tw="flex gap-5 justify-center">
<Configurator /> <Configurator />
</div> </div>
</div> </div>

View File

@ -1,62 +0,0 @@
import { isNil } from 'ramda';
import { FC, Fragment, useMemo } from 'react';
import tw, { css, styled } from 'twin.macro';
import { useLedCount } from '../contents/led-count';
import { PixelRgb } from '../models/pixel-rgb';
import { StyledPixel } from './styled-pixel';
import { BorderLedStrip } from './completed-led-strip';
const StyledCompletedContainerBorder = styled.section(
tw`dark:shadow-xl border-gray-600 bg-black border rounded-full flex flex-nowrap justify-around items-center p-px h-3 mb-1`,
css`
grid-column: 1 / -1;
grid-row: 1 / span 1;
justify-self: stretch;
`,
);
interface StyledCompletedContainerProps {
borderLedStrips: BorderLedStrip[];
overrideBorderLedStrips?: BorderLedStrip[];
}
export const CompletedContainer: FC<StyledCompletedContainerProps> = ({
borderLedStrips,
overrideBorderLedStrips,
}) => {
const { ledCount } = useLedCount();
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}
css={css`
grid-row-start: 1;
grid-column-start: ${i + 1};
align-self: flex-start;
`}
/>
));
}, [ledCount, borderLedStrips, overrideBorderLedStrips]);
return (
<Fragment>
<StyledCompletedContainerBorder />
{completedPixels}
</Fragment>
);
};

View File

@ -1,5 +1,5 @@
import debug from 'debug'; import debug from 'debug';
import { lensPath, set, splitEvery, update } from 'ramda'; import { isNil, lensPath, set, splitEvery, update } from 'ramda';
import { FC, useEffect, useMemo, useState } from 'react'; import { FC, useEffect, useMemo, useState } from 'react';
import tw, { css, styled } from 'twin.macro'; import tw, { css, styled } from 'twin.macro';
import { Borders, borders } from '../../constants/border'; import { Borders, borders } from '../../constants/border';
@ -8,8 +8,8 @@ import { DisplayConfig, LedStripConfigOfBorders } from '../models/display-config
import { LedStripConfig } from '../models/led-strip-config'; import { LedStripConfig } from '../models/led-strip-config';
import { PixelRgb } from '../models/pixel-rgb'; import { PixelRgb } from '../models/pixel-rgb';
import { ScreenshotDto } from '../models/screenshot.dto'; import { ScreenshotDto } from '../models/screenshot.dto';
import { CompletedContainer } from './completed-container';
import { DraggableStrip } from './draggable-strip'; import { DraggableStrip } from './draggable-strip';
import { StyledPixel } from './styled-pixel';
export const logger = debug('app:completed-led-strip'); export const logger = debug('app:completed-led-strip');
@ -18,7 +18,7 @@ interface CompletedLedStripProps {
onDisplayConfigChange?: (value: DisplayConfig) => void; onDisplayConfigChange?: (value: DisplayConfig) => void;
} }
export type BorderLedStrip = { type BorderLedStrip = {
pixels: PixelRgb[]; pixels: PixelRgb[];
config: LedStripConfig | null; config: LedStripConfig | null;
}; };
@ -26,13 +26,20 @@ export type BorderLedStrip = {
const StyledContainer = styled.section( const StyledContainer = styled.section(
({ rows, columns }: { rows: number; columns: number }) => [ ({ rows, columns }: { rows: number; columns: number }) => [
tw`grid m-4 pb-2 items-center justify-items-center select-none`, tw`grid m-4 pb-2 items-center justify-items-center select-none`,
tw`overflow-x-auto overflow-y-hidden flex-none`,
css` css`
grid-template-columns: repeat(${columns}, 0.5em); grid-template-columns: repeat(${columns}, 1fr);
grid-template-rows: auto repeat(${rows}, 0.5em); 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> = ({ export const CompletedLedStrip: FC<CompletedLedStripProps> = ({
screenshots, screenshots,
onDisplayConfigChange, onDisplayConfigChange,
@ -49,18 +56,6 @@ export const CompletedLedStrip: FC<CompletedLedStripProps> = ({
() => borderLedStrips.reduce((prev, curr) => prev + curr.pixels.length, 0), () => borderLedStrips.reduce((prev, curr) => prev + curr.pixels.length, 0),
[borderLedStrips], [borderLedStrips],
); );
const maxIndex = useMemo(
() =>
Math.max(
...borderLedStrips
.map((s) => [
s.config?.global_end_position ?? 0,
s.config?.global_start_position ?? 0,
])
.flat(),
),
[borderLedStrips],
);
const { setLedCount } = useLedCount(); const { setLedCount } = useLedCount();
// setLedCount for context // setLedCount for context
@ -71,6 +66,26 @@ export const CompletedLedStrip: FC<CompletedLedStripProps> = ({
const [overrideBorderLedStrips, setOverrideBorderLedStrips] = const [overrideBorderLedStrips, setOverrideBorderLedStrips] =
useState<BorderLedStrip[]>(); 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(() => { const strips = useMemo(() => {
return borderLedStrips.map(({ config, pixels }, index) => return borderLedStrips.map(({ config, pixels }, index) =>
config ? ( config ? (
@ -108,12 +123,11 @@ export const CompletedLedStrip: FC<CompletedLedStripProps> = ({
setOverrideBorderLedStrips(undefined); setOverrideBorderLedStrips(undefined);
}, [borderLedStrips]); }, [borderLedStrips]);
return ( return (
<StyledContainer rows={screenshots.length * borders.length} columns={maxIndex + 1}> <StyledContainer rows={screenshots.length * borders.length} columns={ledCount}>
<CompletedContainer <StyledCompletedContainer>{completedPixels}</StyledCompletedContainer>
borderLedStrips={borderLedStrips}
overrideBorderLedStrips={overrideBorderLedStrips}
/>
{strips} {strips}
</StyledContainer> </StyledContainer>
); );
}; };

View File

@ -1,4 +1,4 @@
import { HTMLAttributes, MouseEventHandler, useCallback } from 'react'; import { HTMLAttributes, useCallback } from 'react';
import { FC } from 'react'; import { FC } from 'react';
import { LedStripConfig } from '../models/led-strip-config'; import { LedStripConfig } from '../models/led-strip-config';
import tw, { styled } from 'twin.macro'; import tw, { styled } from 'twin.macro';
@ -26,54 +26,36 @@ export const LedStripEditor: FC<LedStripEditorProps> = ({
onChange, onChange,
...htmlAttrs ...htmlAttrs
}) => { }) => {
const addLed: MouseEventHandler = useCallback( const addLed = useCallback(() => {
(ev) => { if (config) {
ev.preventDefault(); if (config.global_start_position <= config.global_end_position) {
const delta = ev.button === 2 ? 10 : 1; onChange?.({ ...config, global_end_position: config.global_end_position + 1 });
if (config) {
if (config.global_start_position <= config.global_end_position) {
onChange?.({
...config,
global_end_position: config.global_end_position + delta,
});
} else {
onChange?.({
...config,
global_start_position: config.global_start_position + delta,
});
}
} else { } else {
onChange?.(new LedStripConfig(0, 0, 0)); onChange?.({
...config,
global_start_position: config.global_start_position + 1,
});
} }
}, } else {
[config, onChange], onChange?.(new LedStripConfig(0, 0, 0));
); }
const removeLed: MouseEventHandler = useCallback( }, [config, onChange]);
(ev) => { const removeLed = useCallback(() => {
ev.preventDefault(); if (!config) {
const delta = ev.button === 2 ? 10 : 1; onChange?.(null);
if (!config) { } else if (Math.abs(config.global_start_position - config.global_end_position) <= 1) {
onChange?.(null); onChange?.(null);
} else if ( } else {
Math.abs(config.global_start_position - config.global_end_position) <= delta if (config.global_start_position <= config.global_end_position) {
) { onChange?.({ ...config, global_end_position: config.global_end_position - 1 });
onChange?.(null);
} else { } else {
if (config.global_start_position <= config.global_end_position) { onChange?.({
onChange?.({ ...config,
...config, global_start_position: config.global_start_position - 1,
global_end_position: config.global_end_position - delta, });
});
} else {
onChange?.({
...config,
global_start_position: config.global_start_position - delta,
});
}
} }
}, }
[config, onChange], }, [config, onChange]);
);
const reverse = useCallback(() => { const reverse = useCallback(() => {
if (!config) { if (!config) {
return; return;
@ -87,10 +69,10 @@ export const LedStripEditor: FC<LedStripEditorProps> = ({
return ( return (
<StyledContainer {...htmlAttrs}> <StyledContainer {...htmlAttrs}>
<StyledButton title="Add LED" onClick={addLed} onContextMenu={addLed}> <StyledButton title="Add LED" onClick={addLed}>
<FontAwesomeIcon icon={faPlus} /> <FontAwesomeIcon icon={faPlus} />
</StyledButton> </StyledButton>
<StyledButton title="Remove LED" onClick={removeLed} onContextMenu={removeLed}> <StyledButton title="Remove LED" onClick={removeLed}>
<FontAwesomeIcon icon={faMinus} /> <FontAwesomeIcon icon={faMinus} />
</StyledButton> </StyledButton>
<StyledButton title="Reverse" onClick={reverse}> <StyledButton title="Reverse" onClick={reverse}>

View File

@ -14,7 +14,6 @@ import { CompletedLedStrip } from './components/completed-led-strip';
import { LedCountProvider } from './contents/led-count'; import { LedCountProvider } from './contents/led-count';
import debug from 'debug'; import debug from 'debug';
import { useSnackbar } from 'notistack'; import { useSnackbar } from 'notistack';
import { fillParentCss } from '../styles/fill-parent';
const logger = debug('app:configurator'); const logger = debug('app:configurator');
@ -34,8 +33,7 @@ const writePickerConfig = async (config: PickerConfiguration) => {
}); });
}; };
const StyledConfiguratorContainer = styled.section( const StyledConfiguratorContainer = styled.section(
tw`flex flex-col items-stretch relative overflow-hidden`, tw`flex flex-col items-stretch relative`,
fillParentCss,
); );
const StyledDisplayContainer = styled.section(tw`overflow-auto`); const StyledDisplayContainer = styled.section(tw`overflow-auto`);
@ -119,7 +117,7 @@ const ConfiguratorInner: FC = () => {
screenshots={screenshotOfDisplays} screenshots={screenshotOfDisplays}
onDisplayConfigChange={onDisplayConfigChange} onDisplayConfigChange={onDisplayConfigChange}
/> />
<StyledDisplayContainer tw="overflow-y-auto">{displays}</StyledDisplayContainer> <StyledDisplayContainer>{displays}</StyledDisplayContainer>
<Fab <Fab
aria-label="reset" aria-label="reset"
size="small" size="small"

View File

@ -1,3 +0,0 @@
import tw from 'twin.macro';
export const fillParentCss = tw`w-full h-full overflow-hidden`;

View File

@ -1,28 +1,13 @@
import React from 'react'; import React from 'react';
import { Global, css } from '@emotion/react'; import { Global, css } from '@emotion/react';
import tw, { theme, GlobalStyles as BaseStyles } from 'twin.macro'; import tw, { theme, GlobalStyles as BaseStyles } from 'twin.macro';
import { fillParentCss } from './fill-parent';
const customStyles = css({ const customStyles = css({
body: { body: {
WebkitTapHighlightColor: theme`colors.purple.500`, WebkitTapHighlightColor: theme`colors.purple.500`,
...tw`antialiased`, ...tw`antialiased`,
...tw`dark:bg-dark-800 bg-dark-100 dark:text-gray-100 text-gray-800`, ...tw`dark:bg-dark-800 bg-dark-100 dark:text-gray-100 text-gray-800`,
...fillParentCss,
}, },
html: {
...fillParentCss,
},
'#root': {
...fillParentCss,
},
'::-webkit-scrollbar': tw`w-1.5 h-1.5`,
'::-webkit-scrollbar-button': tw`hidden`,
'::-webkit-scrollbar-track': tw`bg-transparent`,
'::-webkit-scrollbar-track-piece': tw`bg-transparent`,
'::-webkit-scrollbar-thumb': tw`bg-gray-300 dark:(bg-gray-700/50 hover:bg-gray-700/90 active:bg-gray-700/100) transition-colors rounded-full`,
'::-webkit-scrollbar-corner': tw`bg-gray-600`,
'::-webkit-resizer': tw`hidden`,
}); });
const GlobalStyles = () => ( const GlobalStyles = () => (