Skip to content

Commit 6bde59f

Browse files
committed
feat: introduce embed layout
1 parent 3a4b02e commit 6bde59f

File tree

8 files changed

+213
-108
lines changed

8 files changed

+213
-108
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"dependencies": {
6161
"@emmetio/codemirror-plugin": "^1.1.3",
6262
"@zenuml/core": "^3.14.5",
63+
"clsx": "^2.0.0",
6364
"code-blast-codemirror": "chinchang/code-blast-codemirror#web-maker",
6465
"codemirror": "^5.65.16",
6566
"dom-to-image": "github:MichalBryxi/dom-to-image",

src/assets/external-link.svg

Lines changed: 8 additions & 0 deletions
Loading

src/components/EmbedHeader.jsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
export default function EmbedHeader(props) {
2+
return (
3+
<div className="embed-header">
4+
<div className="embed-header__left">
5+
<div className="header-logo">
6+
<img src="assets/zenuml-icon.png" alt="zenuml logo" />
7+
</div>
8+
<div className="tit">{this.props.title || 'Untitled'}</div>
9+
</div>
10+
<div className="embed-header__right">
11+
<a
12+
className="embed-header__external"
13+
title="Edit on app.zenuml.com"
14+
target="_blank"
15+
href={this.props.link}
16+
>
17+
<img src="assets/external-link.svg" alt="link logo" />
18+
</a>
19+
</div>
20+
</div>
21+
);
22+
}

src/components/Tabs.jsx

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import Tab from './Tab';
55
class Tabs extends Component {
66
static propTypes = {
77
children: PropTypes.instanceOf(Array).isRequired,
8-
}
8+
};
99

1010
constructor(props) {
1111
super(props);
@@ -16,36 +16,32 @@ class Tabs extends Component {
1616
this.state = {
1717
activeTab: this.props.children[0].props.label,
1818
};
19-
}
19+
};
2020
onClickTabItem = async (tab) => {
21-
await this.setState({activeTab: tab});
21+
await this.setState({ activeTab: tab });
2222
this.props.onChange(tab);
23-
}
23+
};
2424

2525
static modifyChildren(child, visible) {
2626
const className = [child.props.className, visible ? '' : 'hide'].join(' ');
2727

2828
const props = {
29-
className
29+
className,
3030
};
3131

3232
return React.cloneElement(child, props);
3333
}
3434
render() {
3535
const {
3636
onClickTabItem,
37-
props: {
38-
children,
39-
},
40-
state: {
41-
activeTab,
42-
}
37+
props: { children },
38+
state: { activeTab },
4339
} = this;
4440
return (
4541
<div className="tabs" style="height:100%">
4642
<ol className="tab-list editor-nav">
4743
{children.map((child) => {
48-
const { label,lineOfCode } = child.props;
44+
const { label, lineOfCode } = child.props;
4945
return (
5046
<Tab
5147
activeTab={activeTab}
@@ -57,16 +53,15 @@ class Tabs extends Component {
5753
);
5854
})}
5955
</ol>
60-
<div className="tab-content" style="height: calc(100% - 45px); overflow-y:auto;-webkit-overflow-scrolling: touch;">
61-
{
62-
React.Children.map(children,
63-
(child) => {
64-
if (child.props.label !== activeTab) {
65-
return React.Children.map(child.props.children, c => Tabs.modifyChildren(c, false));
66-
}
67-
return child.props.children;
68-
})
69-
}
56+
<div className="tab-content">
57+
{React.Children.map(children, (child) => {
58+
if (child.props.label !== activeTab) {
59+
return React.Children.map(child.props.children, (c) =>
60+
Tabs.modifyChildren(c, false)
61+
);
62+
}
63+
return child.props.children;
64+
})}
7065
</div>
7166
</div>
7267
);

src/components/app.jsx

Lines changed: 95 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ import JSZip from 'jszip';
4747
import { loadSubscriptionToApp } from '../javascript/firebase/subscription';
4848
import { currentBrowserTab } from '../services/browserService';
4949
import { syncDiagram, getShareLink } from '../services/syncService';
50+
import clsx from 'clsx';
51+
import EmbedHeader from './EmbedHeader.jsx';
5052

5153
if (module.hot) {
5254
require('preact/debug');
@@ -114,6 +116,8 @@ export default class App extends Component {
114116
isJs13kModeOn: false,
115117
autoCloseTags: true,
116118
};
119+
this.searchParams = new URLSearchParams(location.search);
120+
this.isEmbed = this.searchParams.get('embed');
117121
this.prefs = {};
118122
if (window.zenumlDesktop) {
119123
// hack savedItems, so we can load them on the desktop, without this object, the log in saveBtnClickHandler will not work.
@@ -195,7 +199,7 @@ export default class App extends Component {
195199
let urlCode;
196200
try {
197201
urlCode = JSON.parse(
198-
decodeURIComponent(new URLSearchParams(location.search).get('code'))
202+
decodeURIComponent(this.searchParams.get('code'))
199203
);
200204
} catch (err) {
201205
console.error(err);
@@ -573,44 +577,46 @@ BookLibService.Borrow(id) {
573577
});
574578

575579
// Editor keyboard shortucuts
576-
window.addEventListener('keydown', async (event) => {
577-
// TODO: refactor common listener code
578-
// Ctrl/⌘ + S
579-
if ((event.ctrlKey || event.metaKey) && event.keyCode === 83) {
580-
event.preventDefault();
581-
this.saveItem();
582-
trackEvent('ui', 'saveItemKeyboardShortcut');
583-
}
584-
// Ctrl/⌘ + Shift + 5
585-
if (
586-
(event.ctrlKey || event.metaKey) &&
587-
event.shiftKey &&
588-
event.keyCode === 53
589-
) {
590-
event.preventDefault();
591-
this.contentWrap.setPreviewContent(true, true);
592-
trackEvent('ui', 'previewKeyboardShortcut');
593-
} else if ((event.ctrlKey || event.metaKey) && event.keyCode === 79) {
594-
// Ctrl/⌘ + O
595-
event.preventDefault();
596-
await this.openSavedItemsPane();
597-
trackEvent('ui', 'openCreationKeyboardShortcut');
598-
} else if (
599-
(event.ctrlKey || event.metaKey) &&
600-
event.shiftKey &&
601-
event.keyCode === 191
602-
) {
603-
// Ctrl/⌘ + Shift + ?
604-
event.preventDefault();
605-
await this.setState({
606-
isKeyboardShortcutsModalOpen:
607-
!this.state.isKeyboardShortcutsModalOpen,
608-
});
609-
trackEvent('ui', 'showKeyboardShortcutsShortcut');
610-
} else if (event.keyCode === 27) {
611-
await this.closeSavedItemsPane();
612-
}
613-
});
580+
if (!this.isEmbed) {
581+
window.addEventListener('keydown', async (event) => {
582+
// TODO: refactor common listener code
583+
// Ctrl/⌘ + S
584+
if ((event.ctrlKey || event.metaKey) && event.keyCode === 83) {
585+
event.preventDefault();
586+
this.saveItem();
587+
trackEvent('ui', 'saveItemKeyboardShortcut');
588+
}
589+
// Ctrl/⌘ + Shift + 5
590+
if (
591+
(event.ctrlKey || event.metaKey) &&
592+
event.shiftKey &&
593+
event.keyCode === 53
594+
) {
595+
event.preventDefault();
596+
this.contentWrap.setPreviewContent(true, true);
597+
trackEvent('ui', 'previewKeyboardShortcut');
598+
} else if ((event.ctrlKey || event.metaKey) && event.keyCode === 79) {
599+
// Ctrl/⌘ + O
600+
event.preventDefault();
601+
await this.openSavedItemsPane();
602+
trackEvent('ui', 'openCreationKeyboardShortcut');
603+
} else if (
604+
(event.ctrlKey || event.metaKey) &&
605+
event.shiftKey &&
606+
event.keyCode === 191
607+
) {
608+
// Ctrl/⌘ + Shift + ?
609+
event.preventDefault();
610+
await this.setState({
611+
isKeyboardShortcutsModalOpen:
612+
!this.state.isKeyboardShortcutsModalOpen,
613+
});
614+
trackEvent('ui', 'showKeyboardShortcutsShortcut');
615+
} else if (event.keyCode === 27) {
616+
await this.closeSavedItemsPane();
617+
}
618+
});
619+
}
614620

615621
// Basic Focus trapping
616622
window.addEventListener('focusin', (e) => {
@@ -682,10 +688,11 @@ BookLibService.Borrow(id) {
682688
}
683689
// Remove all layout classes
684690
[1, 2, 3, 4, 5].forEach((layoutNumber) => {
685-
window[`layoutBtn${layoutNumber}`].classList.remove('selected');
691+
window[`layoutBtn${layoutNumber}`] &&
692+
window[`layoutBtn${layoutNumber}`].classList.remove('selected');
686693
document.body.classList.remove(`layout-${layoutNumber}`);
687694
});
688-
$('#layoutBtn' + mode).classList.add('selected');
695+
$('#layoutBtn' + mode) && $('#layoutBtn' + mode).classList.add('selected');
689696
document.body.classList.add('layout-' + mode);
690697

691698
await this.setState({ currentLayoutMode: mode }, () => {
@@ -1379,8 +1386,8 @@ BookLibService.Borrow(id) {
13791386
render() {
13801387
return (
13811388
<div>
1382-
<div class="main-container">
1383-
{window.zenumlDesktop ? null : (
1389+
<div class={clsx('main-container', this.isEmbed && 'embed-app')}>
1390+
{window.zenumlDesktop || this.isEmbed ? null : (
13841391
<MainHeader
13851392
externalLibCount={this.state.externalLibCount}
13861393
openBtnHandler={this.openBtnClickHandler.bind(this)}
@@ -1399,6 +1406,16 @@ BookLibService.Borrow(id) {
13991406
unsavedEditCount={this.state.unsavedEditCount}
14001407
/>
14011408
)}
1409+
{this.isEmbed && (
1410+
<EmbedHeader
1411+
title={this.searchParams.get('title')}
1412+
link={
1413+
`/?code=${JSON.stringify(
1414+
this.state.currentItem || ''
1415+
)}&title=${this.searchParams.get('title')}` || ''
1416+
}
1417+
/>
1418+
)}
14021419
<ContentWrap
14031420
currentLayoutMode={this.state.currentLayoutMode}
14041421
currentItem={this.state.currentItem}
@@ -1412,39 +1429,41 @@ BookLibService.Borrow(id) {
14121429
onEditorFocus={this.editorFocusHandler.bind(this)}
14131430
onSplitUpdate={this.splitUpdateHandler.bind(this)}
14141431
/>
1415-
<Footer
1416-
prefs={this.state.prefs}
1417-
layoutBtnClickHandler={this.layoutBtnClickHandler.bind(this)}
1418-
helpBtnClickHandler={async () =>
1419-
await this.setState({ isHelpModalOpen: true })
1420-
}
1421-
settingsBtnClickHandler={async () =>
1422-
await this.setState({ isSettingsModalOpen: true })
1423-
}
1424-
notificationsBtnClickHandler={this.notificationsBtnClickHandler.bind(
1425-
this
1426-
)}
1427-
supportDeveloperBtnClickHandler={this.supportDeveloperBtnClickHandler.bind(
1428-
this
1429-
)}
1430-
detachedPreviewBtnHandler={this.detachedPreviewBtnHandler.bind(
1431-
this
1432-
)}
1433-
codepenBtnClickHandler={this.codepenBtnClickHandler.bind(this)}
1434-
saveHtmlBtnClickHandler={this.saveHtmlBtnClickHandler.bind(this)}
1435-
keyboardShortcutsBtnClickHandler={async () =>
1436-
await this.setState({ isKeyboardShortcutsModalOpen: true })
1437-
}
1438-
screenshotBtnClickHandler={this.screenshotBtnClickHandler.bind(
1439-
this
1440-
)}
1441-
onJs13KHelpBtnClick={this.js13KHelpBtnClickHandler.bind(this)}
1442-
onJs13KDownloadBtnClick={this.js13KDownloadBtnClickHandler.bind(
1443-
this
1444-
)}
1445-
hasUnseenChangelog={this.state.hasUnseenChangelog}
1446-
codeSize={this.state.codeSize}
1447-
/>
1432+
{this.isEmbed ? null : (
1433+
<Footer
1434+
prefs={this.state.prefs}
1435+
layoutBtnClickHandler={this.layoutBtnClickHandler.bind(this)}
1436+
helpBtnClickHandler={async () =>
1437+
await this.setState({ isHelpModalOpen: true })
1438+
}
1439+
settingsBtnClickHandler={async () =>
1440+
await this.setState({ isSettingsModalOpen: true })
1441+
}
1442+
notificationsBtnClickHandler={this.notificationsBtnClickHandler.bind(
1443+
this
1444+
)}
1445+
supportDeveloperBtnClickHandler={this.supportDeveloperBtnClickHandler.bind(
1446+
this
1447+
)}
1448+
detachedPreviewBtnHandler={this.detachedPreviewBtnHandler.bind(
1449+
this
1450+
)}
1451+
codepenBtnClickHandler={this.codepenBtnClickHandler.bind(this)}
1452+
saveHtmlBtnClickHandler={this.saveHtmlBtnClickHandler.bind(this)}
1453+
keyboardShortcutsBtnClickHandler={async () =>
1454+
await this.setState({ isKeyboardShortcutsModalOpen: true })
1455+
}
1456+
screenshotBtnClickHandler={this.screenshotBtnClickHandler.bind(
1457+
this
1458+
)}
1459+
onJs13KHelpBtnClick={this.js13KHelpBtnClickHandler.bind(this)}
1460+
onJs13KDownloadBtnClick={this.js13KDownloadBtnClickHandler.bind(
1461+
this
1462+
)}
1463+
hasUnseenChangelog={this.state.hasUnseenChangelog}
1464+
codeSize={this.state.codeSize}
1465+
/>
1466+
)}
14481467
</div>
14491468

14501469
<SavedItemPane

src/computes.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,13 @@ export function computeJs(
178178
const cursor = e.data && e.data.cursor;
179179
180180
if (code && app) {
181-
app.render(code, { enableMultiTheme: false, onContentChange: (code) => {
182-
window.parent.postMessage({ code })
183-
}});
181+
app.render(code, {
182+
enableMultiTheme: false,
183+
onContentChange: (code) => {
184+
window.parent.postMessage({ code })
185+
},
186+
stickyOffset: Number(new URLSearchParams(window.location.search).get('stickyOffset') || 0)
187+
});
184188
}
185189
186190
if(app && (cursor !== null || cursor !== undefined)) {

0 commit comments

Comments
 (0)