diff --git a/CHANGELOG.md b/CHANGELOG.md
index fb4d655..5b99c79 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,12 +10,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Side menu for stitch, layers, and scale menus
-- Scale menu for changing the pattern scale
+- Scale menu for changing the pattern scale (modified to use percentage instead of decimal)
- "Open With Pattern Projector" for PDF files on desktop, when installed with Chrome/Edge
- Show a pop up when there's an error
- Change page range in stitch menu with +/- (use + to throw beginning pages at the end e.g. for instruction pages)
- Option to arrange stitched pages by column order
- Support for SVG (with layer visibility toggling), PNG, and JPEG
+- Modified open pdf message slightly to add styling
### Changed
diff --git a/app/[locale]/calibrate/page.tsx b/app/[locale]/calibrate/page.tsx
index bbd0931..d2afbcc 100644
--- a/app/[locale]/calibrate/page.tsx
+++ b/app/[locale]/calibrate/page.tsx
@@ -75,6 +75,7 @@ import { Button } from "@/_components/buttons/button";
import { erosionFilter } from "@/_lib/erode";
import SvgViewer from "@/_components/svg-viewer";
import { toggleFullScreen } from "@/_lib/full-screen";
+import ModifiersBanner from "@/_components/modifiers-banner";
const defaultStitchSettings = {
lineCount: 1,
@@ -296,7 +297,7 @@ export default function Page() {
setMeasuring(false);
setPageCount(0);
setLayers({});
- dispatchPatternScaleAction({ type: "set", scale: "1.00" });
+ dispatchPatternScaleAction({ type: "set", scale: "1.000" });
const lineThicknessString = localStorage.getItem(
`lineThickness:${files[0].name}`,
);
@@ -698,15 +699,16 @@ export default function Page() {
zoomedOut={zoomedOut}
magnifying={magnifying}
restoreTransforms={restoreTransforms}
- patternScale={String(patternScaleFactor)}
+ // patternScale={String(patternScaleFactor)}
/>
)}
+
{!isCalibrating && file !== null && (
(null);
@@ -74,7 +72,6 @@ export default function OverlayCanvas({
magnifying,
restoreTransforms,
t,
- patternScale,
);
drawOverlays(cs);
}
@@ -91,7 +88,6 @@ export default function OverlayCanvas({
magnifying,
restoreTransforms,
t,
- patternScale,
]);
return (
>;
widthInput: string;
@@ -370,7 +372,7 @@ export default function Header({
{
+ const number = +patternScale;
+ if (Number.isNaN(number)) {
+ return "1";
+ }
+ return patternScale;
+ }, [patternScale]);
+
return (
dispatchPatternScaleAction({ type: "delta", delta: delta })
}
- step={0.1}
+ step={0.05}
>
);
diff --git a/app/_components/menus/side-menu.tsx b/app/_components/menus/side-menu.tsx
index 9c70b0e..693f3b8 100644
--- a/app/_components/menus/side-menu.tsx
+++ b/app/_components/menus/side-menu.tsx
@@ -18,8 +18,10 @@ import { StitchSettings } from "@/_lib/interfaces/stitch-settings";
import { LayerAction } from "@/_reducers/layersReducer";
import { PatternScaleAction } from "@/_reducers/patternScaleReducer";
import TuneIcon from "@/_icons/tune-icon";
+import { visible } from "@/_components/theme/css-functions";
export default function SideMenu({
+ hidden,
menuStates,
setMenuStates,
pageCount,
@@ -31,6 +33,7 @@ export default function SideMenu({
patternScale,
dispatchPatternScaleAction,
}: {
+ hidden: boolean;
menuStates: MenuStates;
setMenuStates: Dispatch>;
pageCount: number;
@@ -51,7 +54,7 @@ export default function SideMenu({
pageCount === 0 || file?.name.toLocaleUpperCase().endsWith(".SVG");
return (
-
+
{/* reverse so the tooltips show on top */}
diff --git a/app/_components/modifiers-banner.tsx b/app/_components/modifiers-banner.tsx
new file mode 100644
index 0000000..fbe9bf3
--- /dev/null
+++ b/app/_components/modifiers-banner.tsx
@@ -0,0 +1,35 @@
+import React, { useMemo } from "react";
+import { visible } from "@/_components/theme/css-functions";
+import { decimalToString } from "@/_lib/remove-non-digits";
+import { useTranslations } from "next-intl";
+
+export default function ModifiersBanner({
+ patternScale,
+}: {
+ patternScale?: number;
+}) {
+ const t = useTranslations("OverlayCanvas");
+ const hidden = useMemo(() => {
+ if (!patternScale || patternScale === 1) {
+ return true;
+ }
+ return false;
+ }, [patternScale]);
+
+ const text = useMemo(() => {
+ if (patternScale && patternScale !== 1) {
+ return t.rich("scaled", {
+ scale: () => decimalToString(patternScale, 2),
+ scaleP: () => decimalToString(patternScale * 100, 1),
+ });
+ }
+ }, [patternScale]);
+
+ return (
+
+ {text}
+
+ );
+}
diff --git a/app/_components/pdf-viewer.tsx b/app/_components/pdf-viewer.tsx
index 8b1f36e..f41b83a 100644
--- a/app/_components/pdf-viewer.tsx
+++ b/app/_components/pdf-viewer.tsx
@@ -25,7 +25,8 @@ import { getLayersFromPdf, Layers } from "@/_lib/layers";
import { LoadStatusEnum } from "@/_lib/load-status-enum";
import { Point } from "@/_lib/point";
import { useTranslations } from "next-intl";
-import { MenuStates, getDefaultMenuStates } from "@/_lib/menu-states";
+import { getDefaultMenuStates, MenuStates } from "@/_lib/menu-states";
+import PdfIcon from "@/_icons/pdf-icon";
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
"pdfjs-dist/build/pdf.worker.min.js",
@@ -75,6 +76,7 @@ export default function PdfViewer({
);
const transformer = useTransformerContext();
const t = useTranslations("PdfViewer");
+ const h = useTranslations("Header");
function onDocumentLoadSuccess(docProxy: PDFDocumentProxy) {
const numPages = docProxy.numPages;
@@ -170,7 +172,22 @@ export default function PdfViewer({
{t("noData")}}
+ noData={
+
+
{t("noDataFirst")}
+
+
{t("noDataLast")}
+
+ }
error={{t("error")}
}
onLoadError={() => setFileLoadStatus(LoadStatusEnum.FAILED)}
>
diff --git a/app/_components/theme/colors.ts b/app/_components/theme/colors.ts
index f7c4c54..f063ac2 100644
--- a/app/_components/theme/colors.ts
+++ b/app/_components/theme/colors.ts
@@ -29,8 +29,8 @@ export function getColorClasses(
}
case ButtonColor.PURPLE: {
return style === ButtonStyle.OUTLINE
- ? "text-purple-700 border-purple-700 hover:bg-purple-800 focus:ring-purple-300 dark:border-purple-500 dark:text-purple-500 dark:hover:bg-purple-500 dark:focus:ring-purple-800"
- : "bg-purple-700 hover:bg-purple-800 focus:ring-purple-300 dark:bg-purple-600 dark:hover:bg-purple-700 dark:focus:ring-purple-800";
+ ? "btn-primary-outline"
+ : "btn-primary";
}
}
}
diff --git a/app/_components/theme/styles.ts b/app/_components/theme/styles.ts
index 75aedb7..5a7052f 100644
--- a/app/_components/theme/styles.ts
+++ b/app/_components/theme/styles.ts
@@ -9,4 +9,10 @@ export function getButtonStyleClasses(style: ButtonStyle) {
: `flex gap-2 items-center text-white focus:ring-4 font-medium rounded-lg text-sm px-5 py-2.5 focus:outline-none`;
}
+export function getStaticButtonStyleClasses(style: ButtonStyle) {
+ return style === ButtonStyle.OUTLINE
+ ? `flex gap-2 dark:bg-black bg-white items-center border border-2 border-solid focus:outline-none font-medium rounded-lg text-sm px-5 py-2.5 text-center`
+ : `flex gap-2 items-center text-white font-medium rounded-lg text-sm px-5 py-2.5`;
+}
+
export const sideMenuStyles = `flex flex-col gap-2 p-2 w-64 items-start bg-white dark:bg-black border-b border-r border-gray-200 dark:border-gray-700`;
diff --git a/app/_lib/drawing.ts b/app/_lib/drawing.ts
index 282ee01..2a773c2 100644
--- a/app/_lib/drawing.ts
+++ b/app/_lib/drawing.ts
@@ -41,7 +41,6 @@ export class CanvasState {
public magnifying: boolean,
public restoreTransforms: RestoreTransforms | null,
public t: any,
- public patternScale: string | null,
) {
this.isConcave = checkIsConcave(this.points);
}
@@ -113,15 +112,8 @@ export function drawPolygon(
}
export function drawOverlays(cs: CanvasState) {
- const {
- ctx,
- displaySettings,
- zoomedOut,
- t,
- magnifying,
- restoreTransforms,
- patternScale,
- } = cs;
+ const { ctx, displaySettings, zoomedOut, t, magnifying, restoreTransforms } =
+ cs;
const { grid, border, paper, flipLines, flippedPattern, disabled } =
displaySettings.overlay;
const { theme } = displaySettings;
@@ -153,14 +145,14 @@ export function drawOverlays(cs: CanvasState) {
if (flippedPattern && cs.isFlipped) {
drawFlippedPattern(cs);
}
- if (patternScale && Number(patternScale) !== 1) {
- drawMessage(
- cs,
- t.rich("scaled", {
- scale: () => String(Number(patternScale).toFixed(2)),
- }),
- );
- }
+ // if (patternScale && Number(patternScale) !== 1) {
+ // drawMessage(
+ // cs,
+ // t.rich("scaled", {
+ // scale: () => String(Number(patternScale).toFixed(2)),
+ // }),
+ // );
+ // }
}
}
diff --git a/app/_lib/remove-non-digits.ts b/app/_lib/remove-non-digits.ts
index 68dc42a..9b6c502 100644
--- a/app/_lib/remove-non-digits.ts
+++ b/app/_lib/remove-non-digits.ts
@@ -14,6 +14,19 @@ export default function removeNonDigits(
}
}
+export function roundTo(num: number, decimalDigits: number) {
+ const factor = 10 ** decimalDigits; // Takes 10^num
+ return Math.round(num * factor) / factor;
+}
+
+export function decimalToString(num: number, decimalDigits: number) {
+ const roundedNum = roundTo(num, decimalDigits);
+ if (Number.isInteger(roundedNum)) {
+ return num.toFixed(0);
+ }
+ return num.toFixed(decimalDigits);
+}
+
export function allowInteger(
s: string,
allowNegative: boolean = false,
diff --git a/app/_reducers/patternScaleReducer.ts b/app/_reducers/patternScaleReducer.ts
index 0f78efb..301969a 100644
--- a/app/_reducers/patternScaleReducer.ts
+++ b/app/_reducers/patternScaleReducer.ts
@@ -1,3 +1,5 @@
+import { roundTo } from "@/_lib/remove-non-digits";
+
interface DeltaAction {
type: "delta";
delta: number;
@@ -19,8 +21,8 @@ export default function PatternScaleReducer(
return action.scale;
}
case "delta": {
- const n = action.delta + Number(patternScale);
- const hm = n > 0 ? String(n.toFixed(2)) : patternScale;
+ const n = roundTo(action.delta + Number(patternScale), 3);
+ const hm = n > 0 ? n.toFixed(3) : patternScale;
return hm;
}
}
diff --git a/messages/en.json b/messages/en.json
index b141bd2..c3eb80a 100644
--- a/messages/en.json
+++ b/messages/en.json
@@ -325,10 +325,11 @@
"OverlayCanvas": {
"zoomedOut": "click pattern to zoom in",
"magnifying": "click pattern to stop magnifying",
- "scaled": " × scale"
+ "scaled": "Scaled to x ( %)"
},
"PdfViewer": {
"error": "Failed to load pattern",
- "noData": "Press the \"Open\" button to load a pattern"
+ "noDataFirst": "Press the",
+ "noDataLast": "button to load a pattern"
}
}
diff --git a/tailwind.config.ts b/tailwind.config.ts
index 4e0fa79..87e4f8a 100644
--- a/tailwind.config.ts
+++ b/tailwind.config.ts
@@ -14,5 +14,18 @@ const config: Config = {
require("@tailwindcss/typography"),
require("@tailwindcss/aspect-ratio"),
],
+ theme: {
+ extend: {
+ keyframes: {
+ breathe: {
+ "0%, 100%": { color: "" }, // Primary color
+ "50%": { color: "#FACC15" }, // Secondary color
+ },
+ },
+ animation: {
+ breathe: "breathe 1.5s ease-in-out infinite",
+ },
+ },
+ },
};
export default config;