diff --git a/src/components/Share.jsx b/src/components/Share.jsx index 5d9183d..88484c6 100644 --- a/src/components/Share.jsx +++ b/src/components/Share.jsx @@ -18,6 +18,55 @@ const TOGGLE_VISIBILITY_API = ? 'http://127.0.0.1:5001/web-maker-app/us-central1/toggleVisibility' : */ 'https://togglevisibility-ajhkrtmkaq-uc.a.run.app'; +// Layout mode definitions with icons +const LAYOUT_MODES = [ + { + id: 1, + name: 'Preview on right', + icon: ( + + + + ) + }, + { + id: 2, + name: 'Preview on bottom', + icon: ( + + + + ) + }, + { + id: 3, + name: 'Preview on left', + icon: ( + + + + ) + }, + { + id: 4, + name: 'Full screen preview', + icon: ( + + + + ) + }, + { + id: 5, + name: 'Three-pane horizontal', + icon: ( + + + + ) + } +]; + export function Share({ user, item, @@ -26,6 +75,8 @@ export function Share({ onProBtnClick }) { const [publicItemCount, setPublicItemCount] = useState(); + const [selectedLayout, setSelectedLayout] = useState(2); // Default to layout 2 + useEffect(() => { if (!user) return; window.db.getPublicItemCount(user.uid).then(c => { @@ -75,10 +126,16 @@ export function Share({ } }; + const getShareUrl = () => { + const baseUrl = `${BASE_URL}/create/${item.id}`; + return selectedLayout ? `${baseUrl}?layout=${selectedLayout}` : baseUrl; + }; + const copyUrl = () => { - navigator.clipboard.writeText(`${BASE_URL}/create/${item.id}`); + navigator.clipboard.writeText(getShareUrl()); alertsService.add('URL copied to clipboard'); }; + if (!user) { return ( @@ -106,19 +163,70 @@ export function Share({

)} {item.isPublic && ( -

- Public at{' '} - - {BASE_URL}/create/{item.id} - {' '} - -

+ +

+ Public at{' '} + + {getShareUrl()} + {' '} + +

+ + {/* Layout Mode Selector */} + + + + {LAYOUT_MODES.map(layout => ( + + ))} + + +
)} diff --git a/src/style.css b/src/style.css index b2cb9ca..6271fec 100644 --- a/src/style.css +++ b/src/style.css @@ -14,6 +14,7 @@ --color-text-light: #b0a5d6; --color-text-lightest-final: #787090; --clr-brand: purple; + --clr-brand-2: #e3ba26; --color-pro-1: #1fffb3; --color-pro-2: #f2ff00; @@ -808,7 +809,7 @@ li.CodeMirror-hint-active { /*color: white;*/ } -[data-type="css"] .cm-error { +[data-type='css'] .cm-error { background: inherit !important; } diff --git a/tests/layout-parameter.test.js b/tests/layout-parameter.test.js index 431a635..aea69b0 100644 --- a/tests/layout-parameter.test.js +++ b/tests/layout-parameter.test.js @@ -54,15 +54,48 @@ describe('Layout Parameter Tests', () => { const params = new URLSearchParams(global.window.location.search); global.window.codeHtml = params.get('html') || ''; global.window.codeCss = params.get('css') || ''; - global.window.codeLayout = params.get('layout') - ? parseInt(params.get('layout'), 10) - : null; + global.window.codeLayout = (() => { + const layout = params.get('layout'); + if (!layout) return null; + if (layout === 'full') { + return 4; + } + const _val = parseInt(layout, 10); + if (_val >= 1 && _val <= 5) { + return _val; + } + return null; + })(); } expect(global.window.codeLayout).toBe(3); expect(global.window.codeHtml).toBe('
test
'); }); + test('should handle "full" alias for layout mode 4', () => { + // Set up URL with "full" layout parameter + global.window.location.search = '?layout=full&html=
test
'; + + // Simulate the URL parsing logic + if (global.window.location.search) { + const params = new URLSearchParams(global.window.location.search); + global.window.codeLayout = (() => { + const layout = params.get('layout'); + if (!layout) return null; + if (layout === 'full') { + return 4; + } + const _val = parseInt(layout, 10); + if (_val >= 1 && _val <= 5) { + return _val; + } + return null; + })(); + } + + expect(global.window.codeLayout).toBe(4); + }); + test('should handle invalid layout parameter gracefully', () => { // Set up URL with invalid layout parameter global.window.location.search = '?layout=invalid&html=
test
'; @@ -70,12 +103,21 @@ describe('Layout Parameter Tests', () => { // Simulate the URL parsing logic if (global.window.location.search) { const params = new URLSearchParams(global.window.location.search); - global.window.codeLayout = params.get('layout') - ? parseInt(params.get('layout'), 10) - : null; + global.window.codeLayout = (() => { + const layout = params.get('layout'); + if (!layout) return null; + if (layout === 'full') { + return 4; + } + const _val = parseInt(layout, 10); + if (_val >= 1 && _val <= 5) { + return _val; + } + return null; + })(); } - expect(global.window.codeLayout).toBe(NaN); + expect(global.window.codeLayout).toBe(null); }); test('should handle layout parameter out of range', () => { @@ -87,13 +129,22 @@ describe('Layout Parameter Tests', () => { if (global.window.location.search) { const params = new URLSearchParams(global.window.location.search); - global.window.codeLayout = params.get('layout') - ? parseInt(params.get('layout'), 10) - : null; + global.window.codeLayout = (() => { + const layout = params.get('layout'); + if (!layout) return null; + if (layout === 'full') { + return 4; + } + const _val = parseInt(layout, 10); + if (_val >= 1 && _val <= 5) { + return _val; + } + return null; + })(); } - // The layout should be parsed but may be outside valid range - expect(global.window.codeLayout).toBe(layoutValue); + // The layout should be null for out-of-range values + expect(global.window.codeLayout).toBe(null); }); }); @@ -120,9 +171,18 @@ describe('Layout Parameter Tests', () => { const params = new URLSearchParams(global.window.location.search); global.window.codeHtml = params.get('html') || ''; global.window.codeCss = params.get('css') || ''; - global.window.codeLayout = params.get('layout') - ? parseInt(params.get('layout'), 10) - : null; + global.window.codeLayout = (() => { + const layout = params.get('layout'); + if (!layout) return null; + if (layout === 'full') { + return 4; + } + const _val = parseInt(layout, 10); + if (_val >= 1 && _val <= 5) { + return _val; + } + return null; + })(); } expect(global.window.codeLayout).toBe(2); @@ -138,11 +198,47 @@ describe('Layout Parameter Tests', () => { // Simulate the URL parsing logic if (global.window.location.search) { const params = new URLSearchParams(global.window.location.search); - global.window.codeLayout = params.get('layout') - ? parseInt(params.get('layout'), 10) - : null; + global.window.codeLayout = (() => { + const layout = params.get('layout'); + if (!layout) return null; + if (layout === 'full') { + return 4; + } + const _val = parseInt(layout, 10); + if (_val >= 1 && _val <= 5) { + return _val; + } + return null; + })(); } expect(global.window.codeLayout).toBe(null); }); + + test('should handle all valid layout values', () => { + // Test all valid layout values (1-5) + const validLayouts = [1, 2, 3, 4, 5]; + + validLayouts.forEach(layoutValue => { + global.window.location.search = `?layout=${layoutValue}`; + + if (global.window.location.search) { + const params = new URLSearchParams(global.window.location.search); + global.window.codeLayout = (() => { + const layout = params.get('layout'); + if (!layout) return null; + if (layout === 'full') { + return 4; + } + const _val = parseInt(layout, 10); + if (_val >= 1 && _val <= 5) { + return _val; + } + return null; + })(); + } + + expect(global.window.codeLayout).toBe(layoutValue); + }); + }); });