Generating PDF in next.js - pdf

Hii i am trying to generate PDF in next.js. I tried many libraries like react-pdf, jsPDF etc. but all they are client side library they need window to perform their action. Is There any solution for generating pdf in next.js. If Present then please suggest with code example.

i recommend to use the api routes of next.js and use a node.js pdf library. On the frontend you access the api with the correct path to return the pdf and just render it.
next.js api routes
pdf-lib
Example:
import { PDFDocument, StandardFonts, rgb } from 'pdf-lib'
export default async (req, res) => {
const pdfDoc = await PDFDocument.create();
// do pdf stuff
const buffer = await pdfDoc.save();
res.send(buffer);
};
export const config = {
api: { bodyParser: false, },
};

Using jsPDF, I found this tutorial with Next.js.
pages/index.tsx:
import * as React from "react";
import Image from "next/image";
import dynamic from "next/dynamic";
const GeneratePDF = dynamic(()=>import("./../src/components/GeneratePDF"),{ssr:false});
const app =()=>{
const ref = React.useRef();
return(<div className="main">
<div className="content" ref={ref}>
<h1>Hello PDF</h1>
<img id="image" src="/images/image_header.jpg" width="300" height="200"/>
<p id="text">
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Quisquam animi, molestiae quaerat assumenda neque culpa ab aliquam facilis eos nesciunt! Voluptatibus eligendi vero amet dolorem omnis provident beatae nihil earum!
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Ea, est. Magni animi fugit voluptates mollitia officia libero in. Voluptatibus nisi assumenda accusamus deserunt sunt quidem in, ab perspiciatis ad rem.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Nihil accusantium reprehenderit, quasi dolorum deserunt, nisi dolores quae officiis odio vel natus! Pariatur enim culpa velit consequatur sapiente natus dicta alias!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequatur, asperiores error laudantium corporis sunt earum incidunt expedita quo quidem delectus fugiat facilis quia impedit sit magni quibusdam ipsam reiciendis quaerat!
</p>
</div>
<GeneratePDF html={ref}/>
</div>);
}
export default app;

Related

React native gesture handler overwrites on android but not on ios

I was wondering why my react native if i wrap scrollview with gesture detector, I'm unable to scroll on android but able to scroll on ios. I was wondering how I can make my scrollview work on android.
Thanks!
const gest = Gesture.Pan().onUpdate((e) => {...})
return(
<GestureDetector gesture={roomGestureTV}>
<ScrollView ... />
</GestureDetector>
)
Here is a Snack that shows how to wrap a ScrollView with a PanGesture (Snack or below for future reference). I have tested the code on a Galaxy S9 (Android) and iPhone 13 (Real and Emulator).
Some notes (See the snack first!):
The behaviour for android and IOS gestures differs, because they (react-native-gesture-handler) had to implement a custom solution on Android but not on IOS. On Android the pan gesture cancels the ScrollView gesture, but on IOS the ScrollView cancels the PanGesture. In both cases PanGesture and Scroll gesture do not work simultanously out of the box.
Use createNativeWrapper instead of the ScrollView from gesture handler. While the ScrollView from gesture handler will work, other components that build on ScrollView will not (e.g. FlatLists). In order to use a FlatList instead of a ScrollView, exchange the ScrollView with a FlatList in createNativeWrapper
createNativeWrapper is no longer activly supported by the libary (Source). However, the new/old Native Gesture Component is not working for this use case (at least for me). This might be a bug and might be fixed in newer versions.
Note that simultaneousHandlers for the ScrollView is not limited to one gesture but can accept multiple gestures. E.g. it is possible to have a pan and pinch gesture while scrolling.
Reference Code
import React, { useRef } from 'react';
import { Text, View, ScrollView } from 'react-native';
import Animated, {
useDerivedValue,
useSharedValue,
useWorkletCallback,
} from 'react-native-reanimated';
import {
createNativeWrapper,
GestureHandlerRootView,
Gesture,
GestureDetector,
} from 'react-native-gesture-handler';
import ReText from './components/ReText';
/**
* Gesture states
* (see https://docs.swmansion.com/react-native-gesture-handler/docs/under-the-hood/states-events)
*/
const STATES = {
0: 'UNDETERMINED',
1: 'FAILED',
2: 'BEGAN',
3: 'CANCELLED',
4: 'ACTIVE',
5: 'END',
};
const CustomScrollComponent = createNativeWrapper(ScrollView)
export default function App() {
const panRef = useRef(null);
const scrollRef = useRef(null);
// Log values
const touchPosition = useSharedValue({ x: null, y: null });
const touchPositionX = useDerivedValue(() => {
return `x: ${touchPosition.value.x}`;
});
const touchPositionY = useDerivedValue(() => {
return `y: ${touchPosition.value.y}`;
});
const state = useSharedValue([STATES[0], 'null', 'null']);
const stateString = useDerivedValue(() => {
return `${state.value[0]}\n${state.value[1]}\n${state.value[2]}`;
});
const appendState = useWorkletCallback((arr, value) => {
return [value].concat(arr.slice(0, 2));
}, []);
const panGesture = Gesture.Pan()
.onBegin((e) => {
state.value = appendState(state.value, STATES[e.state]);
})
.onStart((e) => {
state.value = appendState(state.value, STATES[e.state]);
})
.onUpdate((e) => {
if (state.value[0] !== STATES[e.state]) {
state.value = appendState(state.value, STATES[e.state]);
}
touchPosition.value = { x: e.absoluteX, y: e.absoluteY };
})
.onEnd((e) => {
state.value = appendState(state.value, STATES[e.state]);
})
.onFinalize((e) => {
state.value = appendState(state.value, STATES[e.state]);
touchPosition.value = { x: null, y: null };
})
.simultaneousWithExternalGesture(scrollRef)
.withRef(panRef);
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<View style={{ flex: 1 }}>
{/** Logger */}
<View style={{ padding: 16, height: 180, justifyContent: 'flex-end' }}>
<ReText text={touchPositionX} />
<ReText text={touchPositionY} />
<Text>Gesture States (New -> Old):</Text>
<ReText text={stateString} />
</View>
{/** ScrollView with pan gesture */}
<GestureDetector gesture={panGesture}>
<Animated.View style={{ flex: 1 }}>
<CustomScrollComponent
disallowInterruption={false}
scrollEnabled={true}
ref={scrollRef}
style={{ flex: 1 }}
simultaneousHandlers={panRef}>
<Text>
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed
diam nonumy eirmod tempor invidunt ut labore et dolore magna
aliquyam erat, sed diam voluptua. At vero eos et accusam et
justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea
takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum
dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
sed diam voluptua. At vero eos et accusam et justo duo dolores
et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus
est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet,
consetetur sadipscing elitr, sed diam nonumy eirmod tempor
invidunt ut labore et dolore magna aliquyam erat, sed diam
voluptua. At vero eos et accusam et justo duo dolores et ea
rebum. Stet clita kasd gubergren, no sea takimata sanctus est
Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet,
consetetur sadipscing elitr, sed diam nonumy eirmod tempor
invidunt ut labore et dolore magna aliquyam erat, sed diam
voluptua. At vero eos et accusam et justo duo dolores et ea
rebum. Stet clita kasd gubergren, no sea takimata sanctus est
Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet,
consetetur sadipscing elitr, sed diam nonumy eirmod tempor
invidunt ut labore et dolore magna aliquyam erat, sed diam
voluptua. At vero eos et accusam et justo duo dolores et ea
rebum. Stet clita kasd gubergren, no sea takimata sanctus est
Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet,
consetetur sadipscing elitr, sed diam nonumy eirmod tempor
invidunt ut labore et dolore magna aliquyam erat, sed diam
voluptua. At vero eos et accusam et justo duo dolores et ea
rebum. Stet clita kasd gubergren, no sea takimata sanctus est
Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet,
consetetur sadipscing elitr, sed diam nonumy eirmod tempor
invidunt ut labore et dolore magna aliquyam erat, sed diam
voluptua. At vero eos et accusam et justo duo dolores et ea
rebum. Stet clita kasd gubergren, no sea takimata sanctus est
Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet,
consetetur sadipscing elitr, sed diam nonumy eirmod tempor
invidunt ut labore et dolore magna aliquyam erat, sed diam
voluptua. At vero eos et accusam et justo duo dolores et ea
rebum. Stet clita kasd gubergren, no sea takimata sanctus est
Lorem ipsum dolor sit amet. gubergren, no sea takimata sanctus
est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet,
consetetur sadipscing elitr, sed diam nonumy eirmod tempor
invidunt ut labore et dolore magna aliquyam erat, sed diam
voluptua. At vero eos et accusam et justo duo dolores et ea
rebum. Stet clita kasd gubergren, no sea takimata sanctus est
Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet,
consetetur sadipscing elitr, sed diam nonumy eirmod tempor
invidunt ut labore et dolore magna aliquyam erat, sed diam
voluptua. At vero eos et accusam et justo duo dolores et ea
rebum. Stet clita kasd gubergren, no sea takimata sanctus est
Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet,
consetetur sadipscing elitr, sed diam nonumy eirmod tempor
invidunt ut labore et dolore magna aliquyam erat, sed diam
voluptua. At vero eos et accusam et justo duo dolores et ea
rebum. Stet clita kasd gubergren, no sea takimata sanctus est
Lorem ipsum dolor sit amet.
</Text>
</CustomScrollComponent>
</Animated.View>
</GestureDetector>
</View>
</GestureHandlerRootView>
);
}

How Print Vue Component W/ Styles

I'm trying to print a component using VueJS all style is in the same file, but it's not getting the CSS Styling. Also I use Quasar framework, don't know if it can affect the final result.
<div style="margin: 12px 12px">
<div class="central-layout">
<p>
<strong
><a href="https://www.nightprogrammer.com/" target="_blank"
>Nightprogrammer.com</a
></strong
>: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus
posuere, tellus lobortis posuere tempor, elit sem varius libero, ac
vulputate ante orci vel odio. Nam sit amet tortor malesuada tellus
rutrum varius vel a mauris. Integer volutpat neque mauris, vel imperdiet
mi aliquet ac. Proin sed iaculis ipsum. Vivamus tincidunt egestas
sapien, vitae faucibus velit ultricies eget. Donec mattis ante arcu, a
pretium tortor scelerisque et. Morbi sed dui tempor, consectetur turpis
sed, tristique arcu.
</p>
</div>
</div>
<style scoped>
.central-layout{
flex-direction: column-reverse;
}
</style>
exportToPDF() {
const content = this.$refs.printInteraction.innerHTML
let cssHtml = ''
for (const node of [...document.querySelectorAll('style')]) {
cssHtml += node.outerHTML
}
const winPrint = window.open('', '', 'left=0,top=0,width=800,height=900,toolbar=0,scrollbars=0,status=0')
winPrint.document.write(`<!DOCTYPE html>
<html>
<head>
${cssHtml}
</head>
<body>
${content}
</body>
</html>`)
winPrint.document.close()
winPrint.focus()
winPrint.print()
winPrint.close()
}
}
}
Can anyone help me?
I need to print with the styling set in the page
Exporting that properly may be quite difficult because not all the things are properly supported. I recommend the usage of this: https://github.com/niklasvh/html2canvas
Then you could convert the image into a PDF. But anyway, such thing is quite heavy and should be handled by some backend: convert, host the file on AWS/alike and sent back as a callback.

How can I inject fonts and colour variables (fetched from backend api upon page load) into Nuxt.js styles?

I am building an application in Nuxt.js where each clients can configure custom fonts & colours depending on their brand. Clients can specify upto 3 fonts and 3 colours, which are exposed to the front-end via an api endpoint:
Fonts:
primary-font
secondary-font
tertiary-font
Colours:
primary-colour
seconday-colour
tertiary-colour
How can I inject these fonts and colours into the application when a user visits the clients link https://{client-slug}.{domain}.com ?
You can construct a FontFace object and inject it to the document.
Following are the example of how you can achieve it. You can run the code snippet:
const fontFamily = 'Sansita Swashed'; // your custom font family
const fontSrc = 'https://fonts.gstatic.com/s/sansitaswashed/v1/BXR8vFfZifTZgFlDDLgNkBydPKTt3pVCeYWqJnZSW7RpXTIfeymE.woff2' // your custom font source
function injectCustomFont() {
const customFont = new FontFace(fontFamily, `url(${fontSrc})`);
customFont.load().then((font) => {
document.fonts.add(font);
document.body.style.fontFamily = '"Sansita Swashedr", cursive';
});
}
document.getElementById('btnFontChanger').addEventListener('click', () => {
injectCustomFont();
});
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<button id="btnFontChanger" type="button">Click to change font</button>
FontFace() constructor can accept one more parameter. Learn more at here.
Note:
FontFace is still an experimental. You must double check the browser compatibility before using it.
Relatable links:
https://usefulangle.com/post/74/javascript-dynamic-font-loading
https://developer.mozilla.org/en-US/docs/Web/API/FontFace/FontFace

How to change the layout of ion-slide?

I'm trying to use ion-slides:
<ion-content>
<ion-slides pager="true" [options]="slideOpts">
<ion-slide class="step-one">
<h1>Welcome</h1>
<p>Lorem ipsum dolor sit amet, massa nam ante. Vel lacus viverra volutpat tortor ligula ornare, varius ut mauris ipsum mus torquent, scelerisque suspendisse penatibus, purus et arcu ipsum vehicula quam luctus. Consectetuer sed urna accumsan. Nec viverra felis varius pretium, volutpat in et cras, odio consectetuer lacinia risus feugiat sit etiam, commodo pulvinar, dolor non et inventore.</p>
</ion-slide>
<ion-slide class="step-two">
<h1>Heading</h1>
<p>blah, blah</p>
</ion-slide>
<ion-slide class="step-three">
<h1>Heading</h1>
<p>blah, blah</p>
<ion-button (click)="end()">END</ion-button>
</ion-slide>
</ion-slides>
</ion-content>
However, I was expecting the flow of content to be top-to-bottom rather than having the "Welcome" header to the left.
I've looked at the slider layout documentation but I couldn't see how to change the layout to flow vertically down the page.
By inspecting the css in the browser debugger, I figured out that I could change the flex model and by adding the following to my page.scss it appears to fix the problem. Is there a more 'ionic' way to solve this?
.swiper-slide {
flex-direction: column;
}
Apologies if this question is very basic, I'm a data specialist so front end development is not (yet) a strength of mine.
The solution for me was to add the following css:
.swiper-slide {
flex-direction: column;
}

inline tag in haml

In html, you can do something like this
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent eget
aliquet odio. Fusce id quam eu augue sollicitudin imperdiet eu ac eros.
<em>Etiam nec nisi lorem</em>, ac venenatis ipsum. In sollicitudin,
lectus eget varius tincidunt, felis sapien porta eros, non
pellentesque dui quam vitae tellus.
</p>
It is nice, because the paragraph of text still looks like a paragraph in the markup. In haml, it looks like this
%p
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent eget
aliquet odio. Fusce id quam eu augue sollicitudin imperdiet eu ac eros.
%em Etiam nec nisi lorem
, ac venenatis ipsum. In sollicitudin,
lectus eget varius tincidunt, felis sapien porta eros, non
pellentesque dui quam vitae tellus.
Is there any way to totally inline a tag in haml?
Haml excels for structural markup, but it's not really intended for inline markup. Read: Haml Sucks for Content. Just put your inline tags as HTML:
.content
%p
Lorem ipsum <em>dolor</em> sit amet.
Or else use a filter:
.content
:markdown
Lorem ipsum *dolor* sit amet.
I know this is old. But figured I'd post this in case anyone lands here. You can also do this sort of thing in haml (And maybe more what the OP was looking for?).
%p Here is some text I want to #{content_tag(:em, "emphasize!")}, and here the word #{content_tag(:strong, "BOLD")} is in bold. and #{link_to("click here", "url")} for a link.
Useful for those situations where doing it on multiple lines adds spaces you don't want
I.E. When you have a link at the end of a sentence, and don't want that stupid space between the link and the period. (or like in the OP's example, there would be a space between the and the comma.
Just don't get carried away like i did in the example :)
You can inline HTML in any HAML doing
%p!= "Lorem ipsum <em>dolor</em> sit amet"
The != operator means that whatever the right side returns it will be outputted.
As a hybrid of these nice answers by others, I think you can define a Helper method in your application_helper.rb for some inline markups you'd frequently use. You don't need to mix HTML with HAML, nor do you have to type much.
In your helper;
def em(text)
content_tag(:em, text)
end
#def em(text)
# "<em>#{text}</em>".html_safe
#end
In your haml;
%p
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent eget
aliquet odio. Fusce id quam eu augue sollicitudin imperdiet eu ac eros.
#{em 'Etiam nec nisi lorem'}, ac venenatis ipsum. In sollicitudin,
lectus eget varius tincidunt, felis sapien porta eros, non
pellentesque dui quam vitae tellus.
It's all about indentation:
%p
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent eget aliquet odio. Fusce id quam eu augue sollicitudin imperdiet eu ac eros.
%em
Etiam nec nisi lorem, ac venenatis ipsum. In sollicitudin, lectus eget varius tincidunt, felis sapien porta eros, non pellentesque dui quam vitae tellus.