#9: make the user-chosen path more clear to see.
Some checks reported errors
continuous-integration/drone/push Build encountered an error
continuous-integration/drone/pr Build encountered an error

This commit is contained in:
Manuel Friedli 2025-01-11 00:29:16 +01:00
parent 78b8772eff
commit 9efd718c9c
Signed by: manuel
GPG key ID: 41D08ABA75634DA1
5 changed files with 137 additions and 12 deletions

View file

@ -22,14 +22,88 @@
border-left-color: var(--color-maze-border);
}
.user{
background-color: var(--color-maze-cell-user);
.userSELF {
background: radial-gradient(
ellipse 16% 16% at center,
var(--color-maze-cell-user) 0,
var(--color-maze-cell-user) 100%,
#0000 100%
);
}
.user:hover {
background-color: var(--color-maze-cell-user-highlight);
.userSELF:hover {
background: radial-gradient(
ellipse 33% 33% at center,
var(--color-maze-cell-user) 0,
var(--color-maze-cell-user) 80%,
#0000 100%
);
}
.solution.user {
background-color: #c8ff00;
.marker {
display: inline-block;
position: absolute;
}
.marker:hover {
background: #fc08;
}
.userUP .marker.UP {
height: 50%;
width: 100%;
background: linear-gradient(
90deg,
#0000 0,
#0000 33%,
var(--color-maze-cell-user) 33%,
var(--color-maze-cell-user) 66%,
#0000 66%,
#0000 100%
);
}
.userRIGHT .marker.RIGHT {
height: 100%;
width: 50%;
left: 50%;
background: linear-gradient(
0deg,
#0000 0,
#0000 33%,
var(--color-maze-cell-user) 33%,
var(--color-maze-cell-user) 66%,
#0000 66%,
#0000 100%
);
}
.userDOWN .marker.DOWN {
height: 50%;
width: 100%;
top: 50%;
background: linear-gradient(
90deg,
#0000 0,
#0000 33%,
var(--color-maze-cell-user) 33%,
var(--color-maze-cell-user) 66%,
#0000 66%,
#0000 100%
);
}
.userLEFT .marker.LEFT {
height: 100%;
width: 50%;
background: linear-gradient(
0deg,
#0000 0,
#0000 33%,
var(--color-maze-cell-user) 33%,
var(--color-maze-cell-user) 66%,
#0000 66%,
#0000 100%
);
}

View file

@ -4,6 +4,7 @@
height: 2em;
width: 2em;
padding: 0;
position: relative;
}
.cell:hover {

View file

@ -6,8 +6,41 @@ import "./cell.css";
import {State} from "./state/state.ts";
import {ActionDispatch} from "react";
function isMarked(x: number, y: number, marked: Coordinates[]): boolean {
return !!marked.find(e => e.x === x && e.y === y);
function getMarkedDirections(coords: Coordinates, marked: Coordinates[]): Direction[] {
const cellIndex: number = marked.findIndex(e => e.x === coords.x && e.y === coords.y);
if (cellIndex === -1) {
return [];
}
if (marked.length === 1) {
return [Direction.SELF];
}
if (cellIndex === 0) {
const next: Coordinates = marked[1];
return [Direction.SELF, getDirectionTo(coords, next)];
} else {
const previous = marked[cellIndex - 1];
if (cellIndex === marked.length - 1) {
return [Direction.SELF, getDirectionTo(coords, previous)];
}
const next: Coordinates = marked[cellIndex + 1];
return [Direction.SELF, getDirectionTo(coords, previous), getDirectionTo(coords, next)];
}
}
function getDirectionTo(me: Coordinates, other: Coordinates): Direction {
const xDiff = me.x - other.x;
switch (xDiff) {
case -1:
return Direction.RIGHT;
case 1:
return Direction.LEFT;
default:
const yDiff = me.y - other.y;
if (yDiff === -1) {
return Direction.DOWN;
}
return Direction.UP;
}
}
export default function Cell({x, y, state, dispatch}:
@ -24,8 +57,10 @@ export default function Cell({x, y, state, dispatch}:
if (cell.bottom) classes += " bottom";
if (cell.left) classes += " left";
if (cell.solution && state.showSolution) classes += " solution";
const marked = isMarked(x, y, state.userPath);
if (marked) classes += " user";
const markedDirections = getMarkedDirections({x, y}, state.userPath);
for (let i = 0; i < markedDirections.length; i++) {
classes += ` user${Direction[markedDirections[i]]}`;
}
return (
<div className={styles.cell + classes}
onMouseEnter={(e) => {
@ -37,6 +72,14 @@ export default function Cell({x, y, state, dispatch}:
onClick={() => {
dispatch(actionClickedCell(x, y));
}}>
<div className={"marker UP"}></div>
<div className={"marker RIGHT"}></div>
<div className={"marker DOWN"}></div>
<div className={"marker LEFT"}></div>
</div>
);
}
enum Direction {
UP, RIGHT, DOWN, LEFT, SELF
}

View file

@ -1,6 +1,12 @@
import {ActionDispatch, FormEvent, useState} from 'react';
import ValidatingInputNumberField, {ValidatorFunction} from "./validating-input-number-field.tsx";
import {Action, actionLoadedMaze, actionLoadingFailed, actionStartedLoading} from "./state/action.ts";
import {
Action,
actionLoadedMaze,
actionLoadingFailed,
actionStartedLoading,
actionToggledShowSolution
} from "./state/action.ts";
import styles from "./input-form.module.css";
import "./input-form.css";
import {State} from "@/app/state/state.ts";
@ -17,10 +23,10 @@ export default function InputForm({state, dispatch}: {
const handleSubmit = (e: FormEvent) => {
e.preventDefault();
dispatch(actionStartedLoading());
dispatch(actionToggledShowSolution(false));
const url = `https://manuel.friedli.info/labyrinth/create/json?w=${width}&h=${height}&id=${id || ''}&algorithm=${algorithm}`;
fetch(url)
.then(response => response.json())
// .then(result => new Promise(resolve => setTimeout(resolve, 600, result)))
.then(result => {
dispatch(actionLoadedMaze(result));
})

View file

@ -25,6 +25,7 @@ export default function Home() {
<h1>The Maze ({state.maze!.width}x{state.maze!.height}, Algorithm: {state.maze!.algorithm},
ID: {state.maze!.id})</h1>
<input type={"checkbox"}
checked={state.showSolution}
onChange={(e) => {
dispatch(actionToggledShowSolution(e.target.checked));
}}