Skip to content

Commit

Permalink
(#1.1.0) Fetch pdf + Add toggle button
Browse files Browse the repository at this point in the history
- Fetch pdf
- Add toggle button on header
- Center canvas editor
  • Loading branch information
ducquando authored Apr 17, 2024
2 parents 2163733 + f9afa33 commit 506bc0c
Show file tree
Hide file tree
Showing 26 changed files with 316 additions and 229 deletions.
9 changes: 8 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
name: Build
on: push

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
build:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codeslide.net",
"version": "0.3.0",
"version": "0.3.5",
"private": true,
"dependencies": {
"@ant-design/icons": "^4.8.1",
Expand Down
7 changes: 5 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const App = () => {
const selectedItem = useStore(getSelectedShape);
const selectedSet = useStore(getSelectedItems);
const sidebarWidth = useStore(s => s.ui.sidebarSize);
const footerHeight = useStore(s => s.ui.footerSize);
const applicationMode = useStore(s => s.ui.selectedMode);

const margin = {
Expand Down Expand Up @@ -85,7 +86,9 @@ export const App = () => {
<ShapeView />
</Layout.Sider>

<EditorView spacing={vogues.common.editorMargin} />
<Layout.Content >
<EditorView spacing={vogues.common.editorMargin} />
</Layout.Content>
</Layout>

<Layout.Sider
Expand All @@ -97,7 +100,7 @@ export const App = () => {
</Layout>
</Layout>

<Layout.Footer style={{ padding: 0 }} >
<Layout.Footer style={{ padding: 0, display: footerHeight == 0 ? 'none' : '' }} >
<PagesView prevWidth={vogues.common.previewWidth} prevHeight={vogues.common.previewHeight} />
</Layout.Footer>
</Layout>
Expand Down
10 changes: 9 additions & 1 deletion src/const/scripts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,17 @@
* Copyright (c) Do Duc Quan. All rights reserved.
*/

import { vogues } from "./vogues"

export const scripts = {
common: {
animation: '',
reveal: JSON.stringify({ hash: true, backgroundTransition: "none" }, null, 4)
reveal: JSON.stringify({
hash: true,
backgroundTransition: "none",
width: vogues.common.canvasWidth,
height: vogues.common.canvasHeight,
pdfMaxPagesPerSlide: 1
}, null, 4)
}
}
8 changes: 6 additions & 2 deletions src/const/vogues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,26 @@ import { LineCurve, LineNode, LinePivot } from "@app/wireframes/interface";

export const vogues = {
common: {
canvasWidth: 1280,
canvasHeight: 720,
close: 0,
dragSize: 12,
editorMargin: 13,
editorPad: 10,
headerHeight: 56,
iconSmall: 16,
iconDefault: 18,
iconLarge: 20,
offset: 1,
offset: 20,
maxImgSize: 300,
shapeWidth: 38,
sidebarCode: 600,
sidebarClose: 0,
sidebarShape: 38,
selectionThickness: 1,
previewWidth: 128,
previewHeight: 72,
previewPadBot: 20,
projectName: 'Untitled Presentation',
},
color: {
blue: '#00f',
Expand All @@ -37,6 +40,7 @@ export const vogues = {
selectionLock: '#f00',
selectionStroke: '#080',
transparent: 'rgba(0, 0, 0, 0)',
white: '#fff',
},
option: {
strokeThickness: [0, 1, 2, 3, 4, 6, 8, 10],
Expand Down
4 changes: 4 additions & 0 deletions src/icons/icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ export const TriangleIcon = () => (
<svg xmlns="http://www.w3.org/2000/svg" height={vogues.common.iconDefault} viewBox="0 -960 960 960" width={vogues.common.iconLarge}><path d="m96-192 384-576 384 576H96Zm134-72h500L480-638 230-264Zm250-187Z" /></svg>
);

export const PageIcon = () => (
<svg xmlns="http://www.w3.org/2000/svg" height={vogues.common.iconSmall} viewBox="0 -960 960 960" width={vogues.common.iconSmall}><path d="M480-164.157 152.31-418.771l49.076-37.691L480-240.771l278.614-215.691 49.076 37.691L480-164.157Zm0-177.383L152.31-596.154 480-850.767l327.69 254.613L480-341.54Zm0-254.614Zm0 178 230-178-230-178-230 178 230 178Z"/></svg>
)

export const ParagraphIcon = () => (
<svg xmlns="http://www.w3.org/2000/svg" height={vogues.common.iconSmall} viewBox="0 -960 960 960" width={vogues.common.iconLarge}><path d="m171-288 144-384h69l144 384h-66l-34-98H273l-35 98h-67Zm121-154h115l-56-159h-3l-56 159Zm358 164q-47 0-73.5-24.5T550-370q0-41 30.5-66t80.5-25q21 0 42 4t32 10v-14q0-24-19-40t-48-16q-21 0-37.5 8.5T600-483l-41-32q17-25 46.5-38.5T670-567q58 0 90 28.5t32 81.5v169h-57v-31h-3q-16 21-35.5 31T650-278Zm10-50q32 0 53-21.5t21-52.5q-14-8-29.5-12t-32.5-4q-29 0-46 13t-17 34q0 20 14 31.5t37 11.5Z" /></svg>
);
Expand Down
4 changes: 3 additions & 1 deletion src/style/_common.scss
Original file line number Diff line number Diff line change
Expand Up @@ -342,8 +342,10 @@ header {

&-segment {
gap: 3px;
border-radius: 14px;
border-radius: 20px;
padding: 3px 4px;
display: inline-flex;
background-color: $color-background;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/style/_vars.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* stylelint-disable */

$color-background: rgb(240, 242, 245);
$color-background: #f0f2f5;

$color-border: #e8e8e8;
$color-border-dark: darken($color-border, 5%);
Expand Down
7 changes: 6 additions & 1 deletion src/wireframes/components/AnimationView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,19 @@ export const AnimationView = () => {
const dispatch = useDispatch();
const diagram = useStore(getDiagram);
const animation = useStore(s => s.ui.selectedAnimation);
const isFooter = useStore(s => s.ui.footerSize) == vogues.common.previewHeight ? 1 : 0;

const viewPadd = vogues.common.editorMargin * 2 + 10 * 3 + vogues.common.headerHeight + vogues.common.shapeWidth + (vogues.common.previewHeight + vogues.common.editorMargin + vogues.common.previewPadBot) + vogues.common.selectionThickness * 4;
const viewPadd = vogues.common.editorMargin * 2 + 10 * 3 + vogues.common.headerHeight + vogues.common.shapeWidth + isFooter * (vogues.common.previewHeight + vogues.common.editorMargin + vogues.common.previewPadBot) + vogues.common.selectionThickness * 4;
const [viewHeight, setViewHeight] = useState(window.innerHeight - viewPadd);

useEffect(() => {
window.addEventListener('resize', () => setViewHeight(window.innerHeight - viewPadd));
}, []);

useEffect(() => {
setViewHeight(window.innerHeight - viewPadd);
}, [isFooter]);

if (!diagram) {
return null;
}
Expand Down
4 changes: 1 addition & 3 deletions src/wireframes/components/HeaderView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import * as React from 'react';
import { Title } from '@app/core';
import { getEditor, useStore } from '@app/wireframes/model';
import { useLoading } from './actions';
import { ArrangeHeader, FileHeader, PresentHeader, IdHeader, ModeHeader, ScriptHeader } from './headers';
import { ArrangeHeader, FileHeader, PresentHeader, IdHeader, ModeHeader } from './headers';
import './styles/HeaderView.scss'

export const HeaderView = React.memo(() => {
Expand Down Expand Up @@ -65,8 +65,6 @@ export const HeaderView = React.memo(() => {
<span style={{ float: 'right' }}>
<ModeHeader />
<span className='menu-separator' />
<ScriptHeader />
<span className='menu-span' />
<PresentHeader />
</span>
</div>
Expand Down
1 change: 1 addition & 0 deletions src/wireframes/components/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ export * from './use-clipboard';
export * from './use-grouping';
export * from './use-history';
export * from './use-loading';
export * from './use-server';
export * from './use-remove';
153 changes: 153 additions & 0 deletions src/wireframes/components/actions/use-server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import { Diagram, changeFrames, compileSlides, getEditor, getFilteredDiagrams, parseFrames, useStore } from "@app/wireframes/model";
import { AbstractControl } from "@app/wireframes/shapes/utils/abstract-control";
import { getPlugin } from "@app/wireframes/shapes/utils/abstract-plugin";
import * as svg from '@svgdotjs/svg.js';
import { Color } from "@app/core/utils/color";
import { shapes } from "@app/const";
import { MessageInstance } from "antd/es/message/interface";
import { useDispatch } from "react-redux";

export function useServer() {
const dispatch = useDispatch();
const diagrams = useStore(getFilteredDiagrams);
const editor = useStore(getEditor);

const getItem = (diagram: Diagram, str: string) => {
// Split text using `=` symbol, ignoring those inside curly brackets
const regex = /=(?![^{]*})/;
const [id, json] = str.split(regex);

// Get item
let item = diagram.items.get(id);
if (!item || !json) return { item: item, id: id };

// Parse str -> json
let corrected = json.replace(/'/g, '"');
let jsonObj: {[index: string]: string} = JSON.parse(corrected);

// Modify appearance if there are valid specifications
// e.g. Shape1 = {'TEXT': 'Hello, world!'}
const allKeys = Object.values(shapes.key);
for (let [key, value] of Object.entries(jsonObj)) {
if (!allKeys.includes(key)) continue; // Safe-check

if (key.endsWith('COLOR')) {
const color = Color.fromValue(value).toNumber();
item = item.setAppearance(key, color);
} else {
item = item.setAppearance(key, value);
}
}

return { item: item, id: id };
}

const getSlides = () => {
let frame3D: string[][][] = new Array(diagrams.length);

// Get frames
diagrams.map((diagram, i) => {
const frames = diagram.frames ?? [];
frame3D[i] = [];

frames.map((frame, j) => {
const usedIDs: string[] = [];
frame3D[i][j] = [];

for (let k = frame.length; k > 0; k--) {
const { item, id } = getItem(diagram, frame[k - 1]);
if (!item || usedIDs.includes(id)) continue;
usedIDs.push(id);

// Get svg
const svgControl = new AbstractControl(getPlugin(item.renderer));
const svgElement: svg.Element = svgControl.render(item, undefined);
const svgCode = svgElement.node.outerHTML;

// Push object to the head of parent map
frame3D[i][j] = [svgCode, ...frame3D[i][j]];
}
})
})

// Reshape from 3D to 2D
let frame2D = [];
for (let row of frame3D) for (let e of row) frame2D.push(e);

return {
fileName: editor.id,
title: editor.name,
backgroundColor: editor.color.toString(),
size: [editor.size.x, editor.size.y],
config: editor.revealConfig,
frame: frame2D,
};
}

const fetchParser = async () => {
for (let diagram of diagrams) {
const script = diagram.script;
if (!script) continue;

const frames = await parseFrames(script);
dispatch(changeFrames(diagram.id, frames));
}
}

const fetchCompiler = async () => {
const { fileName, title, size, backgroundColor, config, frame } = getSlides();

const linkPresentation = await compileSlides(fileName, title, size, backgroundColor, config, frame);

return linkPresentation;
}

const fetchApi = () => {
// Fetch frames from parser
fetchParser();

// Fetch presentation from compiler
const links = fetchCompiler();
return links;
}

const fetchPdf = async (messageApi: MessageInstance, messageKey: string) => {
// Start compiling
messageApi.open({ key: messageKey, type: 'loading', content: 'Exporting presentation...' });

try {
const { linkPdf } = await fetchApi();
window.open(linkPdf, '_blank');
} catch (err) {
messageApi.error(`${err}`);
} finally {
messageApi.open({
key: messageKey,
type: 'success',
content: `Preparing completed. Your presentation will be opened in a new tab.`,
duration: 1,
});
}
}

const fetchSlide = async (messageApi: MessageInstance, messageKey: string) => {
messageApi.open({ key: messageKey, type: 'loading', content: 'Preparing presentation...' });

try {
const { linkSlide } = await fetchApi();
window.open(linkSlide, '_blank');
} catch (err) {
messageApi.error(`${err}`);
} finally {
messageApi.open({
key: messageKey,
type: 'success',
content: `Preparing completed. Your presentation will be opened in a new tab.`,
duration: 1,
});
}
}

return { slide: fetchSlide, pdf: fetchPdf };
}

17 changes: 15 additions & 2 deletions src/wireframes/components/headers/FileHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
*/

import { changeName, getEditor, useStore } from '@app/wireframes/model';
import { Button, Dropdown, Form, Input } from 'antd';
import { Button, Dropdown, Form, Input, message } from 'antd';
import { useEffect, useState } from 'react';
import { useLoading } from '../actions';
import { useLoading, useServer } from '../actions';
import { texts } from '@app/const/texts';
import { useDispatch } from 'react-redux';
import { FormModal, SettingModal } from '../modal';
Expand All @@ -19,9 +19,12 @@ import { MenuIcon } from '@app/style/icomoon/icomoon_icon';
export const FileHeader = () => {
const dispatch = useDispatch();
const forLoading = useLoading();
const forServer = useServer();
const editor = useStore(getEditor);
const [messageApi, contextHolder] = message.useMessage();
const [isRename, setIsRename] = useState(false);
const [isSettings, setIsSettings] = useState(false);
const messageKey = 'GENERATE';

// Get editor's name
let name = editor.name;
Expand Down Expand Up @@ -81,6 +84,13 @@ export const FileHeader = () => {
className: 'loading-action-item',
disabled: forLoading.downloadDiagram.disabled,
},
{
key: texts.common.saveDiagramToFileTooltip,
label: texts.common.saveDiagramToFileTooltip,
icon: <MenuIcon icon='icon-save' />,
className: 'loading-action-item',
disabled: forLoading.downloadDiagram.disabled,
},
];

const menuEvt: MenuProps['onClick'] = ({key}) => {
Expand All @@ -94,11 +104,14 @@ export const FileHeader = () => {
dispatch(forLoading.openDiagramAction.onAction);
} else if (key == forLoading.downloadDiagram.label) {
dispatch(forLoading.downloadDiagram.onAction);
} else if (texts.common.saveDiagramToFileTooltip) {
dispatch(forServer.pdf(messageApi, messageKey));
}
}

return (
<>
{contextHolder}
<Dropdown
className='loading-action-button'
menu={{ items: menu, onClick: menuEvt }}
Expand Down
Loading

0 comments on commit 506bc0c

Please sign in to comment.