From 488a2783078e572c7352ee5c3407c0d5ecbed10c Mon Sep 17 00:00:00 2001 From: matheoleger <71370253+matheoleger@users.noreply.github.com> Date: Sat, 8 Apr 2023 19:59:58 +0200 Subject: [PATCH 1/7] feat(slide): Added markdown parse for code and image + display slide with style --- index.ts | 32 ++++--- package.json | 1 + src/App.tsx | 7 +- src/assets/css/Home.css | 12 +++ src/assets/css/NewPrez.css | 3 - src/assets/css/Presentation.css | 4 + src/assets/css/Slide.css | 22 +++++ src/assets/css/index.css | 4 +- src/components/NavigationButton.tsx | 27 ++++-- src/components/Presentation.tsx | 48 +++++----- src/components/SideBar.tsx | 24 +++-- src/components/Slide.tsx | 23 +++-- src/main/markdownRenderer.ts | 122 ++++++++++++++++++++++++++ src/main/openAndCloseCodePrezFiles.ts | 6 +- src/renderer/utils/utils.ts | 102 ++++++++++++++++++--- src/types.d.ts | 1 + yarn.lock | 18 ++++ 17 files changed, 386 insertions(+), 70 deletions(-) create mode 100644 src/assets/css/Presentation.css create mode 100644 src/assets/css/Slide.css create mode 100644 src/main/markdownRenderer.ts diff --git a/index.ts b/index.ts index 3527946..56a672f 100644 --- a/index.ts +++ b/index.ts @@ -1,13 +1,13 @@ -import { app, BrowserWindow } from "electron"; +import { app, BrowserWindow, protocol } from "electron"; import { join } from "path"; import { createArchive } from "./src/main/createArchive"; import { openFileDialog, saveFileDialog } from "./src/main/dialogs"; - +import url from "url" import { deleteCodePrezTempFolder, openCodePrezArchive, } from "./src/main/openAndCloseCodePrezFiles"; -import { markdownHighlight } from "./src/renderer/utils/utils"; +import { markdownRenderer } from "./src/main/markdownRenderer" const createWindow = () => { const win = new BrowserWindow({ @@ -48,11 +48,10 @@ const createWindow = () => { if (!archivePath) return; const presentationData = await openCodePrezArchive(archivePath); - const createSection = separate(presentationData); + const createSection = separateAndRender(presentationData); + + if (!presentationData) return; - if (!presentationData) { - return null; - } presentationData.presentationFileContent = createSection || ([] as any); win.webContents.send("set-codeprez-data", presentationData); }); @@ -70,16 +69,29 @@ const createWindow = () => { return win; }; -const separate = (data: any) => { +const separateAndRender = (data: any) => { const slides = data?.presentationFileContent?.split(/^---$/gm); + const createSection = slides?.map((slide: any, index: any) => { - const dataMd: string = markdownHighlight().render(slide); + const dataMd: string = markdownRenderer(data.presentationPath).render(slide); return dataMd; }); return createSection; }; + const initialize = async () => { - await app.whenReady(); + await app.whenReady().then(() => { + protocol.registerFileProtocol('codeprez', (request, callback) => { + try { + const filePath = url.fileURLToPath('file://' + request.url.slice('codeprez:/'.length)) + callback(filePath) + } + catch (error) { + console.error(error) + callback("404") + } + }) + }); const win = createWindow(); }; diff --git a/package.json b/package.json index 5eb9c18..2bf18e4 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ }, "devDependencies": { "@types/decompress": "^4.2.4", + "@types/markdown-it": "^12.2.3", "electron": "^23.1.1" } } diff --git a/src/App.tsx b/src/App.tsx index 8ffb852..f27eebd 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -16,13 +16,18 @@ function App() { height: "100%", }} > + + - + diff --git a/src/assets/css/Home.css b/src/assets/css/Home.css index 14d0029..5f2d174 100644 --- a/src/assets/css/Home.css +++ b/src/assets/css/Home.css @@ -28,3 +28,15 @@ color: var(--pink); border-color: var(--pink); } + +.go-to-viewer-button { + color:var(--black-grey); + border-color: var(--black-grey); + background-color: var(--pink); +} + +.go-to-viewer-button:hover { + background-color: var(--black-grey); + color: var(--pink); + border-color: var(--pink); +} diff --git a/src/assets/css/NewPrez.css b/src/assets/css/NewPrez.css index b0a6c0d..bb024b7 100644 --- a/src/assets/css/NewPrez.css +++ b/src/assets/css/NewPrez.css @@ -41,9 +41,6 @@ margin: 1em 0; } - - - .sendingButton{ cursor: pointer; border:none; diff --git a/src/assets/css/Presentation.css b/src/assets/css/Presentation.css new file mode 100644 index 0000000..09d875e --- /dev/null +++ b/src/assets/css/Presentation.css @@ -0,0 +1,4 @@ +.presentation-page { + overflow-y: auto; + overflow-x: hidden; +} \ No newline at end of file diff --git a/src/assets/css/Slide.css b/src/assets/css/Slide.css new file mode 100644 index 0000000..d3a76ed --- /dev/null +++ b/src/assets/css/Slide.css @@ -0,0 +1,22 @@ +.slide-container { + height: 100vh; + border-radius: 10px; + box-shadow: 0 0 20px 10px rgba(0, 0, 0, 0.2); +} + +.slide-container pre { + border-radius: 10px; + height: 100%; +} + +.slide-container code { + height: 100%; +} + +.scale-preview { + transform : scale(0.85); +} + +.scale-sidebar { + transform : scale(0.3); +} \ No newline at end of file diff --git a/src/assets/css/index.css b/src/assets/css/index.css index e9627a6..79ceac2 100644 --- a/src/assets/css/index.css +++ b/src/assets/css/index.css @@ -27,15 +27,17 @@ body { background-color: var(--background-color); color: var(--white); + overflow: hidden; } -h1 { +.new-prez h1, .home h1, .presentation-title { border:#B4B4B4 1px solid; text-align: center; color: white; padding:0.5em 1em; margin:10px; border-radius: 10px; + text-decoration: none; } diff --git a/src/components/NavigationButton.tsx b/src/components/NavigationButton.tsx index fa08474..4667290 100644 --- a/src/components/NavigationButton.tsx +++ b/src/components/NavigationButton.tsx @@ -1,7 +1,7 @@ import React, { FC } from 'react'; import { useNavigate } from 'react-router-dom'; interface NavigationButtonProp { - goTo: 'prez' | 'add'; + goTo: 'prez' | 'add' |'viewer'; withIcon?: boolean; } @@ -14,16 +14,22 @@ export const NavigationButton: FC = ({ navigate('/add'); }; - const launchPresentation = () => { - console.log("launchPrez"); - navigate('/prez'); + const openPresentation = () => { + window.api.getPresentationData(navigateToPresentation); }; + + const navigateToPresentation = (data: PresentationData) => { + navigate('/prez', { + state: data + }); + } + if (goTo === 'prez') { return ( - ); @@ -36,6 +42,15 @@ export const NavigationButton: FC = ({ )} ); + } else if (goTo == "viewer") { + return ( + + ) } return <>; }; diff --git a/src/components/Presentation.tsx b/src/components/Presentation.tsx index 094bcd5..cc11df7 100644 --- a/src/components/Presentation.tsx +++ b/src/components/Presentation.tsx @@ -1,42 +1,40 @@ import { useState, useEffect } from "react"; +import "../assets/css/Presentation.css" import { Slide } from "./Slide"; +import { useLocation } from "react-router-dom"; +import { NavigationButton } from './NavigationButton'; //TODO: Search for a way to import the css file from the presentation folder and display images with the folder temp export const Presentation = () => { - const [presentationData, setPresentationData] = - useState(); + const [presentationData, setPresentationData] = useState(); - useEffect(() => { - console.log("Je vais dans le useEffect combien de fois ?"); - window.api.getPresentationData(setPresentationData); - }, []); - - /* const updateCSS = () => { - if (presentationData?.presentationPath) { - const head = document.head; - const link = document.createElement("link"); + const {state} = useLocation() - link.type = "text/css"; - link.rel = "stylesheet"; - link.href = presentationData?.presentationPath + "/style.css"; - head.appendChild(link); - import(presentationData?.presentationPath + "/style.css"); - } - }; - updateCSS(); */ + useEffect(() => { + // window.api.getPresentationData(setPresentationData); + setPresentationData(state); + }, [useLocation()]); return ( -
+
{/* */} -

{presentationData?.presentationConfig.title}

+
+

{presentationData?.presentationConfig.title}

+ +
{Array.isArray(presentationData?.presentationFileContent) && - presentationData?.presentationFileContent.map( - (slide, index) => {slide} - )} + presentationData?.presentationFileContent.map((slide, index) => ( + + {slide} + + ))} +
); }; diff --git a/src/components/SideBar.tsx b/src/components/SideBar.tsx index a83b345..424675d 100644 --- a/src/components/SideBar.tsx +++ b/src/components/SideBar.tsx @@ -1,9 +1,18 @@ -import { Outlet, useNavigate } from 'react-router-dom'; +import { Outlet, useLocation, useNavigate } from 'react-router-dom'; import '../assets/css/SideBar.css'; import CodePrezLogo from '../assets/logo.svg'; import { NavigationButton } from './NavigationButton'; +import { Slide } from './Slide'; +import { useState, useEffect } from 'react'; export const SideBar = () => { + const [presentationData, setPresentationData] = useState(); + const navigate = useNavigate(); + const {state} = useLocation(); + + useEffect(() => { + setPresentationData(state); + },[]) const home = () => { navigate('/'); @@ -11,10 +20,6 @@ export const SideBar = () => { return (
-

CodePrez

@@ -22,6 +27,15 @@ export const SideBar = () => {
+ {Array.isArray(presentationData?.presentationFileContent) && + presentationData?.presentationFileContent.map((slide, index) => ( + + {slide} + + ))} +
diff --git a/src/components/Slide.tsx b/src/components/Slide.tsx index 8b297af..c939cd6 100644 --- a/src/components/Slide.tsx +++ b/src/components/Slide.tsx @@ -1,9 +1,20 @@ -export const Slide = ({ children }: any) => { +import { useEffect } from "react"; +import "../assets/css/Slide.css" + +type Props = { + children: string; + slideScale: "preview" | "sidebar" | "slideViewer" +} + +export const Slide = ({ children, slideScale }: Props) => { + return ( -
+
+
); }; diff --git a/src/main/markdownRenderer.ts b/src/main/markdownRenderer.ts new file mode 100644 index 0000000..4bfe83c --- /dev/null +++ b/src/main/markdownRenderer.ts @@ -0,0 +1,122 @@ +import { nativeImage } from "electron"; +import hljs from "highlight.js"; +import MarkdownIt from "markdown-it"; +import path from "path"; +import fs from 'fs'; +import Token from "markdown-it/lib/token"; +import Renderer from "markdown-it/lib/renderer"; + +type RendererRulesArguments = { + tokens: Token[], + idx: number, + options: MarkdownIt.Options, + env: any, + self: Renderer, + presentationPath: string +} + +type CodeFileRendererRulesArguments = { + codeFilePath: string, + href: string | null +} + +export function markdownRenderer(presentationPath: string) { + + const markdownOptions: MarkdownIt.Options = { + highlight: function (str: string, lang: string) { + if (lang && hljs.getLanguage(lang)) { + try { + if(lang == "bash") { + return ( + '
' +
+                            hljs.highlight(str, {
+                                language: lang,
+                                ignoreIllegals: true,
+                            }).value
+                            + '
' + ) + } else { + return ( + '
' +
+                            hljs.highlight(str, {
+                                language: lang,
+                                ignoreIllegals: true,
+                            }).value +
+                            "
" + ); + } + } catch (__) {} + } + + return ( + '
' +
+                md.utils.escapeHtml(str) +
+                "
" + ); + }, + } + + const md = MarkdownIt(markdownOptions); + + //Include images + md.renderer.rules.image = (tokens, idx, options, env, self) => imageRendererRules({tokens, idx, options, env, self, presentationPath}); + + //Include code via file + md.renderer.rules.link_open = (tokens, idx, options, env, self) => linkRendererRules({tokens, idx, options, env, self, presentationPath}) + + return md; +} + +const imageRendererRules = ({tokens, idx, options, env, self, presentationPath}: RendererRulesArguments) => { + const token = tokens[idx]; + + const src = token.attrGet("src"); + + const regexForSrc = /\.\/assets/gm; + + const srcWithPresentationPath = (src?.match(regexForSrc)) ? path.join("codeprez:/", presentationPath, src) : src + token.attrSet('src', srcWithPresentationPath || "") + + return self.renderToken(tokens, idx, options) +} + +const linkRendererRules = ({tokens, idx, options, env, self, presentationPath}: RendererRulesArguments) => { + const token = tokens[idx]; + + const href = token.attrGet("href") + const regexPathFile = /^\.\/(.+\.\w+)/gm; + const relativeCodeFilePath = href?.match(regexPathFile) ?? []; + + if(relativeCodeFilePath.length) { + const codeFilePath = path.join(presentationPath, relativeCodeFilePath[0] ?? "") + return codeFileRendererRules({codeFilePath: codeFilePath, href}); + } else { + return self.renderToken(tokens, idx, options); + } + +} + +const codeFileRendererRules = ({codeFilePath, href}: CodeFileRendererRulesArguments) => { + + const regexLineNumber = /#(\d+)-(\d+)/; + const regexFileExtension = /\.(\w+)(?:#\d+-\d+)?$/; + + const lineNumbers = href?.match(regexLineNumber) ?? []; + const startNumber = lineNumbers[1]; + const endNumber = lineNumbers[2]; + + const fileExtension = href?.match(regexFileExtension) ?? []; + + const file = fs.readFileSync(codeFilePath, { encoding: 'utf8' }); + const lines = file.split("\n").slice(Number(startNumber)-1, Number(endNumber)); + + // I must use a concatenate string instead of `` because of tabulation and break line + return ( + "
" +
+            hljs.highlight(lines.join("\n"), {
+                    language: fileExtension[1] || "",
+                    ignoreIllegals: true,
+                }).value +
+        "
" + ) +} diff --git a/src/main/openAndCloseCodePrezFiles.ts b/src/main/openAndCloseCodePrezFiles.ts index 8b1aac7..4ceb463 100644 --- a/src/main/openAndCloseCodePrezFiles.ts +++ b/src/main/openAndCloseCodePrezFiles.ts @@ -38,7 +38,11 @@ export const openCodePrezArchive = async (archivePath: string) => { ?.data.toString(); const presentationConfig = JSON.parse(plainPresentationConfig ?? "{}"); - return { presentationConfig, presentationFileContent, presentationPath }; + const presentationStyle = files + .find((file) => file.path == "style.css") + ?.data.toString(); + + return { presentationConfig, presentationFileContent, presentationPath, presentationStyle }; }; export const deleteCodePrezTempFolder = () => { diff --git a/src/renderer/utils/utils.ts b/src/renderer/utils/utils.ts index a697926..cb0dc82 100644 --- a/src/renderer/utils/utils.ts +++ b/src/renderer/utils/utils.ts @@ -1,20 +1,37 @@ +import { nativeImage } from "electron"; import hljs from "highlight.js"; +import MarkdownIt from "markdown-it"; +import path from "path"; +import fs from 'fs'; -var md = markdownHighlight(); +export function markdownHighlight(presentationPath: string) { -export function markdownHighlight() { - return require("markdown-it")({ + const markdownOptions: MarkdownIt.Options = { highlight: function (str: string, lang: string) { if (lang && hljs.getLanguage(lang)) { try { - return ( - '
' +
-                        hljs.highlight(str, {
-                            language: lang,
-                            ignoreIllegals: true,
-                        }).value +
-                        "
" - ); + + if(lang == "bash") { + return ( + '
' +
+                            hljs.highlight(str, {
+                                language: lang,
+                                ignoreIllegals: true,
+                            }).value
+                            + '
' + ) + } else { + return ( + '
' +
+                            hljs.highlight(str, {
+                                language: lang,
+                                ignoreIllegals: true,
+                            }).value +
+                            "
" + ); + } + + } catch (__) {} } @@ -24,5 +41,66 @@ export function markdownHighlight() { "" ); }, - }); + } + + const md = MarkdownIt(markdownOptions); + + //Include images + md.renderer.rules.image = (tokens, idx, options, env, self) => { + const token = tokens[idx]; + + const src = token.attrGet("src"); + + const regexForSrc = /\.\/assets/gm; + + const srcWithPresentationPath = (src?.match(regexForSrc)) ? path.join("codeprez:/", presentationPath, src) : src + token.attrSet('src', srcWithPresentationPath || "") + + return self.renderToken(tokens, idx, options) + } + + //Include code via files + md.renderer.rules.link_open = (tokens, idx, options, env, self) => { + const token = tokens[idx]; + + const href = token.attrGet("href"); + + const regexPathFile = /^\.\/(.+\.\w+)/gm; + const regexLineNumber = /#(\d+)-(\d+)/; + const regexFileExtension = /\.(\w+)(?:#\d+-\d+)?$/; + + const pathFile = href?.match(regexPathFile) ?? []; + + const lineNumbers = href?.match(regexLineNumber) ?? []; + const startNumber = lineNumbers[1]; + const endNumber = lineNumbers[2]; + + const fileExtension = href?.match(regexFileExtension) ?? []; + + if(pathFile) { + const file = fs.readFileSync(path.join(presentationPath, pathFile[0] ?? ""), { encoding: 'utf8' }); + const lines = file.split("\n").slice(Number(startNumber)-1, Number(endNumber)); + + // return ( + // `
${hljs.highlight(lines.join("\n"), {
+            //                 language: fileExtension[1] || "",
+            //                 ignoreIllegals: true,
+            //             }).value}
` + // ) + + // I must use a concatenate string instead of `` because of tabulation and break line + return ( + "
" +
+                    hljs.highlight(lines.join("\n"), {
+                            language: fileExtension[1] || "",
+                            ignoreIllegals: true,
+                        }).value +
+                    "
" + ) + } + + return self.renderToken(tokens, idx, options); + } + + return md; } diff --git a/src/types.d.ts b/src/types.d.ts index 2b96695..9c46e07 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -2,6 +2,7 @@ type PresentationData = { presentationConfig: PresentationConfig; presentationFileContent: string[] | string; presentationPath: string; + presentationStyle: string; }; type PresentationConfig = { diff --git a/yarn.lock b/yarn.lock index 8aa8581..d917b88 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2063,6 +2063,24 @@ dependencies: "@types/node" "*" +"@types/linkify-it@*": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-3.0.2.tgz#fd2cd2edbaa7eaac7e7f3c1748b52a19143846c9" + integrity sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA== + +"@types/markdown-it@^12.2.3": + version "12.2.3" + resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-12.2.3.tgz#0d6f6e5e413f8daaa26522904597be3d6cd93b51" + integrity sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ== + dependencies: + "@types/linkify-it" "*" + "@types/mdurl" "*" + +"@types/mdurl@*": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-1.0.2.tgz#e2ce9d83a613bacf284c7be7d491945e39e1f8e9" + integrity sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA== + "@types/mime@*": version "3.0.1" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10" From 7c5b5a63c5a925d256223b2ae6e948e208b69c63 Mon Sep 17 00:00:00 2001 From: matheoleger <71370253+matheoleger@users.noreply.github.com> Date: Sun, 9 Apr 2023 11:47:43 +0200 Subject: [PATCH 2/7] feat(Slide): Style of slide --- src/assets/css/Presentation.css | 10 +++++++ src/assets/css/SideBar.css | 7 +++++ src/assets/css/Slide.css | 52 ++++++++++++++++++++++++++++----- src/components/Presentation.tsx | 14 +++++++-- src/components/SideBar.tsx | 23 ++------------- src/components/Slide.tsx | 11 ++++++- 6 files changed, 87 insertions(+), 30 deletions(-) diff --git a/src/assets/css/Presentation.css b/src/assets/css/Presentation.css index 09d875e..47c129c 100644 --- a/src/assets/css/Presentation.css +++ b/src/assets/css/Presentation.css @@ -1,4 +1,14 @@ .presentation-page { overflow-y: auto; overflow-x: hidden; +} + +.presentation-header { + display: flex; + justify-content: center; + align-items: center; +} + +.authors { + display: flex; } \ No newline at end of file diff --git a/src/assets/css/SideBar.css b/src/assets/css/SideBar.css index f5fba37..b12a0c6 100644 --- a/src/assets/css/SideBar.css +++ b/src/assets/css/SideBar.css @@ -13,6 +13,13 @@ gap:1em; } +.sidebar .slide-preview { + max-width: inherit; + max-height: inherit; + overflow-y: auto; + overflow-x: hidden; +} + button{ cursor: pointer; display: flex; diff --git a/src/assets/css/Slide.css b/src/assets/css/Slide.css index d3a76ed..6d524bc 100644 --- a/src/assets/css/Slide.css +++ b/src/assets/css/Slide.css @@ -1,16 +1,51 @@ -.slide-container { - height: 100vh; +section { + /* height: 100vh; */ border-radius: 10px; box-shadow: 0 0 20px 10px rgba(0, 0, 0, 0.2); + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + flex-wrap: wrap; + background: var(--black-grey); +} + +section p img { + max-height: 80%; + max-width: 80%; +} + +.slide-container p { + display: flex; + justify-content: center; + align-items: center; + margin: 10px; } -.slide-container pre { +pre { border-radius: 10px; - height: 100%; + min-width: 20%; + max-width: 90%; + display: flex; + overflow: auto; } -.slide-container code { - height: 100%; +code:not(pre > code) { + background-color: var(--dark-grey); + border-radius: 5px; + padding: 2px; + color: var(--white); + margin: 2px; +} + +pre button { + width: 40px; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; } .scale-preview { @@ -18,5 +53,8 @@ } .scale-sidebar { - transform : scale(0.3); + transform : scale(0.7); + /* height: 300px; */ + width: 100%; + max-height: 300px; } \ No newline at end of file diff --git a/src/components/Presentation.tsx b/src/components/Presentation.tsx index cc11df7..7b432d6 100644 --- a/src/components/Presentation.tsx +++ b/src/components/Presentation.tsx @@ -13,7 +13,7 @@ export const Presentation = () => { useEffect(() => { // window.api.getPresentationData(setPresentationData); setPresentationData(state); - }, [useLocation()]); + }, [state]); return (
@@ -22,10 +22,20 @@ export const Presentation = () => { type="text/css" href={"codeprez:\\" + presentationData?.presentationPath + "\\style.css"} > */} -
+

{presentationData?.presentationConfig.title}

+ +

{presentationData?.presentationConfig.title}

+ +
+

Créé par :

+ {presentationData?.presentationConfig.authors.map((author) => ( +

{author}

+ ))} +
+
{Array.isArray(presentationData?.presentationFileContent) && presentationData?.presentationFileContent.map((slide, index) => ( diff --git a/src/components/SideBar.tsx b/src/components/SideBar.tsx index 424675d..7deb407 100644 --- a/src/components/SideBar.tsx +++ b/src/components/SideBar.tsx @@ -1,18 +1,10 @@ -import { Outlet, useLocation, useNavigate } from 'react-router-dom'; +import { Outlet, useNavigate } from 'react-router-dom'; import '../assets/css/SideBar.css'; import CodePrezLogo from '../assets/logo.svg'; import { NavigationButton } from './NavigationButton'; -import { Slide } from './Slide'; -import { useState, useEffect } from 'react'; -export const SideBar = () => { - const [presentationData, setPresentationData] = useState(); - - const navigate = useNavigate(); - const {state} = useLocation(); - useEffect(() => { - setPresentationData(state); - },[]) +export const SideBar = () => { + const navigate = useNavigate(); const home = () => { navigate('/'); @@ -27,15 +19,6 @@ export const SideBar = () => {
- {Array.isArray(presentationData?.presentationFileContent) && - presentationData?.presentationFileContent.map((slide, index) => ( - - {slide} - - ))} -
diff --git a/src/components/Slide.tsx b/src/components/Slide.tsx index c939cd6..2bb4512 100644 --- a/src/components/Slide.tsx +++ b/src/components/Slide.tsx @@ -2,12 +2,13 @@ import { useEffect } from "react"; import "../assets/css/Slide.css" type Props = { - children: string; + children: string | React.ReactElement[]; slideScale: "preview" | "sidebar" | "slideViewer" } export const Slide = ({ children, slideScale }: Props) => { + if(typeof children == "string") { return (
{ >
); + } else { + return ( +
+ {children} +
+ ) + } + }; From ed341fdb2ec950bd9be316b7d256d53760ec1a7a Mon Sep 17 00:00:00 2001 From: matheoleger <71370253+matheoleger@users.noreply.github.com> Date: Sun, 9 Apr 2023 15:13:45 +0200 Subject: [PATCH 3/7] feat(slide): Fix assets + fix style for code --- src/assets/css/Presentation.css | 1 + src/assets/css/Slide.css | 22 +++++++++++++++++++++- src/main/createArchive.ts | 2 +- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/assets/css/Presentation.css b/src/assets/css/Presentation.css index 47c129c..5e03e07 100644 --- a/src/assets/css/Presentation.css +++ b/src/assets/css/Presentation.css @@ -1,6 +1,7 @@ .presentation-page { overflow-y: auto; overflow-x: hidden; + width: 100%; } .presentation-header { diff --git a/src/assets/css/Slide.css b/src/assets/css/Slide.css index 6d524bc..1f82fe0 100644 --- a/src/assets/css/Slide.css +++ b/src/assets/css/Slide.css @@ -8,8 +8,14 @@ section { flex-direction: column; justify-content: center; align-items: center; - flex-wrap: wrap; + /* flex-wrap: wrap; */ background: var(--black-grey); + box-sizing: border-box; + /* padding: 0 40px; */ +} + +h1 { + font-size: 2em; } section p img { @@ -28,10 +34,24 @@ pre { border-radius: 10px; min-width: 20%; max-width: 90%; + max-height: 60%; display: flex; + justify-content: space-between; + align-items: center; + box-sizing: border-box; +} + +pre code { + border-radius: inherit; + width: 100%; + max-height: 100%; overflow: auto; } +strong { + margin: 0 4px; +} + code:not(pre > code) { background-color: var(--dark-grey); border-radius: 5px; diff --git a/src/main/createArchive.ts b/src/main/createArchive.ts index a0773dc..03ccc47 100644 --- a/src/main/createArchive.ts +++ b/src/main/createArchive.ts @@ -55,7 +55,7 @@ export const createArchive = async (data: CreationCodePrezProps, file: string) = archive.directory(data.envDirectoryPath, 'env'); } if (data.assetsDirectoryPath) { - archive.directory(data.assetsDirectoryPath, 'css'); + archive.directory(data.assetsDirectoryPath, 'assets'); } archive.finalize().then(() => { From a57a05438de89051fd921a07e5b8bdac9180bd36 Mon Sep 17 00:00:00 2001 From: matheoleger <71370253+matheoleger@users.noreply.github.com> Date: Sun, 9 Apr 2023 15:37:03 +0200 Subject: [PATCH 4/7] fix(slide+archive): Fix archive and authors key --- src/components/Presentation.tsx | 4 ++-- src/main/markdownRenderer.ts | 1 + src/main/openAndCloseCodePrezFiles.ts | 13 +++++++++---- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/components/Presentation.tsx b/src/components/Presentation.tsx index 7b432d6..7512ffa 100644 --- a/src/components/Presentation.tsx +++ b/src/components/Presentation.tsx @@ -31,8 +31,8 @@ export const Presentation = () => {

Créé par :

- {presentationData?.presentationConfig.authors.map((author) => ( -

{author}

+ {presentationData?.presentationConfig.authors.map((author, index) => ( +

{author}

))}
diff --git a/src/main/markdownRenderer.ts b/src/main/markdownRenderer.ts index 4bfe83c..32eb740 100644 --- a/src/main/markdownRenderer.ts +++ b/src/main/markdownRenderer.ts @@ -75,6 +75,7 @@ const imageRendererRules = ({tokens, idx, options, env, self, presentationPath}: const regexForSrc = /\.\/assets/gm; const srcWithPresentationPath = (src?.match(regexForSrc)) ? path.join("codeprez:/", presentationPath, src) : src + console.log(srcWithPresentationPath); token.attrSet('src', srcWithPresentationPath || "") return self.renderToken(tokens, idx, options) diff --git a/src/main/openAndCloseCodePrezFiles.ts b/src/main/openAndCloseCodePrezFiles.ts index 4ceb463..786910f 100644 --- a/src/main/openAndCloseCodePrezFiles.ts +++ b/src/main/openAndCloseCodePrezFiles.ts @@ -22,6 +22,8 @@ const decompressCodePrezArchive = async ( export const openCodePrezArchive = async (archivePath: string) => { const presentationPath = path.join(tempPath, "codeprez"); //useful for assets, style.css and env + deleteCodePrezTempFolder(); + const files = await decompressCodePrezArchive( archivePath, presentationPath @@ -45,10 +47,13 @@ export const openCodePrezArchive = async (archivePath: string) => { return { presentationConfig, presentationFileContent, presentationPath, presentationStyle }; }; -export const deleteCodePrezTempFolder = () => { +export const deleteCodePrezTempFolder = async () => { const presentationPath = path.join(tempPath, "codeprez"); - fs.rmdir(presentationPath, (err) => { - console.error(err); - }); + try { + fs.rmSync(presentationPath, { recursive: true }); + } catch(e) { + console.error(e); + return; + } }; From 87e7dfc754352f059fb22164a39559495d73f01e Mon Sep 17 00:00:00 2001 From: matheoleger <71370253+matheoleger@users.noreply.github.com> Date: Sun, 9 Apr 2023 17:38:41 +0200 Subject: [PATCH 5/7] feat(Slide): Add presentation mode --- index.ts | 13 ++++++ src/App.tsx | 3 +- src/assets/css/SlideViewer.css | 14 ++++++ src/components/NavigationButton.tsx | 10 ++++- src/components/Presentation.tsx | 5 --- src/components/Slide.tsx | 9 ++-- src/main/markdownRenderer.ts | 1 - src/preload/preload.ts | 8 ++++ src/renderer/components/SlideViewer.tsx | 57 +++++++++++++++++++++++++ 9 files changed, 107 insertions(+), 13 deletions(-) create mode 100644 src/assets/css/SlideViewer.css create mode 100644 src/renderer/components/SlideViewer.tsx diff --git a/index.ts b/index.ts index 56a672f..e4f3b65 100644 --- a/index.ts +++ b/index.ts @@ -56,6 +56,19 @@ const createWindow = () => { win.webContents.send("set-codeprez-data", presentationData); }); + //Set to maximize + win.webContents.ipc.on("maximized-app", () => { + console.log("maximized-app") + win.setFullScreen(false) + }) + + //Set to fullscreen + win.webContents.ipc.on("fullscreen-app", () => { + console.log("fullscreen-app") + win.setFullScreen(true) + }) + + win.once("ready-to-show", async () => { win.show(); diff --git a/src/App.tsx b/src/App.tsx index f27eebd..1cdf70e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,6 +5,7 @@ import { HashRouter, Route, Routes } from "react-router-dom"; import { SideBar } from "./components/SideBar"; import { Home } from "./components/Home"; import { Presentation } from "./components/Presentation"; +import { SlideViewer } from "./renderer/components/SlideViewer" import "highlight.js/styles/github.css"; function App() { @@ -27,7 +28,7 @@ function App() { - +
diff --git a/src/assets/css/SlideViewer.css b/src/assets/css/SlideViewer.css new file mode 100644 index 0000000..f18c2d9 --- /dev/null +++ b/src/assets/css/SlideViewer.css @@ -0,0 +1,14 @@ +.viewer-container { + height: 100vh; + scroll-snap-type: y mandatory; + overflow-y: auto; + scroll-behavior: smooth; +} + +.viewer-container:focus { + outline:none; +} + +.viewer-slide { + scroll-snap-align: start; +} \ No newline at end of file diff --git a/src/components/NavigationButton.tsx b/src/components/NavigationButton.tsx index 4667290..acf2536 100644 --- a/src/components/NavigationButton.tsx +++ b/src/components/NavigationButton.tsx @@ -1,5 +1,5 @@ import React, { FC } from 'react'; -import { useNavigate } from 'react-router-dom'; +import { useLocation, useNavigate } from 'react-router-dom'; interface NavigationButtonProp { goTo: 'prez' | 'add' |'viewer'; withIcon?: boolean; @@ -10,6 +10,8 @@ export const NavigationButton: FC = ({ withIcon, }) => { const navigate = useNavigate(); + const {state} = useLocation(); + const createCodePrez = () => { navigate('/add'); }; @@ -24,6 +26,10 @@ export const NavigationButton: FC = ({ }); } + const playPresentation = () => { + navigate('/viewer', {state: state}); + } + if (goTo === 'prez') { return ( ' - ) - } else { - return ( - '
' +
-                            hljs.highlight(str, {
-                                language: lang,
-                                ignoreIllegals: true,
-                            }).value +
-                            "
" - ); - } - - - } catch (__) {} - } - - return ( - '
' +
-                md.utils.escapeHtml(str) +
-                "
" - ); - }, - } - - const md = MarkdownIt(markdownOptions); - - //Include images - md.renderer.rules.image = (tokens, idx, options, env, self) => { - const token = tokens[idx]; - - const src = token.attrGet("src"); - - const regexForSrc = /\.\/assets/gm; - - const srcWithPresentationPath = (src?.match(regexForSrc)) ? path.join("codeprez:/", presentationPath, src) : src - token.attrSet('src', srcWithPresentationPath || "") - - return self.renderToken(tokens, idx, options) - } - - //Include code via files - md.renderer.rules.link_open = (tokens, idx, options, env, self) => { - const token = tokens[idx]; - - const href = token.attrGet("href"); - - const regexPathFile = /^\.\/(.+\.\w+)/gm; - const regexLineNumber = /#(\d+)-(\d+)/; - const regexFileExtension = /\.(\w+)(?:#\d+-\d+)?$/; - - const pathFile = href?.match(regexPathFile) ?? []; - - const lineNumbers = href?.match(regexLineNumber) ?? []; - const startNumber = lineNumbers[1]; - const endNumber = lineNumbers[2]; - - const fileExtension = href?.match(regexFileExtension) ?? []; - - if(pathFile) { - const file = fs.readFileSync(path.join(presentationPath, pathFile[0] ?? ""), { encoding: 'utf8' }); - const lines = file.split("\n").slice(Number(startNumber)-1, Number(endNumber)); - - // return ( - // `
${hljs.highlight(lines.join("\n"), {
-            //                 language: fileExtension[1] || "",
-            //                 ignoreIllegals: true,
-            //             }).value}
` - // ) - - // I must use a concatenate string instead of `` because of tabulation and break line - return ( - "
" +
-                    hljs.highlight(lines.join("\n"), {
-                            language: fileExtension[1] || "",
-                            ignoreIllegals: true,
-                        }).value +
-                    "
" - ) - } - - return self.renderToken(tokens, idx, options); - } - - return md; -} +export {} \ No newline at end of file