Spaces:
Running
Running
Commit ·
5a2ba2c
1
Parent(s): e1e42ea
Create paper drive page template
Browse files- src/RenderUtils.ts +8 -0
- src/paperdrive/PaperDrivePage.tsx +157 -30
src/RenderUtils.ts
CHANGED
|
@@ -19,6 +19,14 @@ function levenshteinDistance(str1: string, str2: string) {
|
|
| 19 |
}
|
| 20 |
export class RenderUtils {
|
| 21 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
public static splitWordsIntoGroups(words: any) {
|
| 23 |
const groups = [];
|
| 24 |
let currentGroup = [];
|
|
|
|
| 19 |
}
|
| 20 |
export class RenderUtils {
|
| 21 |
|
| 22 |
+
public static convertVHToPixels(vh: string) {
|
| 23 |
+
return Math.round(window.innerHeight * (parseInt(vh.replace("vh", "")) / 100));
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
public static convertVWToPixels(vw: string) {
|
| 27 |
+
return Math.round(window.innerWidth * (parseInt(vw.replace("vw", "")) / 100));
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
public static splitWordsIntoGroups(words: any) {
|
| 31 |
const groups = [];
|
| 32 |
let currentGroup = [];
|
src/paperdrive/PaperDrivePage.tsx
CHANGED
|
@@ -1,19 +1,24 @@
|
|
| 1 |
import { Transcript } from "common-utils"
|
| 2 |
-
import React from "react"
|
| 3 |
-
import { AbsoluteFill, staticFile } from "remotion"
|
| 4 |
import { QRCode } from 'react-qrcode-logo';
|
| 5 |
import { RenderUtils } from '../RenderUtils';
|
|
|
|
|
|
|
| 6 |
|
| 7 |
export type PaperDrivePageExtras = {
|
|
|
|
| 8 |
marginBottom: string;
|
| 9 |
url: string,
|
| 10 |
leftMarginLineColor?: string,
|
| 11 |
lineColor?: string,
|
|
|
|
|
|
|
| 12 |
qr?: {
|
| 13 |
logoOpacity?: number;
|
| 14 |
-
|
| 15 |
color?: string | undefined;
|
| 16 |
-
size?:
|
| 17 |
qrStyle?: "squares" | "dots" | "fluid"
|
| 18 |
position?: {
|
| 19 |
position: "static" | "relative" | "absolute" | "sticky" | "fixed" // "right"
|
|
@@ -23,56 +28,178 @@ export type PaperDrivePageExtras = {
|
|
| 23 |
right?: number // 0
|
| 24 |
}
|
| 25 |
},
|
| 26 |
-
|
| 27 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
}
|
| 29 |
export function PaperDrivePage({ transcript }: { transcript: Transcript }) {
|
| 30 |
const extras = transcript.extras as PaperDrivePageExtras
|
| 31 |
-
const qrImageBlend =
|
| 32 |
const defaultQrSize = 300
|
| 33 |
const logo = qrImageBlend ? staticFile(RenderUtils.getFileName(qrImageBlend)!) : undefined
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
return (
|
| 35 |
<AbsoluteFill style={{
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
|
|
|
| 39 |
}}>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
<AbsoluteFill style={{
|
| 41 |
-
|
| 42 |
position: 'relative',
|
| 43 |
-
padding: '20px',
|
| 44 |
-
backgroundImage: `linear-gradient(to bottom, transparent 94%, ${extras.lineColor ?? 'lightgray'} 94%)`,
|
| 45 |
-
backgroundSize: '100% 30px'
|
| 46 |
}}>
|
| 47 |
</AbsoluteFill>
|
| 48 |
|
| 49 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
position: 'absolute',
|
| 51 |
-
top: 0,
|
| 52 |
-
|
|
|
|
|
|
|
| 53 |
}}>
|
| 54 |
-
<
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
|
|
|
|
|
|
|
| 67 |
<div style={{
|
| 68 |
position: 'absolute',
|
| 69 |
-
left: extras.marginLeft,
|
| 70 |
top: '0',
|
| 71 |
height: '100%',
|
| 72 |
width: '2px',
|
| 73 |
backgroundColor: extras.leftMarginLineColor ?? 'lightgray',
|
| 74 |
}}>
|
| 75 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
</AbsoluteFill>
|
| 77 |
)
|
| 78 |
}
|
|
|
|
| 1 |
import { Transcript } from "common-utils"
|
| 2 |
+
import React, { CSSProperties } from "react"
|
| 3 |
+
import { AbsoluteFill, Img, staticFile } from "remotion"
|
| 4 |
import { QRCode } from 'react-qrcode-logo';
|
| 5 |
import { RenderUtils } from '../RenderUtils';
|
| 6 |
+
import { loadFont as loadLato } from "@remotion/google-fonts/Lato";
|
| 7 |
+
import { loadFont as loadPoppins } from "@remotion/google-fonts/Poppins";
|
| 8 |
|
| 9 |
export type PaperDrivePageExtras = {
|
| 10 |
+
backgroundColor: string;
|
| 11 |
marginBottom: string;
|
| 12 |
url: string,
|
| 13 |
leftMarginLineColor?: string,
|
| 14 |
lineColor?: string,
|
| 15 |
+
marginLeft: string // "10%"
|
| 16 |
+
marginTop: string // "10%"
|
| 17 |
qr?: {
|
| 18 |
logoOpacity?: number;
|
| 19 |
+
logo?: string;
|
| 20 |
color?: string | undefined;
|
| 21 |
+
size?: string //200 10vh 10vw
|
| 22 |
qrStyle?: "squares" | "dots" | "fluid"
|
| 23 |
position?: {
|
| 24 |
position: "static" | "relative" | "absolute" | "sticky" | "fixed" // "right"
|
|
|
|
| 28 |
right?: number // 0
|
| 29 |
}
|
| 30 |
},
|
| 31 |
+
header?: {
|
| 32 |
+
underline_style?: CSSProperties
|
| 33 |
+
fontFamily?: string // Lato, sans-serif
|
| 34 |
+
color?: string // black
|
| 35 |
+
text_title?: string // Title
|
| 36 |
+
text_date?: string // Date
|
| 37 |
+
text_page?: string // Page
|
| 38 |
+
},
|
| 39 |
+
footer: {
|
| 40 |
+
text?: string // Lorem ipsum dolor
|
| 41 |
+
text_style?: CSSProperties
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
}
|
| 45 |
export function PaperDrivePage({ transcript }: { transcript: Transcript }) {
|
| 46 |
const extras = transcript.extras as PaperDrivePageExtras
|
| 47 |
+
const qrImageBlend = extras?.qr?.logo
|
| 48 |
const defaultQrSize = 300
|
| 49 |
const logo = qrImageBlend ? staticFile(RenderUtils.getFileName(qrImageBlend)!) : undefined
|
| 50 |
+
const watermark = transcript.imageAbsPaths?.[0]
|
| 51 |
+
let watermarkPath = undefined
|
| 52 |
+
if (watermark) {
|
| 53 |
+
watermarkPath = staticFile(RenderUtils.getFileName(watermark.path)!)
|
| 54 |
+
}
|
| 55 |
+
loadLato();
|
| 56 |
+
loadPoppins();
|
| 57 |
+
|
| 58 |
+
let qrSize = defaultQrSize
|
| 59 |
+
if (extras.qr?.size?.includes("vh")) {
|
| 60 |
+
qrSize = RenderUtils.convertVHToPixels(extras.qr?.size)
|
| 61 |
+
} else if (extras.qr?.size?.includes("vw")) {
|
| 62 |
+
qrSize = RenderUtils.convertVWToPixels(extras.qr?.size)
|
| 63 |
+
} else if (extras.qr?.size) {
|
| 64 |
+
qrSize = parseInt(extras.qr?.size)
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
|
| 68 |
return (
|
| 69 |
<AbsoluteFill style={{
|
| 70 |
+
zIndex: -11,
|
| 71 |
+
background: extras?.backgroundColor ?? 'white',
|
| 72 |
+
paddingTop: extras.marginTop ?? '10vh',
|
| 73 |
+
paddingBottom: extras.marginBottom ?? '10vh',
|
| 74 |
}}>
|
| 75 |
+
{
|
| 76 |
+
watermarkPath &&
|
| 77 |
+
<Img src={watermarkPath}
|
| 78 |
+
style={{
|
| 79 |
+
zIndex: -10,
|
| 80 |
+
position: 'absolute',
|
| 81 |
+
top: 0,
|
| 82 |
+
left: 0,
|
| 83 |
+
bottom: 0,
|
| 84 |
+
width: '100%',
|
| 85 |
+
height: '100%',
|
| 86 |
+
objectFit: 'cover'
|
| 87 |
+
}} />
|
| 88 |
+
}
|
| 89 |
<AbsoluteFill style={{
|
| 90 |
+
zIndex: 10,
|
| 91 |
position: 'relative',
|
| 92 |
+
padding: '20px',
|
| 93 |
+
backgroundImage: `linear-gradient(to bottom, transparent 94%, ${extras.lineColor ?? 'lightgray'} 94%)`,
|
| 94 |
+
backgroundSize: '100% 30px'
|
| 95 |
}}>
|
| 96 |
</AbsoluteFill>
|
| 97 |
|
| 98 |
+
<QRCode
|
| 99 |
+
style={extras.qr?.position ?? {
|
| 100 |
+
position: 'absolute',
|
| 101 |
+
top: 0,
|
| 102 |
+
right: 0
|
| 103 |
+
}}
|
| 104 |
+
fgColor={extras.qr?.color ?? 'black'}
|
| 105 |
+
size={qrSize ?? defaultQrSize}
|
| 106 |
+
value={extras.url}
|
| 107 |
+
qrStyle={extras.qr?.qrStyle ?? 'squares'}
|
| 108 |
+
logoImage={logo}
|
| 109 |
+
logoWidth={qrSize ?? defaultQrSize}
|
| 110 |
+
logoHeight={qrSize ?? defaultQrSize}
|
| 111 |
+
logoOpacity={extras.qr?.logoOpacity ?? 0.1}
|
| 112 |
+
removeQrCodeBehindLogo={false}
|
| 113 |
+
/>
|
| 114 |
+
<div style={{
|
| 115 |
position: 'absolute',
|
| 116 |
+
top: '0',
|
| 117 |
+
left: extras.marginLeft ?? '10%',
|
| 118 |
+
paddingLeft: 20,
|
| 119 |
+
height: extras.marginTop,
|
| 120 |
}}>
|
| 121 |
+
<div style={{
|
| 122 |
+
padding: 20,
|
| 123 |
+
flex: 1,
|
| 124 |
+
height: '100%',
|
| 125 |
+
display: 'flex',
|
| 126 |
+
justifyContent: 'space-evenly', // Even vertical spacing
|
| 127 |
+
alignItems: 'flex-start', // Align items to the left (start of flex container)
|
| 128 |
+
flexDirection: 'column' // Stack items in a column (Y-axis)
|
| 129 |
+
}}>
|
| 130 |
+
{extras?.header?.text_title && <h2 style={{
|
| 131 |
+
display: 'inline-block'
|
| 132 |
+
}}>
|
| 133 |
+
<span dangerouslySetInnerHTML={{ __html: extras?.header?.text_title }} />
|
| 134 |
+
<span style={{
|
| 135 |
+
textDecoration: 'underline',
|
| 136 |
+
marginLeft: '1rem',
|
| 137 |
+
display: 'inline-block',
|
| 138 |
+
width: '40vw',
|
| 139 |
+
borderBottom: '1px dotted black',
|
| 140 |
+
...extras?.header?.underline_style
|
| 141 |
+
}}>
|
| 142 |
+
</span>
|
| 143 |
+
</h2>}
|
| 144 |
+
{
|
| 145 |
+
extras?.header?.text_date &&
|
| 146 |
+
<div style={{
|
| 147 |
+
display: 'inline-block'
|
| 148 |
+
}}>
|
| 149 |
+
<span dangerouslySetInnerHTML={{ __html: extras?.header?.text_date }} />
|
| 150 |
+
<span style={{
|
| 151 |
+
textDecoration: 'underline',
|
| 152 |
+
marginLeft: '1rem',
|
| 153 |
+
display: 'inline-block',
|
| 154 |
+
borderBottom: '1px dotted black',
|
| 155 |
+
...extras?.header?.underline_style,
|
| 156 |
+
width: '10vw',
|
| 157 |
+
|
| 158 |
+
}}>
|
| 159 |
+
</span>
|
| 160 |
+
</div>
|
| 161 |
+
}
|
| 162 |
+
{
|
| 163 |
+
extras?.header?.text_page &&
|
| 164 |
+
<span dangerouslySetInnerHTML={{ __html: extras?.header?.text_page }} />
|
| 165 |
+
}
|
| 166 |
|
| 167 |
+
</div>
|
| 168 |
+
</div>
|
| 169 |
<div style={{
|
| 170 |
position: 'absolute',
|
| 171 |
+
left: extras.marginLeft ?? '10%',
|
| 172 |
top: '0',
|
| 173 |
height: '100%',
|
| 174 |
width: '2px',
|
| 175 |
backgroundColor: extras.leftMarginLineColor ?? 'lightgray',
|
| 176 |
}}>
|
| 177 |
</div>
|
| 178 |
+
|
| 179 |
+
<div style={{
|
| 180 |
+
width: '100%',
|
| 181 |
+
height: extras.marginBottom ?? '10vh',
|
| 182 |
+
position: 'absolute',
|
| 183 |
+
left: 0,
|
| 184 |
+
bottom: 0
|
| 185 |
+
}}>
|
| 186 |
+
<div style={{
|
| 187 |
+
height: '100%',
|
| 188 |
+
display: 'flex',
|
| 189 |
+
justifyContent: 'center',
|
| 190 |
+
alignItems: 'center'
|
| 191 |
+
}}>
|
| 192 |
+
{
|
| 193 |
+
extras?.footer?.text && (
|
| 194 |
+
<span style={{
|
| 195 |
+
fontFamily: extras.header?.fontFamily ?? 'Lato, sans-serif',
|
| 196 |
+
...extras?.footer?.text_style
|
| 197 |
+
}} dangerouslySetInnerHTML={{ __html: extras?.footer?.text }} />
|
| 198 |
+
)
|
| 199 |
+
}
|
| 200 |
+
</div>
|
| 201 |
+
</div>
|
| 202 |
+
|
| 203 |
</AbsoluteFill>
|
| 204 |
)
|
| 205 |
}
|