
I have made a simple web app that finds and shows and enabling you to print a random Sadghuru quote fromgoodreads.com with Node.js, Express, Puppeteer and Vue.js. App includes some basic CSS animations also print-friendly. I don't know very well Sadghuru but I see he is a wise person. I love to read his quotes.
Here is my server (Index.js) (Packages: dotenv, cors, express, puppeteer)
require('dotenv').config();// in .env file (PORT=5000)constPORT=process.env.PORT||3000;constexpress=require('express');constcors=require('cors');constpuppeteer=require('puppeteer');constapp=express();app.use(cors());app.use(express.json());app.get('/',async(req,res)=>{constbrowser=awaitpuppeteer.launch();constpage=awaitbrowser.newPage();constrndPage=Math.floor(Math.random()*26)+1;awaitpage.goto(`https://www.goodreads.com/author/quotes/30378.Sadhguru?page=${rndPage}`);constquotes=awaitpage.$$('.quoteText');constrndQuote=Math.floor(Math.random()*(quotes.length-1))+1;constquote=awaitquotes.find((el,index)=>index===rndQuote).evaluate(el=>el.innerText);awaitbrowser.close();returnres.json({quote});});app.listen(PORT,()=>console.log(`Server started on port${PORT}`));
const browser = await puppeteer.launch();
Try this launch({ headless: false }); and browser will show.
There are 26 pages for Sadghuru quotes. page parameter can be random 1 to 26. goodreads.com/author/quotes/30378.Sadhguru?..{rndPage}
// Get all quote div elements.constquotes=awaitpage.$$('.quoteText');// Random number 1-26constrndQuote=Math.floor(Math.random()*(quotes.length-1))+1;// Find a random quote from all quotes in the random page then grab text in the div.constquote=awaitquotes.find((el,index)=>index===rndQuote).evaluate(el=>el.innerText);
Then we close puppeteer browser.(await browser.close()) Then we send the quote as json.(res.json({quote}))
And Frontend
App.vue
<template><divid="app"><h1class="header-text">SadghuruQuotes</h1><QuoteCard:quote="quote":loadingAnim="loading"@onclick="findQuote()"/><button@click="printQuote()"id="printBtn"><spanclass="material-icons">print</span></button></div></template><script>importaxiosfrom'axios';importQuoteCardfrom'./components/QuoteCard.vue';exportdefault{name:'App',components:{QuoteCard},data(){return{quote:null,loading:true,}},mounted(){this.fetchQuote();},methods:{asyncfetchQuote(){this.loading=true;constresult=awaitaxios.get('http://localhost:5000/');this.quote=result.data.quote;this.loading=false;},findQuote:function(){if(!this.loading)this.fetchQuote();},printQuote(){window.print();}}}</script><style>.header-text{text-align:center;margin:2rem02rem0;}#printBtn{position:fixed;right:2rem;bottom:2rem;outline:none;border:0;padding:1rem;border-radius:50%;cursor:pointer;}#printBtn:hover{animation-name:printbtnanim;animation-duration:1s;animation-iteration-count:infinite;}#printBtnspan{font-size:48px;}@keyframesprintbtnanim{0%{transform:scale(1);}50%{transform:scale(1.2);}100%{transform:scale(1);}}@mediaprint{html,body{color:#000;}#printBtn{display:none;}.header-text{display:none;}}</style>
QuoteCard.vue
<template><divclass="quotecard":class="{'quotecard-anim': loadingAnim, 'fadein-anim': !loadingAnim }"@click="onClick()"><p>{{loadingAnim?'Loading...':quote}}</p></div></template><script>exportdefault{name:'QuoteCard',props:{quote:String,loadingAnim:Boolean},methods:{onClick(){this.$emit('onclick');}}}</script><stylescoped>.quotecard{cursor:pointer;width:70vw;max-height:50vh;overflow:auto;padding:2rem;margin:4remauto0auto;border-radius:10px;box-shadow:0055px1pxrgba(0,250,250,0.3);transition:all.5s;text-align:center;font-size:1.4rem;}.quotecard:hover{box-shadow:0055px1pxrgba(0,250,250,0.8);}.quotecard-anim{animation-name:quotecardanim;animation-duration:1s;animation-iteration-count:infinite;}.fadein-anim{animation-name:fadeinanim;animation-duration:2s;}@keyframesquotecardanim{0%{box-shadow:0055px1pxrgba(0,250,250,.1);}50%{box-shadow:0055px1pxrgba(0,250,250,1);}100%{box-shadow:0055px1pxrgba(0,250,250,.1);}}@keyframesfadeinanim{from{opacity:0;}to{opacity:1;}}::-webkit-scrollbar{width:4px;height:4px;}::-webkit-scrollbar-thumb{background:#ADFFFF;border-radius:15px;}::-webkit-scrollbar-thumb:hover{background:#D4D4D4;}::-webkit-scrollbar-track{background:#F0F0F0;border-radius:0px;box-shadow:inset0px0px0px0px#F0F0F0;}@mediaprint{.quotecard{box-shadow:none;width:100%;max-height:none;padding:1cm;margin:0;border:3pxdashed#000;border-radius:0;}.quotecard::after{content:'Sad Ghuru';display:block;margin-top:1cm;text-align:right;font-weight:bold;}}</style>
style.css
@importurl('https://fonts.googleapis.com/css2?family=Architects+Daughter&family=Italianno&display=swap');*{box-sizing:border-box;margin:0;padding:0;}html,body{font-family:'Architects Daughter',cursive;background:rgb(41,41,41)linear-gradient(rgb(41,41,41),rgb(0,0,0))no-repeattopleft;background-size:cover;color:#fff;height:100%;width:100%;overflow:hidden;}h1{font-family:'Architects Daughter',cursive;}
index.html
<!DOCTYPE html><htmllang=""><head><metacharset="utf-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="width=device-width,initial-scale=1.0"><linkrel="icon"href="<%= BASE_URL %>favicon.ico"><linkrel="stylesheet"href="style.css"><linkhref="https://fonts.googleapis.com/icon?family=Material+Icons"rel="stylesheet"><title><%=htmlWebpackPlugin.options.title%></title></head><body><noscript><strong>We're sorry but<%=htmlWebpackPlugin.options.title%> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><divid="app"></div><!-- built files will be auto injected --></body></html>
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse