diff --git a/app/globals.css b/app/globals.css
index ae584c7a..46a82ac9 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -107,8 +107,15 @@
--highlight-3: 255, 205, 195;
--list-marker-width: 36px;
- --page-width-unitless: min(624, calc(var(--leaflet-width-unitless) - 12));
- --page-width-units: min(624px, calc(100vw - 12px));
+ --page-max-width-unitless: 624;
+ --page-width-unitless: min(
+ var(--page-max-width-unitless),
+ calc(var(--leaflet-width-unitless) - 12)
+ );
+ --page-width-units: min(
+ calc(var(--page-max-width-unitless) * 1px),
+ calc(100vw - 12px)
+ );
--gripperSVG: url("/gripperPattern.svg");
--gripperSVG2: url("/gripperPattern2.svg");
@@ -126,20 +133,26 @@
@media (min-width: 640px) {
:root {
--page-width-unitless: min(
- 624,
+ var(--page-max-width-unitless),
calc(var(--leaflet-width-unitless) - 128)
);
- --page-width-units: min(624px, calc(100vw - 128px));
+ --page-width-units: min(
+ calc(var(--page-max-width-unitless) * 1px),
+ calc(100vw - 128px)
+ );
}
}
@media (min-width: 1280px) {
:root {
--page-width-unitless: min(
- 624,
+ var(--page-max-width-unitless),
calc((var(--leaflet-width-unitless) / 2) - 32)
);
- --page-width-units: min(624px, calc((100vw / 2) - 32px));
+ --page-width-units: min(
+ calc(var(--page-max-width-unitless) * 1px),
+ calc((100vw / 2) - 32px)
+ );
}
}
diff --git a/components/ThemeManager/Pickers/ImagePicker.tsx b/components/ThemeManager/Pickers/ImagePicker.tsx
index b5203df2..3b0a3b79 100644
--- a/components/ThemeManager/Pickers/ImagePicker.tsx
+++ b/components/ThemeManager/Pickers/ImagePicker.tsx
@@ -127,8 +127,8 @@ export const ImageSettings = (props: {
diff --git a/components/ThemeManager/Pickers/PageThemePickers.tsx b/components/ThemeManager/Pickers/PageThemePickers.tsx
index 8aaf4a61..5238caa8 100644
--- a/components/ThemeManager/Pickers/PageThemePickers.tsx
+++ b/components/ThemeManager/Pickers/PageThemePickers.tsx
@@ -51,7 +51,7 @@ export const PageThemePickers = (props: {
>
)}
- void;
value: Color;
diff --git a/components/ThemeManager/Pickers/PageWidthSetter.tsx b/components/ThemeManager/Pickers/PageWidthSetter.tsx
new file mode 100644
index 00000000..d69457dd
--- /dev/null
+++ b/components/ThemeManager/Pickers/PageWidthSetter.tsx
@@ -0,0 +1,120 @@
+import * as Slider from "@radix-ui/react-slider";
+import { Input } from "components/Input";
+import { useEntity, useReplicache } from "src/replicache";
+import { pickers } from "../ThemeSetter";
+import { useState } from "react";
+
+export const PageWidthSetter = (props: {
+ entityID: string;
+ openPicker: pickers;
+ thisPicker: pickers;
+ setOpenPicker: (thisPicker: pickers) => void;
+ closePicker: () => void;
+}) => {
+ let { rep } = useReplicache();
+ let pageWidth = useEntity(props.entityID, "theme/page-width");
+ let currentValue = pageWidth?.data.value || 624;
+ let [interimValue, setInterimValue] = useState(currentValue);
+ let min = 324;
+ let max = 1200;
+
+ let open = props.openPicker == props.thisPicker;
+
+ return (
+
+
+
+
+
+ {
+ e.preventDefault();
+ props.setOpenPicker(props.thisPicker);
+ }}
+ onChange={(e) => {
+ setInterimValue(parseInt(e.currentTarget.value));
+ }}
+ onKeyDown={(e) => {
+ if (e.key === "Enter" || e.key === "Escape") {
+ e.preventDefault();
+ let clampedValue = interimValue;
+ if (!isNaN(interimValue)) {
+ clampedValue = Math.max(min, Math.min(max, interimValue));
+ setInterimValue(clampedValue);
+ }
+ rep?.mutate.assertFact({
+ entity: props.entityID,
+ attribute: "theme/page-width",
+ data: {
+ type: "number",
+ value: clampedValue,
+ },
+ });
+ }
+ }}
+ onBlur={() => {
+ let clampedValue = interimValue;
+ if (!isNaN(interimValue)) {
+ clampedValue = Math.max(min, Math.min(max, interimValue));
+ setInterimValue(clampedValue);
+ }
+ rep?.mutate.assertFact({
+ entity: props.entityID,
+ attribute: "theme/page-width",
+ data: {
+ type: "number",
+ value: clampedValue,
+ },
+ });
+ }}
+ />
+ px
+
+
+ {open && (
+
{
+ setInterimValue(value[0]);
+ }}
+ onPointerUp={() => {
+ rep?.mutate.assertFact({
+ entity: props.entityID,
+ attribute: "theme/page-width",
+ data: { type: "number", value: interimValue },
+ });
+ }}
+ >
+
+
+
+ )}
+
+
+ );
+};
diff --git a/components/ThemeManager/PubPickers/PubTextPickers.tsx b/components/ThemeManager/PubPickers/PubTextPickers.tsx
index 8ea5413e..9902afe9 100644
--- a/components/ThemeManager/PubPickers/PubTextPickers.tsx
+++ b/components/ThemeManager/PubPickers/PubTextPickers.tsx
@@ -1,5 +1,5 @@
import { pickers } from "../ThemeSetter";
-import { PageTextPicker } from "../Pickers/PageThemePickers";
+import { TextPickers } from "../Pickers/PageThemePickers";
import { Color } from "react-aria-components";
export const PagePickers = (props: {
@@ -20,7 +20,7 @@ export const PagePickers = (props: {
: "transparent",
}}
>
-
{props.children}
@@ -106,6 +109,7 @@ export const BaseThemeProvider = ({
highlight2,
highlight3,
showPageBackground,
+ pageWidth,
children,
}: {
local?: boolean;
@@ -118,6 +122,7 @@ export const BaseThemeProvider = ({
highlight1?: string;
highlight2: AriaColor;
highlight3: AriaColor;
+ pageWidth?: number;
children: React.ReactNode;
}) => {
// set accent contrast to the accent color that has the highest contrast with the page background
@@ -196,6 +201,12 @@ export const BaseThemeProvider = ({
"--accent-1-is-contrast",
accentContrast === accent1 ? "1" : "0",
);
+
+ // Set page width CSS variable
+ el?.style.setProperty(
+ "--page-max-width-unitless",
+ (pageWidth || 624).toString(),
+ );
}, [
local,
bgLeaflet,
@@ -207,6 +218,7 @@ export const BaseThemeProvider = ({
accent1,
accent2,
accentContrast,
+ pageWidth,
]);
return (
diff --git a/components/ThemeManager/ThemeSetter.tsx b/components/ThemeManager/ThemeSetter.tsx
index 4afc5917..c55654e6 100644
--- a/components/ThemeManager/ThemeSetter.tsx
+++ b/components/ThemeManager/ThemeSetter.tsx
@@ -10,6 +10,7 @@ import {
PageBorderHider,
PageThemePickers,
} from "./Pickers/PageThemePickers";
+import { PageWidthSetter } from "./Pickers/PageWidthSetter";
import { useMemo, useState } from "react";
import { ReplicacheMutators, useEntity, useReplicache } from "src/replicache";
import { Replicache } from "replicache";
@@ -35,7 +36,8 @@ export type pickers =
| "highlight-1"
| "highlight-2"
| "highlight-3"
- | "page-background-image";
+ | "page-background-image"
+ | "page-width";
export function setColorAttribute(
rep: Replicache
| null,
@@ -75,7 +77,7 @@ export const ThemePopover = (props: { entityID: string; home?: boolean }) => {
return (
<>
+ setOpenPicker("null")}
+ />
diff --git a/src/replicache/attributes.ts b/src/replicache/attributes.ts
index a902d078..c2d71974 100644
--- a/src/replicache/attributes.ts
+++ b/src/replicache/attributes.ts
@@ -191,6 +191,10 @@ export const ThemeAttributes = {
type: "boolean",
cardinality: "one",
},
+ "theme/page-width": {
+ type: "number",
+ cardinality: "one",
+ },
"theme/page-background": {
type: "color",
cardinality: "one",