diff --git a/frontend/Dockerfile b/frontend/Dockerfile
index 4543977..5603a97 100644
--- a/frontend/Dockerfile
+++ b/frontend/Dockerfile
@@ -1,7 +1,10 @@
FROM node:20-alpine AS builder
WORKDIR /app
-ARG VITE_PUBLIC_SITE_URL="https://www.thetriangle.org"
+# Baked in at build time (Vite inlines import.meta.env), so this is the origin
+# every "View Live" link and permalink preview in the published image points at.
+# Override with --build-arg to publish an image aimed at another site.
+ARG VITE_PUBLIC_SITE_URL="https://dev.thetriangle.org"
ENV VITE_PUBLIC_SITE_URL=${VITE_PUBLIC_SITE_URL}
COPY package.json package-lock.json ./
diff --git a/frontend/src/auth/urls.ts b/frontend/src/auth/urls.ts
index df3a2d0..8535c00 100644
--- a/frontend/src/auth/urls.ts
+++ b/frontend/src/auth/urls.ts
@@ -10,8 +10,11 @@ export function authBaseUrl() {
return trimTrailingSlashes(import.meta.env.VITE_AUTH_BASE_URL ?? "")
}
-// Public-facing site origin, used to build article permalinks (e.g. so Yoast can
-// tell internal links from outbound ones).
+// Public-facing site origin, used for article permalinks (e.g. so Yoast can
+// tell internal links from outbound ones) and for the "View Live" links.
+// Defaults to the dev site: the CMS is not yet driving production, so an
+// unconfigured build pointing at www would send editors to pages that do not
+// reflect what they just saved.
export function publicSiteUrl() {
- return trimTrailingSlashes(import.meta.env.VITE_PUBLIC_SITE_URL ?? "https://www.thetriangle.org")
+ return trimTrailingSlashes(import.meta.env.VITE_PUBLIC_SITE_URL ?? "https://dev.thetriangle.org")
}
diff --git a/frontend/src/pages/DashboardPage.tsx b/frontend/src/pages/DashboardPage.tsx
index d47fb10..2c54292 100644
--- a/frontend/src/pages/DashboardPage.tsx
+++ b/frontend/src/pages/DashboardPage.tsx
@@ -1,6 +1,7 @@
import { useEffect, useState } from "react"
import { useNavigate } from "react-router-dom"
import { useApiFetch } from "../hooks/useApiFetch"
+import { publicSiteUrl } from "../auth/urls"
import { useSessionAuth } from "../auth/sessionAuthContext"
import {
FileText,
@@ -336,7 +337,7 @@ export default function DashboardPage() {
variant="outline"
size="sm"
className="gap-1.5"
- onClick={() => window.open("https://www.thetriangle.org", "_blank", "noopener,noreferrer")}
+ onClick={() => window.open(publicSiteUrl(), "_blank", "noopener,noreferrer")}
>
View site
diff --git a/frontend/src/pages/articleView.tsx b/frontend/src/pages/articleView.tsx
index f7a3d9b..49c1b58 100644
--- a/frontend/src/pages/articleView.tsx
+++ b/frontend/src/pages/articleView.tsx
@@ -1,6 +1,7 @@
-import { useEffect, useState } from "react"
+import { useEffect, useMemo, useState } from "react"
import { ExternalLink, Search, Pencil, Plus, Trash2, X, ChevronFirst, ChevronLast, ChevronLeft, ChevronRight, Undo2 } from "lucide-react"
import { useNavigate } from "react-router-dom"
+import { publicSiteUrl } from "../auth/urls"
import { useApiFetch } from "../hooks/useApiFetch"
type ArticleStatus = "Published" | "Draft" | "Archived"
@@ -103,6 +104,9 @@ const writeSessionJSON = (key: string, value: unknown) => {
function ArticleView({ pageTitle = "Articles", fixedType, excludeType }: ArticleViewProps) {
const navigate = useNavigate()
const apiFetch = useApiFetch()
+ // Same origin the comments view and the editor's permalink preview use, so
+ // "View Live" cannot point at a different site than the rest of the CMS.
+ const siteUrl = useMemo(() => publicSiteUrl(), [])
const storageKeyBase = `articleView:${fixedType ?? "all"}:${excludeType ?? "none"}`
const uiStateKey = `${storageKeyBase}:ui`
const resultsCacheKey = `${storageKeyBase}:results`
@@ -603,7 +607,7 @@ function ArticleView({ pageTitle = "Articles", fixedType, excludeType }: Article
{activeTab !== "trash" && item.status === "Published" && (