From 16bfffe78f82d3f88255858e669e6abb65b4d787 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sat, 28 Mar 2026 18:29:15 -0500 Subject: [PATCH] I need extra eyes. --- client/homebrew/brewRenderer/brewRenderer.jsx | 1 - client/homebrew/homebrew.jsx | 3 +- client/homebrew/pages/embedPage/embedPage.jsx | 163 ++++++++++++++++++ .../homebrew/pages/embedPage/embedPage.less | 4 + server/app.js | 9 - 5 files changed, 169 insertions(+), 11 deletions(-) create mode 100644 client/homebrew/pages/embedPage/embedPage.jsx create mode 100644 client/homebrew/pages/embedPage/embedPage.less diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index bf684cc0e..56d3f25b2 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -272,7 +272,6 @@ const BrewRenderer = (props)=>{ const frameDidMount = ()=>{ //This triggers when iFrame finishes internal "componentDidMount" scrollToHash(window.location.hash); - console.log('Frame'); setTimeout(()=>{ //We still see a flicker where the style isn't applied yet, so wait 100ms before showing iFrame renderPages(); //Make sure page is renderable before showing setState((prevState)=>({ diff --git a/client/homebrew/homebrew.jsx b/client/homebrew/homebrew.jsx index 99b3e8fb4..afe0f2b16 100644 --- a/client/homebrew/homebrew.jsx +++ b/client/homebrew/homebrew.jsx @@ -9,6 +9,7 @@ import HomePage from './pages/homePage/homePage.jsx'; import EditPage from './pages/editPage/editPage.jsx'; import UserPage from './pages/userPage/userPage.jsx'; import SharePage from './pages/sharePage/sharePage.jsx'; +import EmbedPage from './pages/embedPage/embedPage.jsx'; import NewPage from './pages/newPage/newPage.jsx'; import ErrorPage from './pages/errorPage/errorPage.jsx'; import VaultPage from './pages/vaultPage/vaultPage.jsx'; @@ -71,7 +72,7 @@ const Homebrew = (props)=>{ } /> } /> - } /> + } /> } /> } /> } /> diff --git a/client/homebrew/pages/embedPage/embedPage.jsx b/client/homebrew/pages/embedPage/embedPage.jsx new file mode 100644 index 000000000..ac68d721f --- /dev/null +++ b/client/homebrew/pages/embedPage/embedPage.jsx @@ -0,0 +1,163 @@ +import './embedPage.less'; +import React, { useState, useEffect, useCallback, useRef } from 'react'; +import Headtags from '../../../../vitreum/headtags.js'; +import MarkdownLegacy from '@shared/markdownLegacy.js'; +import Markdown from '@shared/markdown.js'; + +const Meta = Headtags.Meta; + +import Nav from '@navbar/nav.jsx'; +import Navbar from '@navbar/navbar.jsx'; +import MetadataNav from '@navbar/metadata.navitem.jsx'; +import PrintNavItem from '@navbar/print.navitem.jsx'; +import RecentNavItems from '@navbar/recent.navitem.jsx'; +const { both: RecentNavItem } = RecentNavItems; +import Account from '@navbar/account.navitem.jsx'; +import safeHTML from '../../brewRenderer/safeHTML.js'; + +import { DEFAULT_BREW_LOAD } from '../../../../server/brewDefaults.js'; +import { printCurrentBrew, fetchThemeBundle } from '@shared/helpers.js'; +import _ from 'lodash'; + +const PAGEBREAK_REGEX_V3 = /^(?=\\page(?:break)?(?: *{[^\n{}]*})?$)/m; +const PAGEBREAK_REGEX_LEGACY = /\\page(?:break)?/m; +const COLUMNBREAK_REGEX_LEGACY = /\\column(:?break)?/m; + +let renderedPages = []; +let rawPages = []; + +const BrewPage = (props)=>{ + props = { + contents : '', + index : 0, + ...props + }; + const pageRef = useRef(null); + const cleanText = safeHTML(props.contents); + + return
+
+
; +}; + + +const EmbedPage = (props)=>{ + const [displayOptions, setDisplayOptions] = useState({ + zoomLevel : 100, + spread : 'single', + startOnRight : true, + pageShadows : true, + rowGap : 5, + columnGap : 10, + }); + + if(props.renderer == 'legacy') { + rawPages = props.brew.text.split(PAGEBREAK_REGEX_LEGACY); + } else { + rawPages = props.brew.text.split(PAGEBREAK_REGEX_V3); + } + + const pagesStyle = { + zoom : `${displayOptions.zoomLevel}%`, + columnGap : `${displayOptions.columnGap}px`, + rowGap : `${displayOptions.rowGap}px`, + overflowY : 'auto' + }; + + const { brew = DEFAULT_BREW_LOAD, disableMeta = false, share = true } = props; + + const [themeBundle, setThemeBundle] = useState({}); + const [currentBrewRendererPageNum, setCurrentBrewRendererPageNum] = useState(1); + + const handleBrewRendererPageChange = useCallback((pageNumber)=>{ + setCurrentBrewRendererPageNum(pageNumber); + }, []); + + const handleControlKeys = (e)=>{ + if(!(e.ctrlKey || e.metaKey)) return; + const P_KEY = 80; + if(e.keyCode === P_KEY) { + printCurrentBrew(); + e.stopPropagation(); + e.preventDefault(); + } + }; + + useEffect(()=>{ + document.addEventListener('keydown', handleControlKeys); + fetchThemeBundle(undefined, setThemeBundle, brew.renderer, brew.theme); + + return ()=>{ + document.removeEventListener('keydown', handleControlKeys); + }; + }, []); + + const renderStyle = ()=>{ + const themeStyles = themeBundle?.joinedStyles ?? ''; + const cleanStyle = safeHTML(`${themeStyles} \n\n `); + return
; + }; + + const renderPage = (pageText, index)=>{ + + let styles = { + ...(!displayOptions.pageShadows ? { boxShadow: 'none' } : {}), + marginTop : '10px' + // Add more conditions as needed + }; + let classes = 'page'; + let attributes = {}; + + if(props.renderer == 'legacy') { + pageText.replace(COLUMNBREAK_REGEX_LEGACY, '```\n````\n'); // Allow Legacy brews to use `\column(break)` + const html = MarkdownLegacy.render(pageText); + + return ; + } else { + if(pageText.startsWith('\\page')) { + const firstLineTokens = Markdown.marked.lexer(pageText.split('\n', 1)[0])[0].tokens; + const injectedTags = firstLineTokens?.find((obj)=>obj.injectedTags !== undefined)?.injectedTags; + if(injectedTags) { + styles = { ...styles, ...injectedTags.styles }; + styles = _.mapKeys(styles, (v, k)=>k.startsWith('--') ? k : _.camelCase(k)); // Convert CSS to camelCase for React + classes = [classes, injectedTags.classes].join(' ').trim(); + attributes = injectedTags.attributes; + } + pageText = pageText.includes('\n') ? pageText.substring(pageText.indexOf('\n') + 1) : ''; // Remove the \page line + } + + // DO NOT REMOVE!!! REQUIRED FOR BACKWARDS COMPATIBILITY WITH NON-UPGRADABLE VERSIONS OF CHROME. + pageText += `\n\n \n\\column\n `; //Artificial column break at page end to emulate column-fill:auto (until `wide` is used, when column-fill:balance will reappear) + + const html = Markdown.render(pageText, index); + + return ; + } + }; + + const renderPages = ()=>{ + if(props.errors && props.errors.length) + return renderedPages; + + renderedPages.length = 0; + + _.forEach(rawPages, (page, index)=>{ + { + renderedPages[index] = renderPage(page, index); // Render any page not yet rendered, but only re-render those in PPR range + } + }); + return renderedPages; + }; + + return ( +
+ + {renderStyle()} +
+ {renderPages()} +
+
+ ); +}; + +export default EmbedPage; diff --git a/client/homebrew/pages/embedPage/embedPage.less b/client/homebrew/pages/embedPage/embedPage.less new file mode 100644 index 000000000..c6cfd0438 --- /dev/null +++ b/client/homebrew/pages/embedPage/embedPage.less @@ -0,0 +1,4 @@ +@page { + margin : 0; + size : 8.5in 11in; +} diff --git a/server/app.js b/server/app.js index 6910b386f..f94fc5f1b 100644 --- a/server/app.js +++ b/server/app.js @@ -80,18 +80,9 @@ export default async function createApp(vite) { const herokuRegex = /^https:\/\/(?:homebrewery-pr-\d+\.herokuapp\.com|naturalcrit-pr-\d+\.herokuapp\.com)$/; // Matches any Heroku app - console.log( 'IsLocalEnvironment'); - console.log(isLocalEnvironment); - console.log('localNetworkRegex'); - console.log(localNetworkRegex.test(origin)); - console.log('origin'); - console.log(origin === 'null'); - console.log(origin); - if(!origin || origin === 'null' || allowedOrigins.includes(origin) || herokuRegex.test(origin) || (isLocalEnvironment && localNetworkRegex.test(origin))) { callback(null, true); } else { - console.log(origin, 'not allowed'); callback(new Error('Not allowed by CORS, if you think this is an error, please contact us - Skidoosh')); } },