From 3280a1945ca5179360ee2ef71a98d422900e11e9 Mon Sep 17 00:00:00 2001 From: jimafisk Date: Sun, 8 Sep 2024 18:50:12 -0400 Subject: [PATCH] Redirect to newly evaluated route on content creation (#232). --- cmd/build/data_source.go | 13 ++++++++-- defaults/core/cms/add_content.svelte | 2 +- defaults/core/cms/post_local.js | 10 ++++++- defaults/core/cms/publish.js | 10 ++++++- defaults/core/cms/route_eval.js | 39 ++++++++++++++++++++++++++++ defaults/core/router.svelte | 7 +++++ 6 files changed, 76 insertions(+), 5 deletions(-) create mode 100644 defaults/core/cms/route_eval.js diff --git a/cmd/build/data_source.go b/cmd/build/data_source.go index 5f80a900..0cddabeb 100644 --- a/cmd/build/data_source.go +++ b/cmd/build/data_source.go @@ -60,6 +60,7 @@ type content struct { // Holds sitewide environment variables. type env struct { local string + routes map[string]string baseurl string fingerprint string entrypointHTML string @@ -85,6 +86,7 @@ func DataSource(buildPath string, spaPath string, siteConfig readers.SiteConfig) envPath := spaPath + "generated/env.js" env := env{ local: strconv.FormatBool(Local), + routes: siteConfig.Routes, baseurl: siteConfig.BaseURL, fingerprint: siteConfig.Fingerprint, entrypointHTML: siteConfig.EntryPointHTML, @@ -97,10 +99,17 @@ func DataSource(buildPath string, spaPath string, siteConfig readers.SiteConfig) }, } + flattenRoutes := "{" + for content_type, route := range env.routes { + flattenRoutes += content_type + ": '" + route + "', " + } + flattenRoutes = strings.TrimSuffix(flattenRoutes, ", ") + "}" + // Create env magic prop. envStr := "export let env = { local: " + env.local + ", baseurl: '" + env.baseurl + - "', fingerprint: '" + env.fingerprint + + "', routes: " + flattenRoutes + + ", fingerprint: '" + env.fingerprint + "', entrypointHTML: '" + env.entrypointHTML + "', entrypointJS: '" + env.entrypointJS + "', cms: { repo: '" + env.cms.repo + @@ -269,7 +278,7 @@ func getContent(path string, info os.FileInfo, err error, siteConfig readers.Sit for configContentType, slug := range siteConfig.Routes { if configContentType == contentType { // Replace :filename. - slug = strings.Replace(slug, ":filename", fileName, -1) + slug = strings.Replace(slug, ":filename", strings.TrimSuffix(fileName, ".json"), -1) // Replace :fields(). fieldReplacements := reField.FindAllStringSubmatch(slug, -1) diff --git a/defaults/core/cms/add_content.svelte b/defaults/core/cms/add_content.svelte index 1088f680..a9a6bacf 100644 --- a/defaults/core/cms/add_content.svelte +++ b/defaults/core/cms/add_content.svelte @@ -113,4 +113,4 @@ color: #1c7fc7; text-decoration: underline; } - \ No newline at end of file + diff --git a/defaults/core/cms/post_local.js b/defaults/core/cms/post_local.js index 09325678..217e6897 100644 --- a/defaults/core/cms/post_local.js +++ b/defaults/core/cms/post_local.js @@ -1,4 +1,5 @@ import { env } from '../../generated/env.js'; +import evaluateRoute from './route_eval.js'; export async function postLocal(commitList, shadowContent, action, encoding) { let url = '/postlocal'; @@ -21,6 +22,13 @@ export async function postLocal(commitList, shadowContent, action, encoding) { body: JSON.stringify(body), }); if (response.ok) { + if (commitList.length === 1 && action === 'create') { + let evaluatedRoute = evaluateRoute(commitList[0]); + history.pushState({ + isNew: true, + route: evaluatedRoute + }, '', evaluatedRoute); + } if (action === 'create' || action === 'update') { shadowContent?.onSave?.(); } @@ -32,4 +40,4 @@ export async function postLocal(commitList, shadowContent, action, encoding) { const { error, message } = await response.json(); throw new Error(`Publish failed: ${error || message}`); } -} \ No newline at end of file +} diff --git a/defaults/core/cms/publish.js b/defaults/core/cms/publish.js index 15d8fcb6..94dc112e 100644 --- a/defaults/core/cms/publish.js +++ b/defaults/core/cms/publish.js @@ -1,5 +1,6 @@ import { env } from '../../generated/env.js'; import { makeUrl } from './url_checker.js'; +import evaluateRoute from './route_eval.js'; const repoUrl = makeUrl(env.cms.repo); const apiBaseUrl = `${repoUrl.origin}/api/v4`; @@ -63,6 +64,13 @@ export async function publish(commitList, shadowContent, action, encoding, user) body: JSON.stringify(payload), }); if (response.ok) { + if (commitList.length === 1 && action === 'create') { + let evaluatedRoute = evaluateRoute(commitList[0]); + history.pushState({ + isNew: true, + route: evaluatedRoute + }, '', evaluatedRoute); + } if (action === 'create' || action === 'update') { shadowContent?.onSave?.(); } @@ -74,4 +82,4 @@ export async function publish(commitList, shadowContent, action, encoding, user) const { error, message } = await response.json(); throw new Error(`Publish failed: ${error || message}`); } -} \ No newline at end of file +} diff --git a/defaults/core/cms/route_eval.js b/defaults/core/cms/route_eval.js new file mode 100644 index 00000000..7eb29b6d --- /dev/null +++ b/defaults/core/cms/route_eval.js @@ -0,0 +1,39 @@ +import { env } from '../../generated/env.js'; + +export default function evaluateRoute(commitItem) { + let content_type = window.location.hash.split("/")[1]; + let filename = window.location.hash.split("/")[2]; + let filepath = commitItem.file; + let fields = JSON.parse(commitItem.contents); + let default_route = "/" + content_type + "/" + filename; + let route_pattern = env?.routes?.[content_type] ?? default_route; + + // Replace patterns with actual values + let route = replaceRouteFields(route_pattern, fields); + route = route.replace(':filename', filename); + route = route.replace(':filepath', filepath); + return route; +} + +function replaceRouteFields(route, fields) { + // Regular expression to match :fields(name) pattern + const fieldRegex = /:fields\((\w+)\)/g; + + // Replace each match with the corresponding value from the fields object + return route.replace(fieldRegex, (match, fieldName) => { + if (fieldName in fields) { + return slugify(fields[fieldName]); + } + // If the field is not found in the object, return the original match + return match; + }); +} + +function slugify(str) { + str = str.replace(/^\s+|\s+$/g, ''); // trim leading/trailing white space + str = str.toLowerCase(); // convert string to lowercase + str = str.replace(/[^a-z0-9 -]/g, '') // remove any non-alphanumeric characters + .replace(/\s+/g, '-') // replace spaces with hyphens + .replace(/-+/g, '-'); // remove consecutive hyphens + return str; +} diff --git a/defaults/core/router.svelte b/defaults/core/router.svelte index 7dd15a38..16d6336b 100755 --- a/defaults/core/router.svelte +++ b/defaults/core/router.svelte @@ -24,6 +24,13 @@ } function track(obj) { + if (obj?.uri?.isNew) { + // Add newly generated route to router + router.on(obj?.uri?.route, () => { + // Additional edits should be updates + content.isNew = false; + }); + } path = obj.state || obj.uri || location.pathname; params = new URLSearchParams(location.search); }