Skip to content

Commit

Permalink
Reorganize Gradient Editor
Browse files Browse the repository at this point in the history
Fix palette selector
  • Loading branch information
AaronAsAChimp committed Oct 26, 2024
1 parent 1c64588 commit fd5f9c9
Show file tree
Hide file tree
Showing 20 changed files with 243 additions and 135 deletions.
3 changes: 1 addition & 2 deletions web/src/components/AppSideBar.astro
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ const hasOptions = Astro.slots.has('default');
}

.app-title-tool-specific {
display: flex;
gap: 0.5em;
padding: 1.3em 2em;
}
</style>
28 changes: 28 additions & 0 deletions web/src/components/AppTopBar.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
import {AppMenu} from './app-menu/index.jsx';
const {title} = Astro.props;
const hasOptions = Astro.slots.has('default');
---
<div class={`app-top-bar ${ hasOptions ? 'top-bar-w-options' : null }`}>
<div class="app-title">
{ title }
</div>

<slot />
<AppMenu client:only="react" />
</div>
<style>
.app-top-bar {
font-weight: 200;
font-size: 1.5em;
letter-spacing: 0.06em;

display: flex;
padding: 1em 0;
gap: 0.6em;

& .app-title {
flex: 1 0 auto;
}
}
</style>
24 changes: 17 additions & 7 deletions web/src/components/block-map-selection/index.jsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
import { useContext, useMemo } from 'react';
import { useMemo } from 'react';

import { SELECTION_RADIUS } from '../../consts.js';
import { TextureSwatch } from '../texture-swatch/index.jsx';
import { PaletteContext } from '../../context/palette-context.js';
import { findNear } from '../../blocks.js';

import styles from './styles.module.css';
import { useStore } from '@nanostores/react';
import { blockMapOptionsStore } from '../../context/block-map-store.js';
import { paletteStore } from '../../context/palette-store.js';


/**
* A component to show the selected block.
*/
export function BlockMapSelection() {
const palette = useContext(PaletteContext);
const palette = useStore(paletteStore);
const blockMapOptions = useStore(blockMapOptionsStore);

const nearest = useMemo(() => {
Expand All @@ -24,17 +23,28 @@ export function BlockMapSelection() {

const inRange = findNear(blockMapOptions.selected, blockMapOptions.blocks, palette, SELECTION_RADIUS);

for (let i = 0; i < inRange.length; i++) {
if (inRange[i].candidate.name === blockMapOptions.selected.name) {
inRange.splice(i, 1);
break;
}
}

return inRange;
}, [blockMapOptions.selected, blockMapOptions.blocks, palette]);

return (blockMapOptions.selected ?
<div className={styles['selected-block']}>
<div className="name">{blockMapOptions.selected.name}</div>
<div>
<h3>Selected</h3>
<div>{blockMapOptions.selected.name}</div>
<TextureSwatch block={blockMapOptions.selected} />

<h3>Similar Blocks</h3>
<div className="similar">
{ nearest.map(block => <TextureSwatch block={block.candidate} key={block.candidate.name} />) }
</div>
</div> :
null);
<p>
Select a colored block on the map to view information on it and blocks with similar colors.
</p>);
}
3 changes: 0 additions & 3 deletions web/src/components/block-map-selection/styles.module.css

This file was deleted.

7 changes: 4 additions & 3 deletions web/src/components/block-map/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import droidSansRegular from 'three/examples/fonts/droid/droid_sans_regular.type

import { OBJLoader as ThreeOBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
import { ContrastContext } from '../../context/contrast-context.js';
import { PaletteContext } from '../../context/palette-context.js';
import { DATA_DIR, SELECTION_RADIUS } from '../../consts.js';
import { TooltipWrapper } from '../tooltip/index.jsx';
import { paletteStore } from '../../context/palette-store.js';
import { useStore } from '@nanostores/react';

const BLOCK_SIZE = SELECTION_RADIUS / 8;

Expand Down Expand Up @@ -147,7 +148,7 @@ const AnimatedBillboard = animated(Billboard);
* @param {SelectionMeshProps} props
*/
function SelectionMesh({block}) {
const palette = useContext(PaletteContext);
const palette = useStore(paletteStore);
/** @type {import('shared/src/block').Color} */
const color = block.palette[palette];
const contrast = useContext(ContrastContext);
Expand Down Expand Up @@ -230,7 +231,7 @@ const LabelsMemoized = memo(Labels);
* @param {BlockMeshProps} props
*/
function BlockMesh({block, onSelect, onMouseEnter, onMouseLeave}) {
const palette = useContext(PaletteContext);
const palette = useStore(paletteStore);
const color = block.palette[palette];
const {position} = useSpring({
position: [
Expand Down
17 changes: 17 additions & 0 deletions web/src/components/help-button/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { faQuestion } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useState } from 'react';
import { LazyDialog } from '../lazy-dialog';

import styles from './styles.module.css';

export function HelpButton({content}) {
const [helpOpen, setHelpOpen] = useState(false);

return <>
<button className={styles['help-button']} onClick={() => setHelpOpen(true)}><FontAwesomeIcon icon={faQuestion} /></button>
<LazyDialog open={helpOpen} onClose={() => setHelpOpen(false)}>
<div dangerouslySetInnerHTML={{__html: content}}></div>
</LazyDialog>
</>
}
14 changes: 14 additions & 0 deletions web/src/components/help-button/styles.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.help-button {
aspect-ratio: 1;
align-self: center;
width: 2.2em;
background: var(--layer1-color);
color: var(--layer1-contrast-color);
border: none;
cursor: pointer;

&:hover {
background: var(--layer1-hover);
color: var(--layer1-hover-contrast-color);
}
}
38 changes: 14 additions & 24 deletions web/src/components/page-color-map/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,30 +131,20 @@ export function ColorMap() {
}

return <div ref={rootRef}>
<PaletteContext.Provider value={palette}>
<ContrastContext.Provider value={colors}>
<BlockMap
labels={labels}
blocks={blockMapOptions.blocks}
selected={blockMapOptions.selected}
onSelected={selectionChange}
onAlphaChange={alphaChange} />

{/*<AppTitleBar title="Block Game Color Map">*/}
<BlockSearch value={searchTerm} onChange={searchHandler} blocks={blockMapOptions.blocks} />
<label>
Color Extraction:
<select className="pallette-select" onInput={paletteChange} value={palette}>
<option value="average">Average</option>
<option value="mostSaturated">Most Saturated</option>
<option value="mostCommon">Most Common</option>
</select>
</label>
<button onClick={() => setHelpOpen(true)}><FontAwesomeIcon icon={faQuestion} /></button>
{/*</AppTitleBar>*/}

</ContrastContext.Provider>
</PaletteContext.Provider>
<ContrastContext.Provider value={colors}>
<BlockMap
labels={labels}
blocks={blockMapOptions.blocks}
selected={blockMapOptions.selected}
onSelected={selectionChange}
onAlphaChange={alphaChange} />

{/*<AppTitleBar title="Block Game Color Map">*/}
<BlockSearch value={searchTerm} onChange={searchHandler} blocks={blockMapOptions.blocks} />
<button onClick={() => setHelpOpen(true)}><FontAwesomeIcon icon={faQuestion} /></button>
{/*</AppTitleBar>*/}

</ContrastContext.Provider>
<LazyDialog open={helpOpen} onClose={() => setHelpOpen(false)}>
<MapHelpContent />
</LazyDialog>
Expand Down
85 changes: 28 additions & 57 deletions web/src/components/page-gradient/index.jsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
import { faQuestion } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { memo, useEffect, useMemo, useRef, useState } from "react";
import { buildGradientParam, parseGradientParam } from "shared/src/gradient";
// import { AppTitleBar } from "../../../components/app-title-bar";
import { GradientHelpContent } from "../content";
import { GradientDisplay } from "../gradient-display";
import { LazyDialog } from "../lazy-dialog";
import { Share } from "../share";
import { TextureSwatch } from "../texture-swatch";
import { PaletteContext } from "../../context/palette-context";
import { BlockLookup, loadBlocks } from "../../blocks";
import './styles.css';

const MIN_STEPS = 0;
const DEFAULT_START = 0x000000;
const DEFAULT_END = 0xFFFFFF;
const DEFAULT_STEPS = 5;

const TextureSwatchMemo = memo(TextureSwatch);
Expand Down Expand Up @@ -60,7 +53,6 @@ export function Gradient() {
// const navigate = useNavigate();

const [palette, setPalette] = useState('average');
const [helpOpen, setHelpOpen] = useState(false);

useEffect(() => {
loadBlocks('gradient-blocks')
Expand All @@ -77,11 +69,6 @@ export function Gradient() {
return null;
}, [blocks]);

function paletteChange(e) {
const select = e.target;
setPalette(select.options[select.selectedIndex].value);
}

useEffect(() => {
window.history.replaceState(null, null, '?g=' + buildGradientParam(gradientRef.current, numSteps));
}, [gradientSteps])
Expand All @@ -108,53 +95,37 @@ export function Gradient() {
// }

return <>
<PaletteContext.Provider value={palette}>
{/*<AppTitleBar title="Gradient Editor">*/}
<div className="gradient-editor">
<div className="gradient-display-panel">
<GradientDisplay onGradientChange={gradientChange} initialGradientStops={initialStops} />
</div>

<div className="gradient-controls">
<label>
Color Extraction:
<select className="pallette-select" onInput={paletteChange} value={palette}>
<option value="average">Average</option>
<option value="mostSaturated">Most Saturated</option>
<option value="mostCommon">Most Common</option>
</select>
Number of blocks:
<input type="number" min={MIN_STEPS} onInput={stepsChange} value={numSteps} />
</label>
<button onClick={() => setHelpOpen(true)}><FontAwesomeIcon icon={faQuestion} /></button>
{/*</AppTitleBar>*/}
<div className="gradient-editor">
<div className="gradient-display-panel">
<GradientDisplay onGradientChange={gradientChange} initialGradientStops={initialStops} />
</div>

<div className="gradient-controls">
<label>
Number of blocks:
<input type="number" min={MIN_STEPS} onInput={stepsChange} value={numSteps} />
</label>
{/* <a onClick={ onSchematicDownload } download="schematic.lightmatic">
Schematic
</a>*/}
</div>

<div className="gradient-share">
<Share href={window.location} subject="Block Game Tools - Block Gradient" body="" />
</div>

<div className="gradient-swatches">
{ gradientSteps.length && blockLookup
? gradientSteps.map((color, idx) => {
const blockMatch = blockLookup.find(color, palette);

return <div className="gradient-swatch-container" key={idx}>
<TextureSwatchMemo block={blockMatch.block} title={Math.sqrt(blockMatch.magnitude) >= 10 ? 'Out of gamut' : null } />
</div>
})
: null
}
</div>
Schematic
</a>*/}
</div>

<div className="gradient-share">
<Share href={window.location} subject="Block Game Tools - Block Gradient" body="" />
</div>

<div className="gradient-swatches">
{ gradientSteps.length && blockLookup
? gradientSteps.map((color, idx) => {
const blockMatch = blockLookup.find(color, palette);

return <div className="gradient-swatch-container" key={idx}>
<TextureSwatchMemo block={blockMatch.block} title={Math.sqrt(blockMatch.magnitude) >= 10 ? 'Out of gamut' : null } />
</div>
})
: null
}
</div>
</PaletteContext.Provider>
<LazyDialog open={helpOpen} onClose={() => setHelpOpen(false)}>
<GradientHelpContent />
</LazyDialog>
</div>
</>;
}
25 changes: 7 additions & 18 deletions web/src/components/page-texturizer/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { LitematicaSchematic } from "../../schematic/schematic.js";
import { SchematicRegion } from "../../schematic/schematic-region.js";
import { BlockLookup, loadBlocks } from "../../blocks";
import { coordToIndex, dither, ordered } from "../../dithering";
import { paletteStore } from '../../context/palette-store';

import styles from './styles.module.css';
import { useStore } from '@nanostores/react';
Expand Down Expand Up @@ -85,17 +86,12 @@ export function Texturizer() {
const [textureBlocks, setTextureBlocks] = useState(null);
const texturizerOptions = useStore(texturizerOptionsStore);

const [gradientUpdateToken, setGradientUpdateToken] = useState(null);
const [redraws, setRedraws] = useState(0);
const [blocks, setBlocks] = useState([]);

const [palette, setPalette] = useState('average');
const [helpOpen, setHelpOpen] = useState(false);
const palette = useStore(paletteStore);

function paletteChange(e) {
const select = e.target;
setPalette(select.options[select.selectedIndex].value);
}
const [helpOpen, setHelpOpen] = useState(false);

function resetNoiser() {
noiserRef.current = createNoise2D();
Expand Down Expand Up @@ -173,6 +169,10 @@ export function Texturizer() {
return null;
}

if (!texturizerOptions.gradient) {
return null;
}

const globalBlockLookup = new BlockLookup(blocks);
let blockLookup = globalBlockLookup;

Expand Down Expand Up @@ -260,17 +260,6 @@ export function Texturizer() {

return <>
<PaletteContext.Provider value={palette}>
{/*<AppTitleBar title="Texturizer">*/}
<label>
Color Extraction:
<select className="pallette-select" onInput={paletteChange} value={palette}>
<option value="average">Average</option>
<option value="mostSaturated">Most Saturated</option>
<option value="mostCommon">Most Common</option>
</select>
</label>
{/*<button onClick={() => setHelpOpen(true)}><FontAwesomeIcon icon={faQuestion} /></button>*/}
{/*</AppTitleBar>*/}
<div className={styles['texturizer-controls']}>
<button type="button" onClick={resetNoiser}>Randomize</button>
<button ref={downloadSchematicRef} onClick={downloadSchematic}>Download Litematica Schematic</button>
Expand Down
Loading

0 comments on commit fd5f9c9

Please sign in to comment.