Compare commits
7 Commits
646cfa6561
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 00851d37b8 | |||
| a55ba6ce2f | |||
| c2e01dd1e8 | |||
| 860c52e829 | |||
| b28e7b2da5 | |||
| 7d6eeb2310 | |||
| 558ac03fbb |
+2
-1
@@ -18,7 +18,8 @@
|
|||||||
"ext-libxml": "*",
|
"ext-libxml": "*",
|
||||||
"donatello-za/rake-php-plus": "^1.0",
|
"donatello-za/rake-php-plus": "^1.0",
|
||||||
"phpmailer/phpmailer": "^6.9",
|
"phpmailer/phpmailer": "^6.9",
|
||||||
"onelogin/php-saml": "^4.1"
|
"onelogin/php-saml": "^4.1",
|
||||||
|
"ext-mbstring": "*"
|
||||||
},
|
},
|
||||||
"repositories": [
|
"repositories": [
|
||||||
{
|
{
|
||||||
|
|||||||
Vendored
+30
-2
@@ -674,7 +674,11 @@ EOD;
|
|||||||
public function changeHTMLSrc(string $body, string $to, string $from): string
|
public function changeHTMLSrc(string $body, string $to, string $from): string
|
||||||
{
|
{
|
||||||
$htmlDoc = new DOMDocument();
|
$htmlDoc = new DOMDocument();
|
||||||
$htmlDoc->loadHTML($body, LIBXML_NOERROR);
|
|
||||||
|
// Load the raw HTML content into DOMDocument
|
||||||
|
@$htmlDoc->loadHTML($body, LIBXML_NOERROR);
|
||||||
|
|
||||||
|
// Get the body and process images
|
||||||
$doc = $htmlDoc->getElementsByTagName('body')->item(0);
|
$doc = $htmlDoc->getElementsByTagName('body')->item(0);
|
||||||
$imgs = $doc->getElementsByTagName('img');
|
$imgs = $doc->getElementsByTagName('img');
|
||||||
|
|
||||||
@@ -687,9 +691,11 @@ EOD;
|
|||||||
$srcList[] = $src;
|
$srcList[] = $src;
|
||||||
$fileName = basename($src);
|
$fileName = basename($src);
|
||||||
|
|
||||||
|
// Update the src attribute to the new location
|
||||||
$img->setAttribute("src", substr($to, 2) . $fileName);
|
$img->setAttribute("src", substr($to, 2) . $fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rename files and clean up old ones
|
||||||
$files = scandir($from);
|
$files = scandir($from);
|
||||||
foreach ($files as $file)
|
foreach ($files as $file)
|
||||||
{
|
{
|
||||||
@@ -705,14 +711,36 @@ EOD;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process the HTML content for output
|
||||||
$newBody = '';
|
$newBody = '';
|
||||||
foreach ($doc->childNodes as $node)
|
foreach ($doc->childNodes as $node)
|
||||||
{
|
{
|
||||||
$newBody .= $htmlDoc->saveHTML($node);
|
// Only convert text nodes to HTML entities
|
||||||
|
if ($node->nodeType === XML_TEXT_NODE)
|
||||||
|
{
|
||||||
|
$newBody .= $this->convertToHtmlEntities($node->nodeValue); // Convert text nodes
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$newBody .= $htmlDoc->saveHTML($node); // Keep HTML tags intact
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $newBody;
|
return $newBody;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert all characters in a string to HTML entities while leaving HTML tags intact.
|
||||||
|
* @param string $text - The text to convert
|
||||||
|
* @return string - The converted text with HTML entities
|
||||||
|
*/
|
||||||
|
private function convertToHtmlEntities(string $text): string
|
||||||
|
{
|
||||||
|
// Convert characters to HTML entities using mb_encode_numericentity
|
||||||
|
return htmlentities($text, ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all posts with the given category
|
* Get all posts with the given category
|
||||||
* @param string $category - Category of the post
|
* @param string $category - Category of the post
|
||||||
|
|||||||
Vendored
+1
-1
@@ -181,7 +181,7 @@ class userRoutes implements routesInterface
|
|||||||
$inactive = 60 * 60 * 48; // 2 days
|
$inactive = 60 * 60 * 48; // 2 days
|
||||||
$_SESSION["timeout"] = time() + $inactive;
|
$_SESSION["timeout"] = time() + $inactive;
|
||||||
|
|
||||||
return $response->withHeader("Location", "https://rohitpai.co.uk/editor/editor.html")->withStatus(302);
|
return $response->withHeader("Location", "https://rohitpai.co.uk/editor/")->withStatus(302);
|
||||||
}
|
}
|
||||||
|
|
||||||
$response->getBody()->write(json_encode(array("error" => "Unauthorised")));
|
$response->getBody()->write(json_encode(array("error" => "Unauthorised")));
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+2
-2
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+2
-2
File diff suppressed because one or more lines are too long
Generated
+1866
-920
File diff suppressed because it is too large
Load Diff
@@ -674,7 +674,11 @@ EOD;
|
|||||||
public function changeHTMLSrc(string $body, string $to, string $from): string
|
public function changeHTMLSrc(string $body, string $to, string $from): string
|
||||||
{
|
{
|
||||||
$htmlDoc = new DOMDocument();
|
$htmlDoc = new DOMDocument();
|
||||||
$htmlDoc->loadHTML($body, LIBXML_NOERROR);
|
|
||||||
|
// Load the raw HTML content into DOMDocument
|
||||||
|
@$htmlDoc->loadHTML($body, LIBXML_NOERROR);
|
||||||
|
|
||||||
|
// Get the body and process images
|
||||||
$doc = $htmlDoc->getElementsByTagName('body')->item(0);
|
$doc = $htmlDoc->getElementsByTagName('body')->item(0);
|
||||||
$imgs = $doc->getElementsByTagName('img');
|
$imgs = $doc->getElementsByTagName('img');
|
||||||
|
|
||||||
@@ -687,9 +691,11 @@ EOD;
|
|||||||
$srcList[] = $src;
|
$srcList[] = $src;
|
||||||
$fileName = basename($src);
|
$fileName = basename($src);
|
||||||
|
|
||||||
|
// Update the src attribute to the new location
|
||||||
$img->setAttribute("src", substr($to, 2) . $fileName);
|
$img->setAttribute("src", substr($to, 2) . $fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rename files and clean up old ones
|
||||||
$files = scandir($from);
|
$files = scandir($from);
|
||||||
foreach ($files as $file)
|
foreach ($files as $file)
|
||||||
{
|
{
|
||||||
@@ -705,14 +711,36 @@ EOD;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process the HTML content for output
|
||||||
$newBody = '';
|
$newBody = '';
|
||||||
foreach ($doc->childNodes as $node)
|
foreach ($doc->childNodes as $node)
|
||||||
{
|
{
|
||||||
$newBody .= $htmlDoc->saveHTML($node);
|
// Only convert text nodes to HTML entities
|
||||||
|
if ($node->nodeType === XML_TEXT_NODE)
|
||||||
|
{
|
||||||
|
$newBody .= $this->convertToHtmlEntities($node->nodeValue); // Convert text nodes
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$newBody .= $htmlDoc->saveHTML($node); // Keep HTML tags intact
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $newBody;
|
return $newBody;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert all characters in a string to HTML entities while leaving HTML tags intact.
|
||||||
|
* @param string $text - The text to convert
|
||||||
|
* @return string - The converted text with HTML entities
|
||||||
|
*/
|
||||||
|
private function convertToHtmlEntities(string $text): string
|
||||||
|
{
|
||||||
|
// Convert characters to HTML entities using mb_encode_numericentity
|
||||||
|
return htmlentities($text, ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all posts with the given category
|
* Get all posts with the given category
|
||||||
* @param string $category - Category of the post
|
* @param string $category - Category of the post
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ class userRoutes implements routesInterface
|
|||||||
$inactive = 60 * 60 * 48; // 2 days
|
$inactive = 60 * 60 * 48; // 2 days
|
||||||
$_SESSION["timeout"] = time() + $inactive;
|
$_SESSION["timeout"] = time() + $inactive;
|
||||||
|
|
||||||
return $response->withHeader("Location", "https://rohitpai.co.uk/editor/editor.html")->withStatus(302);
|
return $response->withHeader("Location", "https://rohitpai.co.uk/editor/")->withStatus(302);
|
||||||
}
|
}
|
||||||
|
|
||||||
$response->getBody()->write(json_encode(array("error" => "Unauthorised")));
|
$response->getBody()->write(json_encode(array("error" => "Unauthorised")));
|
||||||
|
|||||||
@@ -123,3 +123,102 @@ section.largePost .outerContent .postContent a {
|
|||||||
display: table-cell;
|
display: table-cell;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
section#olderPosts {
|
||||||
|
/*max-width: 90%;*/
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts .carousel {
|
||||||
|
position: relative;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts .arrow {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
display: flex;
|
||||||
|
width: 2.5em;
|
||||||
|
height: 2.5em;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
z-index: 1;
|
||||||
|
font-size: 1.625em;
|
||||||
|
color: white;
|
||||||
|
background: var(--mutedBlack);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts .arrow:hover {
|
||||||
|
background: var(--grey);
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts #prev {
|
||||||
|
left: -4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts #next {
|
||||||
|
right: -4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts .carouselOuter {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1em;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts #allCarouselItems {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts #carouselInner {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: stretch;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 1em;
|
||||||
|
transition: transform 0.5s ease-in-out;
|
||||||
|
left: 0;
|
||||||
|
height: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts #carouselInner .cardItem {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
border: 2px solid var(--primaryDefault);
|
||||||
|
-webkit-border-radius: 0.625rem;
|
||||||
|
-moz-border-radius: 0.625rem;
|
||||||
|
border-radius: 0.625rem;
|
||||||
|
width: 30em;
|
||||||
|
height: 40rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts #carouselInner .cardItem img {
|
||||||
|
width: 100%;
|
||||||
|
height: 300px;
|
||||||
|
object-fit: cover;
|
||||||
|
object-position: left;
|
||||||
|
-webkit-border-radius: 0.625rem;
|
||||||
|
-moz-border-radius: 0.625rem;
|
||||||
|
border-radius: 0.625rem;
|
||||||
|
color: #FFFFFF;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts #carouselInner .cardItem .content {
|
||||||
|
height: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
align-items: center;
|
||||||
|
background: #FFFFFF;
|
||||||
|
margin: 0 2em 1.5em;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|||||||
+49
-1
@@ -9,6 +9,12 @@
|
|||||||
@import "home.css";
|
@import "home.css";
|
||||||
@import "category.css";
|
@import "category.css";
|
||||||
|
|
||||||
|
div.menuBar a.link::before, main a.link::before,
|
||||||
|
div.menuBar a.link::after, main a.link::after {
|
||||||
|
margin-top: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Modal Styling */
|
||||||
.policy {
|
.policy {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -72,7 +78,12 @@
|
|||||||
/**** Media Queries *****/
|
/**** Media Queries *****/
|
||||||
|
|
||||||
@media screen and (max-width: 90em) {
|
@media screen and (max-width: 90em) {
|
||||||
|
|
||||||
|
|
||||||
|
section#olderPosts #carouselInner .cardItem {
|
||||||
|
width: 25em;
|
||||||
|
}
|
||||||
|
|
||||||
/***** Individual Blog Posts ***/
|
/***** Individual Blog Posts ***/
|
||||||
|
|
||||||
div.mainContent {
|
div.mainContent {
|
||||||
@@ -124,6 +135,25 @@
|
|||||||
width: 90%;
|
width: 90%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
section#olderPosts .arrow {
|
||||||
|
width: 2em;
|
||||||
|
height: 2em;
|
||||||
|
font-size: 1.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
section#olderPosts #prev {
|
||||||
|
left: -3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts #next {
|
||||||
|
right: -3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts #carouselInner .cardItem {
|
||||||
|
width: 20em;
|
||||||
|
}
|
||||||
|
|
||||||
/***** Individual Blog Posts ***/
|
/***** Individual Blog Posts ***/
|
||||||
section#individualPost {
|
section#individualPost {
|
||||||
flex-direction: column-reverse;
|
flex-direction: column-reverse;
|
||||||
@@ -219,6 +249,24 @@
|
|||||||
max-width: 75%;
|
max-width: 75%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
section#olderPosts .arrow {
|
||||||
|
width: 1.5em;
|
||||||
|
height: 1.5em;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts #prev {
|
||||||
|
left: -1.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts #next {
|
||||||
|
right: -1.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
section#olderPosts #carouselInner .cardItem {
|
||||||
|
width: 15em;
|
||||||
|
}
|
||||||
|
|
||||||
/***** Individual Blog Posts ***/
|
/***** Individual Blog Posts ***/
|
||||||
|
|
||||||
aside.sideContent > div.authorInfo {
|
aside.sideContent > div.authorInfo {
|
||||||
|
|||||||
+198
-2
@@ -41,7 +41,6 @@ function goToURL(url)
|
|||||||
if (url === '/blog' || url === 'blog' || url === '/blog/')
|
if (url === '/blog' || url === 'blog' || url === '/blog/')
|
||||||
{
|
{
|
||||||
loadHomeContent();
|
loadHomeContent();
|
||||||
// window.history.pushState(null, null, url);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,6 +161,10 @@ function submitNewsletter()
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* unsubscribe by email
|
||||||
|
* @param email the email to unsubscribe
|
||||||
|
*/
|
||||||
function unsubscribe(email)
|
function unsubscribe(email)
|
||||||
{
|
{
|
||||||
fetch(`/api/blog/newsletter/${email}`, {
|
fetch(`/api/blog/newsletter/${email}`, {
|
||||||
@@ -243,6 +246,32 @@ function createLargePost(post)
|
|||||||
return outerContent;
|
return outerContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a card post element
|
||||||
|
* @param post the object
|
||||||
|
* @returns {HTMLDivElement} the outer content of the post
|
||||||
|
*/
|
||||||
|
function createCardPost(post)
|
||||||
|
{
|
||||||
|
let cardItem = document.createElement('div');
|
||||||
|
cardItem.classList.add('cardItem');
|
||||||
|
cardItem.id = 'post' + post.ID;
|
||||||
|
let img = document.createElement('img');
|
||||||
|
img.className = 'cardImg';
|
||||||
|
img.src = post.headerImg.replaceAll('%2F', '/');
|
||||||
|
img.alt = post.title;
|
||||||
|
cardItem.appendChild(img);
|
||||||
|
let content = document.createElement('div');
|
||||||
|
content.classList.add('content');
|
||||||
|
content.innerHTML = `
|
||||||
|
<h2>${post.title}</h2>
|
||||||
|
<h3>Last updated: ${createFormattedDate(post.dateModified)}</h3>
|
||||||
|
<a href="/blog/post/${post.title}" class="btn btnPrimary">See Post</a>
|
||||||
|
`;
|
||||||
|
cardItem.appendChild(content);
|
||||||
|
return cardItem;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the home content
|
* Loads the home content
|
||||||
*/
|
*/
|
||||||
@@ -250,6 +279,30 @@ function loadHomeContent()
|
|||||||
{
|
{
|
||||||
fetch('/api/blog/post').then(res => res.json().then(json =>
|
fetch('/api/blog/post').then(res => res.json().then(json =>
|
||||||
{
|
{
|
||||||
|
// older posts outside the carousel and loop
|
||||||
|
let olderPosts = document.createElement('section');
|
||||||
|
olderPosts.classList.add('largePost');
|
||||||
|
olderPosts.id = 'olderPosts';
|
||||||
|
let h1 = document.createElement('h1');
|
||||||
|
h1.innerHTML = 'older posts';
|
||||||
|
olderPosts.appendChild(h1);
|
||||||
|
|
||||||
|
let carousel = document.createElement('div');
|
||||||
|
carousel.classList.add('carousel');
|
||||||
|
carousel.innerHTML += `<div class="arrow" id="prev"><i class="fa-solid fa-chevron-left"></i></div>
|
||||||
|
<div class="arrow" id="next"><i class="fa-solid fa-chevron-right"></i></div>
|
||||||
|
`;
|
||||||
|
let carouselOuter = document.createElement('div');
|
||||||
|
let carouselInner = document.createElement('div');
|
||||||
|
let allCarouselItems = document.createElement('div');
|
||||||
|
carouselOuter.classList.add('carouselOuter');
|
||||||
|
carouselInner.id = 'carouselInner';
|
||||||
|
allCarouselItems.id = 'allCarouselItems';
|
||||||
|
carouselOuter.appendChild(allCarouselItems);
|
||||||
|
carouselOuter.appendChild(carouselInner);
|
||||||
|
carousel.appendChild(carouselOuter);
|
||||||
|
olderPosts.appendChild(carousel);
|
||||||
|
|
||||||
for (let i = 0; i < json.length; i++)
|
for (let i = 0; i < json.length; i++)
|
||||||
{
|
{
|
||||||
if (json[i].featured === 1)
|
if (json[i].featured === 1)
|
||||||
@@ -278,10 +331,150 @@ function loadHomeContent()
|
|||||||
document.querySelector('#main').appendChild(latestPost);
|
document.querySelector('#main').appendChild(latestPost);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (i > 1)
|
||||||
|
{
|
||||||
|
allCarouselItems.appendChild(createCardPost(json[i]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
document.querySelector('#main').appendChild(olderPosts);
|
||||||
|
//carousel loop
|
||||||
|
carouselLoop(carouselInner, allCarouselItems);
|
||||||
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the loop for the carousel
|
||||||
|
* @param {HTMLDivElement} carouselInner
|
||||||
|
* @param {HTMLDivElement} allItems
|
||||||
|
*/
|
||||||
|
function carouselLoop(carouselInner, allItems)
|
||||||
|
{
|
||||||
|
const prev = document.querySelector('#prev');
|
||||||
|
const next = document.querySelector('#next');
|
||||||
|
const mediaBig = window.matchMedia('(max-width: 75em)');
|
||||||
|
const mediaSmall = window.matchMedia('(max-width: 30em)');
|
||||||
|
let cards = document.querySelectorAll('#allCarouselItems .cardItem');
|
||||||
|
let visibleCardsCount = 3;
|
||||||
|
|
||||||
|
if (mediaBig.matches)
|
||||||
|
{
|
||||||
|
visibleCardsCount = 2; // only show 2 cards if on a slightly smaller screen e.g. tablet/laptop
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mediaSmall.matches)
|
||||||
|
{
|
||||||
|
visibleCardsCount = 1; // only show 1 card if on a mobile, although it'll only work on portrait
|
||||||
|
}
|
||||||
|
|
||||||
|
let visibleCards = [];
|
||||||
|
|
||||||
|
// put the first n (3, 2, or 1) cards in the carousel
|
||||||
|
for (let i = 0; i < visibleCardsCount; i++)
|
||||||
|
{
|
||||||
|
carouselInner.appendChild(cards[i]);
|
||||||
|
visibleCards.push(cards[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allItems.children.length === 0)
|
||||||
|
{
|
||||||
|
// if there are no cards in the carousel, don't show the arrows
|
||||||
|
prev.style.visibility = 'hidden';
|
||||||
|
next.style.visibility = 'hidden';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
next.addEventListener('click', () =>
|
||||||
|
{
|
||||||
|
const firstCard = visibleCards.shift();
|
||||||
|
firstCard.style.visibility = 'hidden'; // hide the first card
|
||||||
|
|
||||||
|
// add the next card to the end and off the screen
|
||||||
|
const nextCard = allItems.querySelector('.cardItem');
|
||||||
|
nextCard.style.transform = 'translateX(100%)';
|
||||||
|
nextCard.style.transition = 'none';
|
||||||
|
carouselInner.appendChild(nextCard);
|
||||||
|
visibleCards.push(nextCard);
|
||||||
|
|
||||||
|
// transition all the cards to the left after 50ms
|
||||||
|
// i.e. after the next card is added hence the setTimeout
|
||||||
|
setTimeout(() =>
|
||||||
|
{
|
||||||
|
// move all the cards to the left
|
||||||
|
for (let i = 0; i < carouselInner.children.length; i++)
|
||||||
|
{
|
||||||
|
carouselInner.children[i].style.transition = 'transform 0.5s ease-out';
|
||||||
|
carouselInner.children[i].style.transform = 'translateX(-100%)';
|
||||||
|
}
|
||||||
|
}, 50);
|
||||||
|
|
||||||
|
// after 500ms move all cards back to the center and move
|
||||||
|
// the first card to the hidden div
|
||||||
|
setTimeout(() =>
|
||||||
|
{
|
||||||
|
// move the first card back to the center
|
||||||
|
// instantly and move it to the hidden div
|
||||||
|
firstCard.style.transition = 'none';
|
||||||
|
firstCard.style.transform = 'translateX(0)';
|
||||||
|
allItems.appendChild(firstCard);
|
||||||
|
firstCard.style.visibility = 'visible'; // make it visible again
|
||||||
|
|
||||||
|
// for the remaining cards, reset them
|
||||||
|
for (let i = 0; i < carouselInner.children.length; i++)
|
||||||
|
{
|
||||||
|
carouselInner.children[i].style.transition = 'none';
|
||||||
|
carouselInner.children[i].style.transform = 'translateX(0%)';
|
||||||
|
}
|
||||||
|
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
|
||||||
|
// everything is done in reverse
|
||||||
|
prev.addEventListener('click', () =>
|
||||||
|
{
|
||||||
|
const lastCard = visibleCards.pop();
|
||||||
|
lastCard.style.visibility = 'hidden'; // hide the last card
|
||||||
|
|
||||||
|
// add the previous card to the beginning and off the screen
|
||||||
|
const prevCard = allItems.querySelector('.cardItem:last-child');
|
||||||
|
prevCard.style.transform = 'translateX(-100%)';
|
||||||
|
prevCard.style.transition = 'none';
|
||||||
|
carouselInner.insertBefore(prevCard, carouselInner.firstChild);
|
||||||
|
visibleCards.unshift(prevCard);
|
||||||
|
|
||||||
|
// transition all the cards to the right after 50ms
|
||||||
|
// i.e. after the previous card is added hence the setTimeout
|
||||||
|
setTimeout(() =>
|
||||||
|
{
|
||||||
|
// move all the cards to the right
|
||||||
|
for (let i = 0; i < carouselInner.children.length; i++)
|
||||||
|
{
|
||||||
|
carouselInner.children[i].style.transition = 'transform 0.5s ease-out';
|
||||||
|
carouselInner.children[i].style.transform = 'translateX(100%)';
|
||||||
|
}
|
||||||
|
}, 50);
|
||||||
|
|
||||||
|
// after 500ms move all cards back to the center and move
|
||||||
|
// the last card to the hidden div
|
||||||
|
setTimeout(() =>
|
||||||
|
{
|
||||||
|
// move the last card back to the center
|
||||||
|
// instantly and move it to the hidden div
|
||||||
|
lastCard.style.transition = 'none';
|
||||||
|
lastCard.style.transform = 'translateX(0)';
|
||||||
|
allItems.insertBefore(lastCard, allItems.firstChild);
|
||||||
|
lastCard.style.visibility = 'visible';
|
||||||
|
|
||||||
|
// for the remaining cards reset them
|
||||||
|
for (let i = 0; i < carouselInner.children.length; i++)
|
||||||
|
{
|
||||||
|
carouselInner.children[i].style.transition = 'none';
|
||||||
|
carouselInner.children[i].style.transform = 'translateX(0%)';
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the latest and featured posts
|
* Gets the latest and featured posts
|
||||||
* @returns {Promise<any[]>} the latest and featured posts
|
* @returns {Promise<any[]>} the latest and featured posts
|
||||||
@@ -390,7 +583,7 @@ async function createSideContent()
|
|||||||
<div class="authorInfo">
|
<div class="authorInfo">
|
||||||
<div class="picture">
|
<div class="picture">
|
||||||
<img src="/imgs/profile.jpg"
|
<img src="/imgs/profile.jpg"
|
||||||
alt="My professional picture taken in brighton near
|
alt="My professional picture taken in brighton near
|
||||||
north street at night wearing a beige jacket and checkered shirt"
|
north street at night wearing a beige jacket and checkered shirt"
|
||||||
class="profile">
|
class="profile">
|
||||||
<p>Rohit Pai</p>
|
<p>Rohit Pai</p>
|
||||||
@@ -848,6 +1041,9 @@ function loadPrivacyPolicy()
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the cookie policy
|
||||||
|
*/
|
||||||
function loadCookiePolicy()
|
function loadCookiePolicy()
|
||||||
{
|
{
|
||||||
document.querySelector('#main').innerHTML = `
|
document.querySelector('#main').innerHTML = `
|
||||||
|
|||||||
Vendored
+2
-2
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -876,7 +876,7 @@ function createEditors(...ids)
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
`<iframe width="560" height="315" style="text-align:center;" src="https://www.youtube.com/embed/${id}${time ? `?start=${time}` : ''}" ` +
|
`<iframe width="560" height="315" style="text-align:center;" src="https://www.youtube.com/embed/${id}${time ? `?start=${time}` : ''}" ` +
|
||||||
'frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen>' +
|
'allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen>' +
|
||||||
'</iframe>'
|
'</iframe>'
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -1229,8 +1229,8 @@ function updateProjectItem(id, e)
|
|||||||
data['gitLink'] = document.querySelector(`#git${id}proj`).value;
|
data['gitLink'] = document.querySelector(`#git${id}proj`).value;
|
||||||
|
|
||||||
let imgData = new FormData();
|
let imgData = new FormData();
|
||||||
imgData.append("img", document.querySelector(`#img${id}`).files[0]);
|
imgData.append('img', document.querySelector(`#img${id}proj`).files[0]);
|
||||||
|
|
||||||
fetch("/api/projectData/" + id, {
|
fetch("/api/projectData/" + id, {
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
@@ -1254,8 +1254,8 @@ function updateProjectItem(id, e)
|
|||||||
}
|
}
|
||||||
|
|
||||||
document.querySelector(`#projectItem${id}`).classList.toggle("editing");
|
document.querySelector(`#projectItem${id}`).classList.toggle("editing");
|
||||||
document.querySelector(`#title${id}`).setAttribute("disabled", "");
|
document.querySelector(`#title${id}proj`).setAttribute('disabled', '');
|
||||||
document.querySelector(`#info${id}`).setAttribute("disabled", "");
|
document.querySelector(`#info${id}proj`).setAttribute('disabled', '');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log("updating image")
|
console.log("updating image")
|
||||||
@@ -1293,8 +1293,8 @@ function updateProjectItem(id, e)
|
|||||||
}
|
}
|
||||||
|
|
||||||
document.querySelector(`#projectItem${id}`).classList.toggle("editing");
|
document.querySelector(`#projectItem${id}`).classList.toggle("editing");
|
||||||
document.querySelector(`#title${id}`).setAttribute("disabled", "");
|
document.querySelector(`#title${id}proj`).setAttribute('disabled', '');
|
||||||
document.querySelector(`#info${id}`).setAttribute("disabled", "");
|
document.querySelector(`#info${id}proj`).setAttribute('disabled', '');
|
||||||
document.querySelector(`#projectImage${id}`).src = updatedProjectImage.imgLocation;
|
document.querySelector(`#projectImage${id}`).src = updatedProjectImage.imgLocation;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-9
@@ -32,6 +32,7 @@
|
|||||||
<li><a href="/blog" class="textShadow link">blog</a></li>
|
<li><a href="/blog" class="textShadow link">blog</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<header>
|
<header>
|
||||||
<div>
|
<div>
|
||||||
<h1>full stack developer</h1>
|
<h1>full stack developer</h1>
|
||||||
@@ -108,7 +109,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="#">
|
<a href="https://rohitpai.co.uk/blog">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||||
<path d="M15.5 14.625c0 .484-.387.875-.864.875h-5.273c-.477 0-.863-.392-.863-.875s.387-.875.863-.875h5.272c.478 0 .865.391.865.875zm-6.191-4.375h2.466c.448 0 .809-.392.809-.875s-.361-.875-.81-.875h-2.465c-.447 0-.809.392-.809.875s.362.875.809.875zm14.691 1.75c0 6.627-5.373 12-12 12s-12-5.373-12-12 5.373-12 12-12 12 5.373 12 12zm-5-1.039c0-.383-.311-.692-.691-.692h-1.138c-.583 0-.69-.446-.69-.996-.001-2.36-1.91-4.273-4.265-4.273h-2.952c-2.355 0-4.264 1.913-4.264 4.272v5.455c0 2.36 1.909 4.273 4.264 4.273h5.474c2.353 0 4.262-1.913 4.262-4.272v-3.767z"/>
|
<path d="M15.5 14.625c0 .484-.387.875-.864.875h-5.273c-.477 0-.863-.392-.863-.875s.387-.875.863-.875h5.272c.478 0 .865.391.865.875zm-6.191-4.375h2.466c.448 0 .809-.392.809-.875s-.361-.875-.81-.875h-2.465c-.447 0-.809.392-.809.875s.362.875.809.875zm14.691 1.75c0 6.627-5.373 12-12 12s-12-5.373-12-12 5.373-12 12-12 12 5.373 12 12zm-5-1.039c0-.383-.311-.692-.691-.692h-1.138c-.583 0-.69-.446-.69-.996-.001-2.36-1.91-4.273-4.265-4.273h-2.952c-2.355 0-4.264 1.913-4.264 4.272v5.455c0 2.36 1.909 4.273 4.264 4.273h5.474c2.353 0 4.262-1.913 4.262-4.272v-3.767z"/>
|
||||||
</svg>
|
</svg>
|
||||||
@@ -173,15 +174,16 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<footer class="flexRow">
|
|
||||||
<div class="spacer"></div>
|
|
||||||
<p>© <span id="year"></span> Rohit Pai all rights reserved</p>
|
|
||||||
<div class="button">
|
|
||||||
<button id="goBackToTop"><i class="fa-solid fa-chevron-up"></i></button>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
<footer class="flexRow">
|
||||||
|
<div class="spacer"></div>
|
||||||
|
<p>© <span id="year"></span> Rohit Pai all rights reserved</p>
|
||||||
|
<div class="button">
|
||||||
|
<button id="goBackToTop"><i class="fa-solid fa-chevron-up"></i></button>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
<script src="js/index.js"></script>
|
<script src="js/index.js"></script>
|
||||||
<script src="js/typewriter.js"></script>
|
<script src="js/typewriter.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
Reference in New Issue
Block a user