Skip to content
Open

Beta #394

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
eeb470e
Accept SVG for open with
courtneypattison Jun 26, 2025
7ae73f6
Change node version to >=22 for Vercel updates
courtneypattison Jul 16, 2025
0403d81
Added translation using Weblate (Chinese (Simplified Han script))
Aug 15, 2025
5b832a1
Translated using Weblate (Chinese (Simplified Han script))
Aug 15, 2025
7bffe21
Added translation using Weblate (Portuguese (Brazil))
xandaaguiar Aug 18, 2025
2030dc6
Translated using Weblate (Portuguese (Brazil))
xandaaguiar Aug 18, 2025
308a8b0
Translated using Weblate (Portuguese (Brazil))
xandaaguiar Aug 18, 2025
e8d96c2
Translated using Weblate (Danish)
anneloppe Sep 7, 2025
b64bc3f
Add line length and angle text input
courtneypattison Sep 11, 2025
4cf0aaf
Add line length and angle text input
courtneypattison Sep 11, 2025
fa182cd
Translated using Weblate (Danish)
anneloppe Sep 14, 2025
e5d3062
Merge pull request #396 from weblate/weblate-pattern-projector-patter…
courtneypattison Sep 16, 2025
36430d2
Add pt-BR and zh-Hans translations
courtneypattison Sep 16, 2025
167c93a
Allow pointer events behind the calibration warning
courtneypattison Sep 16, 2025
d37d72c
Fix #381 by changing end point touch area to be 1/2 inch
courtneypattison Sep 16, 2025
0e23585
Merge branch 'beta' into dist-angle-input
courtneypattison Sep 16, 2025
7e3f1cc
Add file name to stitch menu #390
courtneypattison Sep 16, 2025
43b8a19
Update CHANGELOF with file name showing
courtneypattison Sep 16, 2025
457ed6c
Fix #386 show line length as input length when magnifying
courtneypattison Sep 16, 2025
e21498f
Fix angle/length border colour in dark mode
courtneypattison Sep 30, 2025
7a050e2
Fix mismatch between angle input and canvas angle
courtneypattison Sep 30, 2025
df8114c
Change unselected lines to bright orange
courtneypattison Oct 1, 2025
f705b81
Change red overlays to bright orange (better luminance)
courtneypattison Oct 1, 2025
8b47b5d
Add documentation for length and angle input
courtneypattison Oct 14, 2025
4816b48
Merge pull request #401 from Pattern-Projector/dist-angle-input
courtneypattison Oct 14, 2025
72e6478
Added translation using Weblate (Finnish)
Oct 26, 2025
d52ec3e
Translated using Weblate (Finnish)
Oct 26, 2025
5fb7301
Translated using Weblate (Finnish)
Oct 29, 2025
b4512cb
Add playwright visual testing #30
courtneypattison Nov 11, 2025
fc28ec8
Merge pull request #407 from weblate/weblate-pattern-projector-patter…
courtneypattison Nov 11, 2025
98fdedf
Add Suomi translations
courtneypattison Nov 11, 2025
bfac73f
Fix #409 pressing C resets & recenters the pattern
courtneypattison Nov 15, 2025
56796c8
Fix pink screen on calibrate page
courtneypattison Nov 25, 2025
0be0e60
Update CHANGELOG with screenshot testing
courtneypattison Nov 25, 2025
2dba0ea
Merge pull request #408 from Pattern-Projector/testing
courtneypattison Nov 25, 2025
e55dba1
Fix #406 measurement labels match theme
courtneypattison Nov 26, 2025
73f6e84
Fix #410 add max to height and width input
courtneypattison Nov 26, 2025
8b78087
Update CHANGELOG with width/height limit
courtneypattison Nov 26, 2025
8e3b1fb
Fix #402 by adjusting the green theme filter
courtneypattison Nov 26, 2025
fe5d9d7
Update CHANGELOG for bright green lines for SVGs
courtneypattison Nov 26, 2025
4ee79e9
Allow measuring when magnifying
courtneypattison Dec 22, 2025
592bab0
Change arrow movement to 1/8" or 2mm #414
courtneypattison Dec 22, 2025
95b3016
Slow down speed of pattern movement with arrow keys
courtneypattison Dec 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Input line length and angle using textboxes
- Português (Brasil), Suomi, and 简体中文 translations
- Opened file name shows in the stitch menu
- Screenshot testing

### Fixed

- Menus will not hide when inputting text
- Able to drag ends of lines on touch devices
- Pressing C resets & recenters the pattern
- App crashing from large width/height inputs by setting the limit to 1000
- Bright instead of pale green lines for SVGs when the green theme is enabled

### Changed

- Line measurement labels match the theme
- Enabled measuring when magnified for precision measuring
- Pressing an arrow button once will move the pattern by 1/8" or 2mm
- Slow down speed of pattern movement with arrow keys

## [1.3.0] - 2025-06-25

### Added
Expand Down
15 changes: 9 additions & 6 deletions app/[locale]/calibrate/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import {
themeFilter,
Theme,
} from "@/_lib/display-settings";
import { getPtDensity, IN } from "@/_lib/unit";
import { getPtDensity, Unit } from "@/_lib/unit";
import { visible } from "@/_components/theme/css-functions";
import { useTranslations } from "next-intl";
import MeasureCanvas from "@/_components/canvases/measure-canvas";
Expand Down Expand Up @@ -87,6 +87,7 @@ export default function Page() {
// Default dimensions should be available on most cutting mats and large enough to get an accurate calibration
const defaultWidthDimensionValue = "24";
const defaultHeightDimensionValue = "16";
const maxDimensionValue = 1000; // Prevents crashing from excessive grid lines #410

const maxPoints = 4; // One point per vertex in rectangle

Expand Down Expand Up @@ -115,7 +116,7 @@ export default function Page() {
const [restoreTransforms, setRestoreTransforms] =
useState<RestoreTransforms | null>(null);
const [pageCount, setPageCount] = useState<number>(0);
const [unitOfMeasure, setUnitOfMeasure] = useState(IN);
const [unitOfMeasure, setUnitOfMeasure] = useState<Unit>(Unit.IN);
const [layoutWidth, setLayoutWidth] = useState<number>(0);
const [layoutHeight, setLayoutHeight] = useState<number>(0);
const [lineThickness, setLineThickness] = useState<number>(0);
Expand Down Expand Up @@ -267,14 +268,14 @@ export default function Page() {

// Save valid calibration grid height in localStorage
function handleHeightChange(e: ChangeEvent<HTMLInputElement>) {
const h = removeNonDigits(e.target.value, heightInput);
const h = removeNonDigits(e.target.value, heightInput, maxDimensionValue);
setHeightInput(h);
updateLocalSettings({ height: h });
}

// Save valid calibration grid width in localStorage
function handleWidthChange(e: ChangeEvent<HTMLInputElement>) {
const w = removeNonDigits(e.target.value, widthInput);
const w = removeNonDigits(e.target.value, widthInput, maxDimensionValue);
setWidthInput(w);
updateLocalSettings({ width: w });
}
Expand Down Expand Up @@ -521,6 +522,7 @@ export default function Page() {
<main
onPointerDown={handlePointerDown}
onPointerMove={handlePointerMove}
onKeyDown={resetIdle}
ref={noZoomRefCallback}
className={`${menusHidden && "cursor-none"} ${isDarkTheme(displaySettings.theme) && "dark bg-black"} w-screen h-screen absolute overflow-hidden touch-none`}
>
Expand All @@ -530,11 +532,11 @@ export default function Page() {
className="bg-white dark:bg-black transition-all duration-500 w-screen h-screen"
>
{showCalibrationAlert ? (
<div className="flex flex-col items-center gap-4 absolute left-1/4 top-1/2 -translate-y-1/2 w-1/2 bg-white dark:bg-black dark:text-white z-[150] p-4 rounded border-2 border-black dark:border-white">
<div className="flex flex-col items-center gap-4 absolute left-1/4 top-1/2 -translate-y-1/2 w-1/2 bg-white dark:bg-black dark:text-white z-[150] p-4 rounded border-2 border-black dark:border-white pointer-events-none">
<WarningIcon ariaLabel="warning" />
<p>{t("calibrationAlert")}</p>
<Button
className="flex items-center justify-center"
className="flex items-center justify-center pointer-events-auto"
onClick={() => toggleFullScreen(fullScreenHandle)}
>
<span className="mr-1 -mt-1.5 w-4 h-4">
Expand Down Expand Up @@ -604,6 +606,7 @@ export default function Page() {
magnifying={magnifying}
menusHidden={menusHidden}
menuStates={menuStates}
isDarkTheme={isDarkTheme(displaySettings.theme)}
>
<Draggable
className={`absolute ${menusHidden && "!cursor-none"} `}
Expand Down
76 changes: 72 additions & 4 deletions app/[locale]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { Button } from "@/_components/buttons/button";
import { ButtonStyle } from "@/_components/theme/styles";
import ZoomInIcon from "@/_icons/zoom-in-icon";
import TuneIcon from "@/_icons/tune-icon";
import InlineInput from "@/_components/inline-input";

const DynamicInstallButton = dynamic(
() => import("@/_components/buttons/install-button"),
Expand Down Expand Up @@ -67,7 +68,7 @@ export default function Home() {
</menu>
</nav>
<article className="prose lg:prose-xl m-auto">
<h1>{t("welcome.title")}</h1>
<h1 data-testid="welcome-title">{t("welcome.title")}</h1>
<p>
{t.rich("welcome.description", {
changeLogLink: (chunks) => (
Expand Down Expand Up @@ -149,8 +150,14 @@ export default function Home() {
</li>
<li>{t("calibration.start")}</li>
<li>
{t("calibration.fullscreen")}
<FullScreenIcon ariaLabel="" />
{t.rich("calibration.fullscreen", {
fullscreenIcon: () => (
<FullScreenIcon
className="inline-block align-middle"
ariaLabel=""
/>
),
})}
</li>
<li>{t("calibration.drag")}</li>
<li>
Expand All @@ -176,7 +183,13 @@ export default function Home() {
<ol>
<li>
{t.rich("project.open", {
pdficon: () => <PdfIcon fill="#000" ariaLabel="" />,
pdficon: () => (
<PdfIcon
fill="#000"
ariaLabel=""
className="inline-block align-middle"
/>
),
})}
</li>
<li>{t("project.move")}</li>
Expand Down Expand Up @@ -389,6 +402,61 @@ export default function Home() {
{t("lineTool.move.description")}
<p>{t("lineTool.move.use")}</p>
</Definition>
<Definition
icon={
<InlineInput
className="relative flex flex-col w-20"
disabled={true}
handleChange={() => {}}
inputClassName="pl-1.5 pr-7 !border-2 !border-black dark:!border-white"
id="distance"
labelRight={"in"}
name="distance"
value={"10"}
type="string"
/>
}
title={t("lineTool.length.title")}
>
{t("lineTool.length.description")}
<p>
{t.rich("lineTool.length.use", {
lineToolVideoLink: (chunks) => (
<a href="https://youtu.be/TH8tY9BoxfM?si=VTC1QRnNzBfG555Z&t=709">
{chunks}
</a>
),
})}
</p>
</Definition>
<Definition
icon={
<InlineInput
className="relative flex flex-col w-20"
disabled={true}
handleChange={() => {}}
inputClassName="pl-1.5 pr-7 !border-2 !border-black dark:!border-white"
id="distance"
labelRight={"°"}
name="distance"
value={"45"}
type="string"
/>
}
title={t("lineTool.angle.title")}
>
{t("lineTool.angle.description")}
<p>
{t.rich("lineTool.angle.use", {
alignIcon: () => (
<RotateToHorizontalIcon
className="inline-block align-middle"
ariaLabel=""
/>
),
})}
</p>
</Definition>
</dl>

<a href="#faq">
Expand Down
4 changes: 3 additions & 1 deletion app/_components/canvases/calibration-canvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { PointAction } from "@/_reducers/pointsReducer";
import { FullScreenHandle } from "react-full-screen";
import Matrix from "ml-matrix";
import { getCalibrationContextUpdatedWithEvent } from "@/_lib/calibration-context";
import { Unit } from "@/_lib/unit";

const maxPoints = 4; // One point per vertex in rectangle
const cornerMargin = 96;
Expand All @@ -44,7 +45,7 @@ export default function CalibrationCanvas({
width: number;
height: number;
isCalibrating: boolean;
unitOfMeasure: string;
unitOfMeasure: Unit;
displaySettings: DisplaySettings;
corners: Set<number>;
setCorners: Dispatch<SetStateAction<Set<number>>>;
Expand Down Expand Up @@ -246,6 +247,7 @@ export default function CalibrationCanvas({

return (
<canvas
data-testid="calibration-canvas"
tabIndex={0}
ref={canvasRef}
className={`${className} outline-none`}
Expand Down
Loading