Compare commits
9 Commits
7f96aa9277
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 00851d37b8 | |||
| a55ba6ce2f | |||
| c2e01dd1e8 | |||
| 860c52e829 | |||
| b28e7b2da5 | |||
| 7d6eeb2310 | |||
| 558ac03fbb | |||
| 646cfa6561 | |||
| 591db4dfa3 |
+2
-1
@@ -18,7 +18,8 @@
|
||||
"ext-libxml": "*",
|
||||
"donatello-za/rake-php-plus": "^1.0",
|
||||
"phpmailer/phpmailer": "^6.9",
|
||||
"onelogin/php-saml": "^4.1"
|
||||
"onelogin/php-saml": "^4.1",
|
||||
"ext-mbstring": "*"
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
|
||||
Vendored
+30
-2
@@ -674,7 +674,11 @@ EOD;
|
||||
public function changeHTMLSrc(string $body, string $to, string $from): string
|
||||
{
|
||||
$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);
|
||||
$imgs = $doc->getElementsByTagName('img');
|
||||
|
||||
@@ -687,9 +691,11 @@ EOD;
|
||||
$srcList[] = $src;
|
||||
$fileName = basename($src);
|
||||
|
||||
// Update the src attribute to the new location
|
||||
$img->setAttribute("src", substr($to, 2) . $fileName);
|
||||
}
|
||||
|
||||
// Rename files and clean up old ones
|
||||
$files = scandir($from);
|
||||
foreach ($files as $file)
|
||||
{
|
||||
@@ -705,14 +711,36 @@ EOD;
|
||||
}
|
||||
}
|
||||
|
||||
// Process the HTML content for output
|
||||
$newBody = '';
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param string $category - Category of the post
|
||||
|
||||
Vendored
-138
@@ -1,138 +0,0 @@
|
||||
<?php
|
||||
namespace api\user;
|
||||
use Firebase\JWT\JWT;
|
||||
use PDO;
|
||||
|
||||
require_once __DIR__ . "/../utils/config.php";
|
||||
|
||||
/**
|
||||
* User Class
|
||||
* Define all functions which either check, update or delete user data
|
||||
*/
|
||||
class user
|
||||
{
|
||||
/**
|
||||
* Check if user exists and can be logged in
|
||||
* @param $username string - Username
|
||||
* @param $password string - Password
|
||||
* @return bool - True if logged in, false if not
|
||||
*/
|
||||
function checkUser(string $username, string $password): bool
|
||||
{
|
||||
$conn = dbConn();
|
||||
$stmt = $conn->prepare("SELECT * FROM users WHERE username = :username");
|
||||
$stmt->bindParam(":username", $username);
|
||||
$stmt->execute();
|
||||
|
||||
// set the resulting array to associative
|
||||
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($result)
|
||||
{
|
||||
if (password_verify($password, $result[0]["password"]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a JWT token
|
||||
* @param $username string - Username
|
||||
* @return string - JWT token
|
||||
*/
|
||||
function createToken(string $username): string
|
||||
{
|
||||
$now = time();
|
||||
$future = strtotime('+6 hour',$now);
|
||||
$secretKey = getSecretKey();
|
||||
$payload = [
|
||||
"jti"=>$username,
|
||||
"iat"=>$now,
|
||||
"exp"=>$future
|
||||
];
|
||||
|
||||
return JWT::encode($payload,$secretKey,"HS256");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if email is already in use
|
||||
* @param string $email - Email to check
|
||||
* @return bool - True if email exists, false if not
|
||||
*/
|
||||
function checkEmail(string $email): bool
|
||||
{
|
||||
$conn = dbConn();
|
||||
$stmt = $conn->prepare("SELECT * FROM users WHERE email = :email");
|
||||
$stmt->bindParam(":email", $email);
|
||||
$stmt->execute();
|
||||
|
||||
// set the resulting array to associative
|
||||
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($result)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a verification email to the user
|
||||
* @param $email - email address of the user
|
||||
* @return string - verification code
|
||||
*/
|
||||
function sendResetEmail($email): string
|
||||
{
|
||||
//generate a random token and email the address
|
||||
$token = uniqid("rpe-");
|
||||
$headers1 = "From: noreply@rohitpai.co.uk\r\n";
|
||||
$headers1 .= "MIME-Version: 1.0\r\n";
|
||||
$headers1 .= "Content-Type: text/html; charset=UTF-8\r\n";
|
||||
|
||||
$message = "
|
||||
<!doctype html>
|
||||
<html lang='en'>
|
||||
<head>
|
||||
<meta charset='UTF-8'>
|
||||
<meta name='viewport' content='width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0'>
|
||||
<meta http-equiv='X-UA-Compatible' content='ie=edge'>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Reset Password Verification Code</h1>
|
||||
<br>
|
||||
<p>Please enter the following code to reset your password: $token</p>
|
||||
</body>
|
||||
</html>
|
||||
";
|
||||
|
||||
mail($email, "Reset Password Verification Code", $message, $headers1);
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change password for an email with new password
|
||||
* @param $email string Email
|
||||
* @param $password string Password
|
||||
* @return bool - true if the password was changed, false if not
|
||||
*/
|
||||
function changePassword(string $email, string $password): bool
|
||||
{
|
||||
$conn = dbConn();
|
||||
$stmt = $conn->prepare("UPDATE users SET password = :password WHERE email = :email");
|
||||
$newPwd = password_hash($password, PASSWORD_BCRYPT);
|
||||
$stmt->bindParam(":password", $newPwd);
|
||||
$stmt->bindParam(":email", $email);
|
||||
|
||||
if ($stmt->execute())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Vendored
+3
-3
@@ -17,7 +17,7 @@ class userRoutes implements routesInterface
|
||||
private Auth $samlAuth;
|
||||
|
||||
/**
|
||||
* constructor used to instantiate a base user routes, to be used in the index.php file.
|
||||
* constructor used to instantiate base user routes, to be used in the index.php file.
|
||||
* @param App $app - the slim app used to create the routes
|
||||
* @throws Error
|
||||
*/
|
||||
@@ -181,7 +181,7 @@ class userRoutes implements routesInterface
|
||||
$inactive = 60 * 60 * 48; // 2 days
|
||||
$_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")));
|
||||
@@ -214,4 +214,4 @@ class userRoutes implements routesInterface
|
||||
return $response->withStatus(500);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
-142
@@ -1,142 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace api\user;
|
||||
|
||||
use Firebase\JWT\JWT;
|
||||
use PDO;
|
||||
use function api\utils\dbConn;
|
||||
use function api\utils\getSecretKey;
|
||||
|
||||
require_once __DIR__ . "/../utils/config.php";
|
||||
|
||||
/**
|
||||
* User Class
|
||||
* Define all functions which either check, update or delete userData data
|
||||
*/
|
||||
class userData
|
||||
{
|
||||
/**
|
||||
* Check if userData exists and can be logged in
|
||||
* @param $username string - Username
|
||||
* @param $password string - Password
|
||||
* @return bool - True if logged in, false if not
|
||||
*/
|
||||
public function checkUser(string $username, string $password): bool
|
||||
{
|
||||
$conn = dbConn();
|
||||
$stmt = $conn->prepare("SELECT * FROM users WHERE username = :username");
|
||||
$stmt->bindParam(":username", $username);
|
||||
$stmt->execute();
|
||||
|
||||
// set the resulting array to associative
|
||||
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($result)
|
||||
{
|
||||
if (password_verify($password, $result[0]["password"]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a JWT token
|
||||
* @param $username string - Username
|
||||
* @return string - JWT token
|
||||
*/
|
||||
public function createToken(string $username): string
|
||||
{
|
||||
$now = time();
|
||||
$future = strtotime('+2 day', $now);
|
||||
$secretKey = getSecretKey();
|
||||
$payload = [
|
||||
"jti" => $username,
|
||||
"iat" => $now,
|
||||
"exp" => $future
|
||||
];
|
||||
|
||||
return JWT::encode($payload, $secretKey, "HS256");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if email is already in use
|
||||
* @param string $email - Email to check
|
||||
* @return bool - True if email exists, false if not
|
||||
*/
|
||||
public function checkEmail(string $email): bool
|
||||
{
|
||||
$conn = dbConn();
|
||||
$stmt = $conn->prepare("SELECT * FROM users WHERE email = :email");
|
||||
$stmt->bindParam(":email", $email);
|
||||
$stmt->execute();
|
||||
|
||||
// set the resulting array to associative
|
||||
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($result)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a verification email to the userData
|
||||
* @param $email - email address of the userData
|
||||
* @return string - verification code
|
||||
*/
|
||||
public function sendResetEmail($email): string
|
||||
{
|
||||
//generate a random token and email the address
|
||||
$token = uniqid("rpe-");
|
||||
$headers1 = "From: noreply@rohitpai.co.uk\r\n";
|
||||
$headers1 .= "MIME-Version: 1.0\r\n";
|
||||
$headers1 .= "Content-Type: text/html; charset=UTF-8\r\n";
|
||||
|
||||
$message = "
|
||||
<!doctype html>
|
||||
<html lang='en'>
|
||||
<head>
|
||||
<meta charset='UTF-8'>
|
||||
<meta name='viewport' content='width=device-width, userData-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0'>
|
||||
<meta http-equiv='X-UA-Compatible' content='ie=edge'>
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Reset Password Verification Code</h1>
|
||||
<br>
|
||||
<p>Please enter the following code to reset your password: $token</p>
|
||||
</body>
|
||||
</html>
|
||||
";
|
||||
|
||||
mail($email, "Reset Password Verification Code", $message, $headers1);
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change password for an email with new password
|
||||
* @param $email string Email
|
||||
* @param $password string Password
|
||||
* @return bool - true if the password was changed, false if not
|
||||
*/
|
||||
public function changePassword(string $email, string $password): bool
|
||||
{
|
||||
$conn = dbConn();
|
||||
$stmt = $conn->prepare("UPDATE users SET password = :password WHERE email = :email");
|
||||
$newPwd = password_hash($password, PASSWORD_BCRYPT);
|
||||
$stmt->bindParam(":password", $newPwd);
|
||||
$stmt->bindParam(":email", $email);
|
||||
|
||||
if ($stmt->execute())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Vendored
-168
@@ -1,168 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace api\user;
|
||||
require_once __DIR__ . "/../utils/routesInterface.php";
|
||||
require_once "userData.php";
|
||||
|
||||
use api\utils\routesInterface;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Slim\App;
|
||||
|
||||
class userRoutes implements routesInterface
|
||||
{
|
||||
private userData $user;
|
||||
|
||||
/**
|
||||
* constructor used to instantiate a base user routes, to be used in the index.php file.
|
||||
* @param App $app - the slim app used to create the routes
|
||||
*/
|
||||
public function __construct(App $app)
|
||||
{
|
||||
$this->user = new userData();
|
||||
$this->createRoutes($app);
|
||||
}
|
||||
|
||||
/**
|
||||
* creates the routes for the user
|
||||
* @param App $app - the slim app used to create the routes
|
||||
* @return void - returns nothing
|
||||
*/
|
||||
public function createRoutes(App $app): void
|
||||
{
|
||||
$app->post("/user/login", function (Request $request, Response $response)
|
||||
{
|
||||
// get request data
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
if (empty($data["username"]) || empty($data["password"]))
|
||||
{
|
||||
// uh oh user sent empty data
|
||||
return $response->withStatus(400);
|
||||
}
|
||||
|
||||
if ($this->user->checkUser($data["username"], $data["password"]))
|
||||
{
|
||||
// yay, user is logged in
|
||||
$_SESSION["token"] = $this->user->createToken($data["username"]);
|
||||
$_SESSION["username"] = $data["username"];
|
||||
|
||||
$inactive = 60 * 60 * 48; // 2 days
|
||||
$_SESSION["timeout"] = time() + $inactive;
|
||||
|
||||
$response->getBody()->write(json_encode(array("token" => $_SESSION["token"])));
|
||||
return $response;
|
||||
}
|
||||
$response->getBody()->write(json_encode(array("error" => "Unauthorised")));
|
||||
return $response->withStatus(401);
|
||||
});
|
||||
|
||||
$app->get("/user/logout", function (Request $request, Response $response)
|
||||
{
|
||||
session_unset();
|
||||
return $response;
|
||||
});
|
||||
|
||||
$app->get("/user/isLoggedIn", function (Request $request, Response $response)
|
||||
{
|
||||
if (empty($_SESSION["token"]) && empty($_SESSION["username"]))
|
||||
{
|
||||
// uh oh user not logged in
|
||||
return $response->withStatus(401);
|
||||
}
|
||||
|
||||
$inactive = 60 * 60 * 48; // 2 days
|
||||
$sessionLife = time() - $_SESSION["timeout"];
|
||||
if ($sessionLife > $inactive)
|
||||
{
|
||||
// uh oh user session expired
|
||||
session_destroy();
|
||||
return $response->withStatus(401);
|
||||
}
|
||||
|
||||
if (empty($_SESSION["token"]))
|
||||
{
|
||||
// user is logged in but no token was created
|
||||
$_SESSION["token"] = $this->user->createToken($_SESSION["username"]);
|
||||
return $response->withStatus(201);
|
||||
}
|
||||
|
||||
$response->getBody()->write(json_encode(array("token" => $_SESSION["token"])));
|
||||
return $response;
|
||||
|
||||
});
|
||||
|
||||
$app->get("/user/checkResetEmail/{email}", function (Request $request, Response $response, array $args)
|
||||
{
|
||||
if (empty($args["email"]))
|
||||
{
|
||||
// uh oh sent empty data
|
||||
return $response->withStatus(400);
|
||||
}
|
||||
|
||||
if ($this->user->checkEmail($args["email"]))
|
||||
{
|
||||
// yay email does exist
|
||||
$_SESSION["resetToken"] = $this->user->sendResetEmail($args["email"]);
|
||||
$_SESSION["resetEmail"] = $args["email"];
|
||||
return $response;
|
||||
}
|
||||
return $response->withStatus(404);
|
||||
});
|
||||
|
||||
$app->get("/user/resendEmail", function (Request $request, Response $response)
|
||||
{
|
||||
if (empty($_SESSION["resetToken"]))
|
||||
{
|
||||
// uh oh not authorized to resend email
|
||||
return $response->withStatus(401);
|
||||
}
|
||||
|
||||
$_SESSION["resetToken"] = $this->user->sendResetEmail($_SESSION["resetEmail"]);
|
||||
return $response;
|
||||
});
|
||||
|
||||
$app->get("/user/checkResetCode/{code}", function (Request $request, Response $response, array $args)
|
||||
{
|
||||
if (empty($args["code"]))
|
||||
{
|
||||
// uh oh sent empty data
|
||||
return $response->withStatus(400);
|
||||
}
|
||||
|
||||
if ($_SESSION["resetToken"] === $args["code"])
|
||||
{
|
||||
// yay, code code matches
|
||||
return $response;
|
||||
}
|
||||
|
||||
return $response->withStatus(401);
|
||||
});
|
||||
|
||||
$app->post("/user/changePassword", function (Request $request, Response $response)
|
||||
{
|
||||
if (empty($_SESSION["resetToken"]) && empty($_SESSION["resetEmail"]))
|
||||
{
|
||||
// uh oh not authorized to change password
|
||||
return $response->withStatus(401);
|
||||
}
|
||||
|
||||
$data = $request->getParsedBody();
|
||||
if (empty($data["password"]))
|
||||
{
|
||||
// uh oh sent empty data
|
||||
return $response->withStatus(400);
|
||||
}
|
||||
|
||||
if ($this->user->changePassword($_SESSION["resetEmail"], $data["password"]))
|
||||
{
|
||||
// yay, password changed
|
||||
unset($_SESSION["resetToken"]);
|
||||
unset($_SESSION["resetEmail"]);
|
||||
return $response->withStatus(201);
|
||||
}
|
||||
|
||||
return $response->withStatus(500);
|
||||
});
|
||||
}
|
||||
}
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
/* PrismJS 1.29.0
|
||||
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+abap+abnf+actionscript+ada+agda+al+antlr4+apacheconf+apex+apl+applescript+aql+arduino+arff+armasm+arturo+asciidoc+aspnet+asm6502+asmatmel+autohotkey+autoit+avisynth+avro-idl+awk+bash+basic+batch+bbcode+bbj+bicep+birb+bison+bnf+bqn+brainfuck+brightscript+bro+bsl+c+csharp+cpp+cfscript+chaiscript+cil+cilkc+cilkcpp+clojure+cmake+cobol+coffeescript+concurnas+csp+cooklang+coq+crystal+css-extras+csv+cue+cypher+d+dart+dataweave+dax+dhall+diff+django+dns-zone-file+docker+dot+ebnf+editorconfig+eiffel+ejs+elixir+elm+etlua+erb+erlang+excel-formula+fsharp+factor+false+firestore-security-rules+flow+fortran+ftl+gml+gap+gcode+gdscript+gedcom+gettext+gherkin+git+glsl+gn+linker-script+go+go-module+gradle+graphql+groovy+haml+handlebars+haskell+haxe+hcl+hlsl+hoon+http+hpkp+hsts+ichigojam+icon+icu-message-format+idris+ignore+inform7+ini+io+j+java+javadoc+javadoclike+javastacktrace+jexl+jolie+jq+jsdoc+js-extras+json+json5+jsonp+jsstacktrace+js-templates+julia+keepalived+keyman+kotlin+kumir+kusto+latex+latte+less+lilypond+liquid+lisp+livescript+llvm+log+lolcode+lua+magma+makefile+markdown+markup-templating+mata+matlab+maxscript+mel+mermaid+metafont+mizar+mongodb+monkey+moonscript+n1ql+n4js+nand2tetris-hdl+naniscript+nasm+neon+nevod+nginx+nim+nix+nsis+objectivec+ocaml+odin+opencl+openqasm+oz+parigp+parser+pascal+pascaligo+psl+pcaxis+peoplecode+perl+php+phpdoc+php-extras+plant-uml+plsql+powerquery+powershell+processing+prolog+promql+properties+protobuf+pug+puppet+pure+purebasic+purescript+python+qsharp+q+qml+qore+r+racket+cshtml+jsx+tsx+reason+regex+rego+renpy+rescript+rest+rip+roboconf+robotframework+ruby+rust+sas+sass+scss+scala+scheme+shell-session+smali+smalltalk+smarty+sml+solidity+solution-file+soy+sparql+splunk-spl+sqf+sql+squirrel+stan+stata+iecst+stylus+supercollider+swift+systemd+t4-templating+t4-cs+t4-vb+tap+tcl+tt2+textile+toml+tremor+turtle+twig+typescript+typoscript+unrealscript+uorazor+uri+v+vala+vbnet+velocity+verilog+vhdl+vim+visual-basic+warpscript+wasm+web-idl+wgsl+wiki+wolfram+wren+xeora+xml-doc+xojo+xquery+yaml+yang+zig&plugins=line-numbers+show-language+inline-color+previewers+unescaped-markup+toolbar+copy-to-clipboard+download-button+match-braces */
|
||||
code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}
|
||||
pre[class*=language-].line-numbers{position:relative;padding-left:3.8em;counter-reset:linenumber}pre[class*=language-].line-numbers>code{position:relative;white-space:inherit}.line-numbers .line-numbers-rows{position:absolute;pointer-events:none;top:0;font-size:100%;left:-3.8em;width:3em;letter-spacing:-1px;border-right:1px solid #999;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.line-numbers-rows>span{display:block;counter-increment:linenumber}.line-numbers-rows>span:before{content:counter(linenumber);color:#999;display:block;padding-right:.8em;text-align:right}
|
||||
div.code-toolbar{position:relative}div.code-toolbar>.toolbar{position:absolute;z-index:10;top:.3em;right:.2em;transition:opacity .3s ease-in-out;opacity:0}div.code-toolbar:hover>.toolbar{opacity:1}div.code-toolbar:focus-within>.toolbar{opacity:1}div.code-toolbar>.toolbar>.toolbar-item{display:inline-block}div.code-toolbar>.toolbar>.toolbar-item>a{cursor:pointer}div.code-toolbar>.toolbar>.toolbar-item>button{background:0 0;border:0;color:inherit;font:inherit;line-height:normal;overflow:visible;padding:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}div.code-toolbar>.toolbar>.toolbar-item>a,div.code-toolbar>.toolbar>.toolbar-item>button,div.code-toolbar>.toolbar>.toolbar-item>span{color:#bbb;font-size:.8em;padding:0 .5em;background:#f5f2f0;background:rgba(224,224,224,.2);box-shadow:0 2px 0 0 rgba(0,0,0,.2);border-radius:.5em}div.code-toolbar>.toolbar>.toolbar-item>a:focus,div.code-toolbar>.toolbar>.toolbar-item>a:hover,div.code-toolbar>.toolbar>.toolbar-item>button:focus,div.code-toolbar>.toolbar>.toolbar-item>button:hover,div.code-toolbar>.toolbar>.toolbar-item>span:focus,div.code-toolbar>.toolbar>.toolbar-item>span:hover{color:inherit;text-decoration:none}
|
||||
span.inline-color-wrapper{background:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyIDIiPjxwYXRoIGZpbGw9ImdyYXkiIGQ9Ik0wIDBoMnYySDB6Ii8+PHBhdGggZmlsbD0id2hpdGUiIGQ9Ik0wIDBoMXYxSDB6TTEgMWgxdjFIMXoiLz48L3N2Zz4=);background-position:center;background-size:110%;display:inline-block;height:1.333ch;width:1.333ch;margin:0 .333ch;box-sizing:border-box;border:1px solid #fff;outline:1px solid rgba(0,0,0,.5);overflow:hidden}span.inline-color{display:block;height:120%;width:120%}
|
||||
.prism-previewer,.prism-previewer:after,.prism-previewer:before{position:absolute;pointer-events:none}.prism-previewer,.prism-previewer:after{left:50%}.prism-previewer{margin-top:-48px;width:32px;height:32px;margin-left:-16px;z-index:10;opacity:0;-webkit-transition:opacity .25s;-o-transition:opacity .25s;transition:opacity .25s}.prism-previewer.flipped{margin-top:0;margin-bottom:-48px}.prism-previewer:after,.prism-previewer:before{content:'';position:absolute;pointer-events:none}.prism-previewer:before{top:-5px;right:-5px;left:-5px;bottom:-5px;border-radius:10px;border:5px solid #fff;box-shadow:0 0 3px rgba(0,0,0,.5) inset,0 0 10px rgba(0,0,0,.75)}.prism-previewer:after{top:100%;width:0;height:0;margin:5px 0 0 -7px;border:7px solid transparent;border-color:rgba(255,0,0,0);border-top-color:#fff}.prism-previewer.flipped:after{top:auto;bottom:100%;margin-top:0;margin-bottom:5px;border-top-color:rgba(255,0,0,0);border-bottom-color:#fff}.prism-previewer.active{opacity:1}.prism-previewer-angle:before{border-radius:50%;background:#fff}.prism-previewer-angle:after{margin-top:4px}.prism-previewer-angle svg{width:32px;height:32px;-webkit-transform:rotate(-90deg);-moz-transform:rotate(-90deg);-ms-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg)}.prism-previewer-angle[data-negative] svg{-webkit-transform:scaleX(-1) rotate(-90deg);-moz-transform:scaleX(-1) rotate(-90deg);-ms-transform:scaleX(-1) rotate(-90deg);-o-transform:scaleX(-1) rotate(-90deg);transform:scaleX(-1) rotate(-90deg)}.prism-previewer-angle circle{fill:transparent;stroke:#2d3438;stroke-opacity:.9;stroke-width:32;stroke-dasharray:0,500}.prism-previewer-gradient{background-image:linear-gradient(45deg,#bbb 25%,transparent 25%,transparent 75%,#bbb 75%,#bbb),linear-gradient(45deg,#bbb 25%,#eee 25%,#eee 75%,#bbb 75%,#bbb);background-size:10px 10px;background-position:0 0,5px 5px;width:64px;margin-left:-32px}.prism-previewer-gradient:before{content:none}.prism-previewer-gradient div{position:absolute;top:-5px;left:-5px;right:-5px;bottom:-5px;border-radius:10px;border:5px solid #fff;box-shadow:0 0 3px rgba(0,0,0,.5) inset,0 0 10px rgba(0,0,0,.75)}.prism-previewer-color{background-image:linear-gradient(45deg,#bbb 25%,transparent 25%,transparent 75%,#bbb 75%,#bbb),linear-gradient(45deg,#bbb 25%,#eee 25%,#eee 75%,#bbb 75%,#bbb);background-size:10px 10px;background-position:0 0,5px 5px}.prism-previewer-color:before{background-color:inherit;background-clip:padding-box}.prism-previewer-easing{margin-top:-76px;margin-left:-30px;width:60px;height:60px;background:#333}.prism-previewer-easing.flipped{margin-bottom:-116px}.prism-previewer-easing svg{width:60px;height:60px}.prism-previewer-easing circle{fill:#2d3438;stroke:#fff}.prism-previewer-easing path{fill:none;stroke:#fff;stroke-linecap:round;stroke-width:4}.prism-previewer-easing line{stroke:#fff;stroke-opacity:.5;stroke-width:2}@-webkit-keyframes prism-previewer-time{0%{stroke-dasharray:0,500;stroke-dashoffset:0}50%{stroke-dasharray:100,500;stroke-dashoffset:0}100%{stroke-dasharray:0,500;stroke-dashoffset:-100}}@-o-keyframes prism-previewer-time{0%{stroke-dasharray:0,500;stroke-dashoffset:0}50%{stroke-dasharray:100,500;stroke-dashoffset:0}100%{stroke-dasharray:0,500;stroke-dashoffset:-100}}@-moz-keyframes prism-previewer-time{0%{stroke-dasharray:0,500;stroke-dashoffset:0}50%{stroke-dasharray:100,500;stroke-dashoffset:0}100%{stroke-dasharray:0,500;stroke-dashoffset:-100}}@keyframes prism-previewer-time{0%{stroke-dasharray:0,500;stroke-dashoffset:0}50%{stroke-dasharray:100,500;stroke-dashoffset:0}100%{stroke-dasharray:0,500;stroke-dashoffset:-100}}.prism-previewer-time:before{border-radius:50%;background:#fff}.prism-previewer-time:after{margin-top:4px}.prism-previewer-time svg{width:32px;height:32px;-webkit-transform:rotate(-90deg);-moz-transform:rotate(-90deg);-ms-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg)}.prism-previewer-time circle{fill:transparent;stroke:#2d3438;stroke-opacity:.9;stroke-width:32;stroke-dasharray:0,500;stroke-dashoffset:0;-webkit-animation:prism-previewer-time linear infinite 3s;-moz-animation:prism-previewer-time linear infinite 3s;-o-animation:prism-previewer-time linear infinite 3s;animation:prism-previewer-time linear infinite 3s}
|
||||
[class*=lang-] script[type='text/plain'],[class*=language-] script[type='text/plain'],script[type='text/plain'][class*=lang-],script[type='text/plain'][class*=language-]{display:block;font:100% Consolas,Monaco,monospace;white-space:pre;overflow:auto}
|
||||
.token.punctuation.brace-hover,.token.punctuation.brace-selected{outline:solid 1px}.rainbow-braces .token.punctuation.brace-level-1,.rainbow-braces .token.punctuation.brace-level-5,.rainbow-braces .token.punctuation.brace-level-9{color:#e50;opacity:1}.rainbow-braces .token.punctuation.brace-level-10,.rainbow-braces .token.punctuation.brace-level-2,.rainbow-braces .token.punctuation.brace-level-6{color:#0b3;opacity:1}.rainbow-braces .token.punctuation.brace-level-11,.rainbow-braces .token.punctuation.brace-level-3,.rainbow-braces .token.punctuation.brace-level-7{color:#26f;opacity:1}.rainbow-braces .token.punctuation.brace-level-12,.rainbow-braces .token.punctuation.brace-level-4,.rainbow-braces .token.punctuation.brace-level-8{color:#e0e;opacity:1}
|
||||
|
||||
/*gruvbox light*/
|
||||
code[class*=language-],pre[class*=language-]{color:#3c3836;font-family:Consolas,Monaco,"Andale Mono",monospace;direction:ltr;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{color:#282828;background:#a89984}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{color:#282828;background:#a89984}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f9f5d7}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em}.token.attr-name,.token.attr-value,.token.attr-value .punctuation,.token.cdata,.token.comment,.token.operator,.token.prolog,.token.punctuation{color:#7c6f64}.token.atrule,.token.boolean,.token.constant,.token.delimiter,.token.important,.token.keyword,.token.property,.token.selector,.token.variable{color:#9d0006}.token.builtin,.token.doctype,.token.function,.token.tag,.token.tag .punctuation{color:#b57614}.token.entity,.token.number,.token.symbol{color:#8f3f71}.token.char,.token.string,.token.url{color:#797403}.token.url{text-decoration:underline}.token.regex{background:#797403}.token.bold{font-weight:700}.token.italic{font-style:italic}.token.inserted{background:#7c6f64}.token.deleted{background:#9d0006}
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Rohit Pai - Blog</title><meta name="title" content="Rohit Pai - Blog"><meta name="description" content="This is all the blog posts that Rohit Pai has posted. You'll find posts on various topics, mostly on tech but some on various other random topics."><meta name="keywords" content="Blog, all posts, rohit, pai, rohit pai, tech, web development, self-hosting, hosting"><meta name="robots" content="index, follow"><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><meta name="language" content="English"><meta name="author" content="Rohit Pai"><link rel="stylesheet" href="/blog/css/main.css"><script src="https://kit.fontawesome.com/ed3c25598e.js" crossorigin="anonymous"></script><script type="text/javascript" src="https://platform-api.sharethis.com/js/sharethis.js#property=6550cdc47a115e0012964576&product=sop" async="async"></script></head><body><nav><input type="checkbox" id="nav-check"><h1><a href="/" class="link">rohit pai</a></h1><div class="nav-btn"><label for="nav-check"><span></span> <span></span> <span></span></label></div><ul><li><a href="/#about" class="textShadow link">about</a></li><li><a href="/#curriculumVitae" class="textShadow link">cv</a></li><li><a href="/#projects" class="textShadow link">projects</a></li><li><a href="/#contact" class="textShadow link">contact</a></li><li><a href="/blog" class="textShadow link active">blog</a></li></ul></nav><header><div><h1>full stack developer</h1><a href="/#sayHello" class="btn btnPrimary boxShadowIn boxShadowOut">Contact Me</a> <a href="" id="arrow"><i class="fa-solid fa-chevron-down"></i></a></div></header><div class="menuBar"><div class="menu"><ul><li><a href="/blog" class="link active">All posts</a></li><li><a href="/blog/category" class="link">categories</a></li><li><label for="searchField" aria-hidden="true" hidden>search</label> <input type="search" name="search" id="searchField" placeholder="Search..."> <button type="submit" id="searchBtn" class="btn btnPrimary"><i class="fa fa-search"></i></button></li></ul></div></div><main id="main"></main><div class="modal-container" id="cookiePopup"><div class="modal"><div class="modal-content"><h2><i class="fas fa-cookie-bite"></i> Hey I use cookies btw</h2><p>Just to let you know, I use cookies to give you the best experience on my blog. By clicking agree I'll assume that you are happy with it. <a href="/blog/policy/cookie" class="link">Read more</a></p><div class="flexRow"><button class="btn btnPrimary" id="cookieAccept">agree</button></div></div></div></div><footer class="flexRow"><div class="nav"><ul><li><a href="/blog/policy/privacy" class="link">privacy policy</a></li><li><a href="/blog/policy/cookie" class="link">cookie policy</a></li></ul></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/typewriter.js"></script><script src="/blog/js/index.js"></script><script id="dsq-count-scr" src="https://rohitpaiportfolio.disqus.com/count.js" async></script></body></html>
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Rohit Pai - Blog</title><meta name="title" content="Rohit Pai - Blog"><meta name="description" content="This is all the blog posts that Rohit Pai has posted. You'll find posts on various topics, mostly on tech but some on various other random topics."><meta name="keywords" content="Blog, all posts, rohit, pai, rohit pai, tech, web development, self-hosting, hosting"><meta name="robots" content="index, follow"><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><meta name="language" content="English"><meta name="author" content="Rohit Pai"><link rel="stylesheet" href="/blog/css/prism.css"><link rel="stylesheet" href="/blog/css/main.css"><script src="https://kit.fontawesome.com/ed3c25598e.js" crossorigin="anonymous"></script><script type="text/javascript" src="https://platform-api.sharethis.com/js/sharethis.js#property=6550cdc47a115e0012964576&product=sop" async="async"></script></head><body><nav><input type="checkbox" id="nav-check"><h1><a href="/" class="link">rohit pai</a></h1><div class="nav-btn"><label for="nav-check"><span></span> <span></span> <span></span></label></div><ul><li><a href="/#about" class="textShadow link">about</a></li><li><a href="/#curriculumVitae" class="textShadow link">cv</a></li><li><a href="/#projects" class="textShadow link">projects</a></li><li><a href="/#contact" class="textShadow link">contact</a></li><li><a href="/blog" class="textShadow link active">blog</a></li></ul></nav><header><div><h1>full stack developer</h1><a href="/#sayHello" class="btn btnPrimary boxShadowIn boxShadowOut">Contact Me</a> <a href="" id="arrow"><i class="fa-solid fa-chevron-down"></i></a></div></header><div class="menuBar"><div class="menu"><ul><li><a href="/blog" class="link active">All posts</a></li><li><a href="/blog/category" class="link">categories</a></li><li><label for="searchField" aria-hidden="true" hidden>search</label> <input type="search" name="search" id="searchField" placeholder="Search..."> <button type="submit" id="searchBtn" class="btn btnPrimary"><i class="fa fa-search"></i></button></li></ul></div></div><main id="main"></main><div class="modal-container" id="cookiePopup"><div class="modal"><div class="modal-content"><h2><i class="fas fa-cookie-bite"></i> Hey I use cookies btw</h2><p>Just to let you know, I use cookies to give you the best experience on my blog. By clicking agree I'll assume that you are happy with it. <a href="/blog/policy/cookie" class="link">Read more</a></p><div class="flexRow"><button class="btn btnPrimary" id="cookieAccept">agree</button></div></div></div></div><footer class="flexRow"><div class="nav"><ul><li><a href="/blog/policy/privacy" class="link">privacy policy</a></li><li><a href="/blog/policy/cookie" class="link">cookie policy</a></li></ul></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/typewriter.js"></script><script src="/blog/js/prism.js"></script><script src="/blog/js/index.js"></script><script id="dsq-count-scr" src="https://rohitpaiportfolio.disqus.com/count.js" async></script></body></html>
|
||||
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
|
||||
{
|
||||
$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);
|
||||
$imgs = $doc->getElementsByTagName('img');
|
||||
|
||||
@@ -687,9 +691,11 @@ EOD;
|
||||
$srcList[] = $src;
|
||||
$fileName = basename($src);
|
||||
|
||||
// Update the src attribute to the new location
|
||||
$img->setAttribute("src", substr($to, 2) . $fileName);
|
||||
}
|
||||
|
||||
// Rename files and clean up old ones
|
||||
$files = scandir($from);
|
||||
foreach ($files as $file)
|
||||
{
|
||||
@@ -705,14 +711,36 @@ EOD;
|
||||
}
|
||||
}
|
||||
|
||||
// Process the HTML content for output
|
||||
$newBody = '';
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param string $category - Category of the post
|
||||
|
||||
+18
-21
@@ -17,7 +17,7 @@ class userRoutes implements routesInterface
|
||||
private Auth $samlAuth;
|
||||
|
||||
/**
|
||||
* constructor used to instantiate a base user routes, to be used in the index.php file.
|
||||
* constructor used to instantiate base user routes, to be used in the index.php file.
|
||||
* @param App $app - the slim app used to create the routes
|
||||
* @throws Error
|
||||
*/
|
||||
@@ -168,27 +168,24 @@ class userRoutes implements routesInterface
|
||||
$this->samlAuth->processResponse();
|
||||
|
||||
$attributes = $this->samlAuth->getAttributes();
|
||||
// $username = $attributes["username"][0];
|
||||
// $email = $attributes["email"][0];
|
||||
$username = $attributes["username"][0];
|
||||
$email = $attributes["email"][0];
|
||||
|
||||
$response->getBody()->write(json_encode($attributes));
|
||||
return $response;
|
||||
if ($this->user->checkSAMLUser($username, $email))
|
||||
{
|
||||
// yay, user is logged in
|
||||
$_SESSION["token"] = $this->user->createToken($username);
|
||||
$_SESSION["username"] = $username;
|
||||
$_SESSION["email"] = $email;
|
||||
|
||||
// if ($this->user->checkSAMLUser($username, $email))
|
||||
// {
|
||||
// // yay, user is logged in
|
||||
// $_SESSION["token"] = $this->user->createToken($username);
|
||||
// $_SESSION["username"] = $username;
|
||||
// $_SESSION["email"] = $email;
|
||||
//
|
||||
// $inactive = 60 * 60 * 48; // 2 days
|
||||
// $_SESSION["timeout"] = time() + $inactive;
|
||||
//
|
||||
// return $response->withHeader("Location", "https://rohitpai.co.uk/editor/editor.html")->withStatus(302);
|
||||
// }
|
||||
//
|
||||
// $response->getBody()->write(json_encode(array("error" => "Unauthorised")));
|
||||
// return $response->withStatus(401);
|
||||
$inactive = 60 * 60 * 48; // 2 days
|
||||
$_SESSION["timeout"] = time() + $inactive;
|
||||
|
||||
return $response->withHeader("Location", "https://rohitpai.co.uk/editor/")->withStatus(302);
|
||||
}
|
||||
|
||||
$response->getBody()->write(json_encode(array("error" => "Unauthorised")));
|
||||
return $response->withStatus(401);
|
||||
});
|
||||
|
||||
$app->post("/user/changePassword", function (Request $request, Response $response)
|
||||
@@ -217,4 +214,4 @@ class userRoutes implements routesInterface
|
||||
return $response->withStatus(500);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +84,11 @@ article a::after {
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
article a.btn::before,
|
||||
article a.btn::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
article a::before {
|
||||
content: ' <';
|
||||
margin-left: -0.5em;
|
||||
@@ -110,6 +115,27 @@ article h3:not(div.byLine > h3), .otherPosts h3 {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
article .media {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
article table td, article table th {
|
||||
border: 1px solid #ddd;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
article table tr:nth-child(even) {
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
article table tr:hover {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
article .table {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
aside.sideContent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -123,3 +123,102 @@ section.largePost .outerContent .postContent a {
|
||||
display: table-cell;
|
||||
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
-2
@@ -8,8 +8,13 @@
|
||||
@import "blogPosts.css";
|
||||
@import "home.css";
|
||||
@import "category.css";
|
||||
@import "prism.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 {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -73,7 +78,12 @@
|
||||
/**** Media Queries *****/
|
||||
|
||||
@media screen and (max-width: 90em) {
|
||||
|
||||
|
||||
|
||||
section#olderPosts #carouselInner .cardItem {
|
||||
width: 25em;
|
||||
}
|
||||
|
||||
/***** Individual Blog Posts ***/
|
||||
|
||||
div.mainContent {
|
||||
@@ -125,6 +135,25 @@
|
||||
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 ***/
|
||||
section#individualPost {
|
||||
flex-direction: column-reverse;
|
||||
@@ -220,6 +249,24 @@
|
||||
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 ***/
|
||||
|
||||
aside.sideContent > div.authorInfo {
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
/* PrismJS 1.29.0
|
||||
https://prismjs.com/download.html#themes=prism-okaidia&languages=markup+css+clike+javascript+abap+abnf+actionscript+ada+agda+al+antlr4+apacheconf+apex+apl+applescript+aql+arduino+arff+armasm+arturo+asciidoc+aspnet+asm6502+asmatmel+autohotkey+autoit+avisynth+avro-idl+awk+bash+basic+batch+bbcode+bbj+bicep+birb+bison+bnf+bqn+brainfuck+brightscript+bro+bsl+c+csharp+cpp+cfscript+chaiscript+cil+cilkc+cilkcpp+clojure+cmake+cobol+coffeescript+concurnas+csp+cooklang+coq+crystal+css-extras+csv+cue+cypher+d+dart+dataweave+dax+dhall+diff+django+dns-zone-file+docker+dot+ebnf+editorconfig+eiffel+ejs+elixir+elm+etlua+erb+erlang+excel-formula+fsharp+factor+false+firestore-security-rules+flow+fortran+ftl+gml+gap+gcode+gdscript+gedcom+gettext+gherkin+git+glsl+gn+linker-script+go+go-module+gradle+graphql+groovy+haml+handlebars+haskell+haxe+hcl+hlsl+hoon+http+hpkp+hsts+ichigojam+icon+icu-message-format+idris+ignore+inform7+ini+io+j+java+javadoc+javadoclike+javastacktrace+jexl+jolie+jq+jsdoc+js-extras+json+json5+jsonp+jsstacktrace+js-templates+julia+keepalived+keyman+kotlin+kumir+kusto+latex+latte+less+lilypond+liquid+lisp+livescript+llvm+log+lolcode+lua+magma+makefile+markdown+markup-templating+mata+matlab+maxscript+mel+mermaid+metafont+mizar+mongodb+monkey+moonscript+n1ql+n4js+nand2tetris-hdl+naniscript+nasm+neon+nevod+nginx+nim+nix+nsis+objectivec+ocaml+odin+opencl+openqasm+oz+parigp+parser+pascal+pascaligo+psl+pcaxis+peoplecode+perl+php+phpdoc+php-extras+plant-uml+plsql+powerquery+powershell+processing+prolog+promql+properties+protobuf+pug+puppet+pure+purebasic+purescript+python+qsharp+q+qml+qore+r+racket+cshtml+jsx+tsx+reason+regex+rego+renpy+rescript+rest+rip+roboconf+robotframework+ruby+rust+sas+sass+scss+scala+scheme+shell-session+smali+smalltalk+smarty+sml+solidity+solution-file+soy+sparql+splunk-spl+sqf+sql+squirrel+stan+stata+iecst+stylus+supercollider+swift+systemd+t4-templating+t4-cs+t4-vb+tap+tcl+tt2+textile+toml+tremor+turtle+twig+typescript+typoscript+unrealscript+uorazor+uri+v+vala+vbnet+velocity+verilog+vhdl+vim+visual-basic+warpscript+wasm+web-idl+wgsl+wiki+wolfram+wren+xeora+xml-doc+xojo+xquery+yaml+yang+zig&plugins=line-numbers+autolinker+show-language+previewers+toolbar+match-braces+diff-highlight */
|
||||
code[class*=language-],pre[class*=language-]{color:#f8f8f2;background:0 0;text-shadow:0 1px rgba(0,0,0,.3);font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto;border-radius:.3em}:not(pre)>code[class*=language-],pre[class*=language-]{background:#272822}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#8292a2}.token.punctuation{color:#f8f8f2}.token.namespace{opacity:.7}.token.constant,.token.deleted,.token.property,.token.symbol,.token.tag{color:#f92672}.token.boolean,.token.number{color:#ae81ff}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#a6e22e}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url,.token.variable{color:#f8f8f2}.token.atrule,.token.attr-value,.token.class-name,.token.function{color:#e6db74}.token.keyword{color:#66d9ef}.token.important,.token.regex{color:#fd971f}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}
|
||||
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+abap+abnf+actionscript+ada+agda+al+antlr4+apacheconf+apex+apl+applescript+aql+arduino+arff+armasm+arturo+asciidoc+aspnet+asm6502+asmatmel+autohotkey+autoit+avisynth+avro-idl+awk+bash+basic+batch+bbcode+bbj+bicep+birb+bison+bnf+bqn+brainfuck+brightscript+bro+bsl+c+csharp+cpp+cfscript+chaiscript+cil+cilkc+cilkcpp+clojure+cmake+cobol+coffeescript+concurnas+csp+cooklang+coq+crystal+css-extras+csv+cue+cypher+d+dart+dataweave+dax+dhall+diff+django+dns-zone-file+docker+dot+ebnf+editorconfig+eiffel+ejs+elixir+elm+etlua+erb+erlang+excel-formula+fsharp+factor+false+firestore-security-rules+flow+fortran+ftl+gml+gap+gcode+gdscript+gedcom+gettext+gherkin+git+glsl+gn+linker-script+go+go-module+gradle+graphql+groovy+haml+handlebars+haskell+haxe+hcl+hlsl+hoon+http+hpkp+hsts+ichigojam+icon+icu-message-format+idris+ignore+inform7+ini+io+j+java+javadoc+javadoclike+javastacktrace+jexl+jolie+jq+jsdoc+js-extras+json+json5+jsonp+jsstacktrace+js-templates+julia+keepalived+keyman+kotlin+kumir+kusto+latex+latte+less+lilypond+liquid+lisp+livescript+llvm+log+lolcode+lua+magma+makefile+markdown+markup-templating+mata+matlab+maxscript+mel+mermaid+metafont+mizar+mongodb+monkey+moonscript+n1ql+n4js+nand2tetris-hdl+naniscript+nasm+neon+nevod+nginx+nim+nix+nsis+objectivec+ocaml+odin+opencl+openqasm+oz+parigp+parser+pascal+pascaligo+psl+pcaxis+peoplecode+perl+php+phpdoc+php-extras+plant-uml+plsql+powerquery+powershell+processing+prolog+promql+properties+protobuf+pug+puppet+pure+purebasic+purescript+python+qsharp+q+qml+qore+r+racket+cshtml+jsx+tsx+reason+regex+rego+renpy+rescript+rest+rip+roboconf+robotframework+ruby+rust+sas+sass+scss+scala+scheme+shell-session+smali+smalltalk+smarty+sml+solidity+solution-file+soy+sparql+splunk-spl+sqf+sql+squirrel+stan+stata+iecst+stylus+supercollider+swift+systemd+t4-templating+t4-cs+t4-vb+tap+tcl+tt2+textile+toml+tremor+turtle+twig+typescript+typoscript+unrealscript+uorazor+uri+v+vala+vbnet+velocity+verilog+vhdl+vim+visual-basic+warpscript+wasm+web-idl+wgsl+wiki+wolfram+wren+xeora+xml-doc+xojo+xquery+yaml+yang+zig&plugins=line-numbers+show-language+inline-color+previewers+unescaped-markup+toolbar+copy-to-clipboard+download-button+match-braces */
|
||||
code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}
|
||||
pre[class*=language-].line-numbers{position:relative;padding-left:3.8em;counter-reset:linenumber}pre[class*=language-].line-numbers>code{position:relative;white-space:inherit}.line-numbers .line-numbers-rows{position:absolute;pointer-events:none;top:0;font-size:100%;left:-3.8em;width:3em;letter-spacing:-1px;border-right:1px solid #999;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.line-numbers-rows>span{display:block;counter-increment:linenumber}.line-numbers-rows>span:before{content:counter(linenumber);color:#999;display:block;padding-right:.8em;text-align:right}
|
||||
.token a{color:inherit}
|
||||
div.code-toolbar{position:relative}div.code-toolbar>.toolbar{position:absolute;z-index:10;top:.3em;right:.2em;transition:opacity .3s ease-in-out;opacity:0}div.code-toolbar:hover>.toolbar{opacity:1}div.code-toolbar:focus-within>.toolbar{opacity:1}div.code-toolbar>.toolbar>.toolbar-item{display:inline-block}div.code-toolbar>.toolbar>.toolbar-item>a{cursor:pointer}div.code-toolbar>.toolbar>.toolbar-item>button{background:0 0;border:0;color:inherit;font:inherit;line-height:normal;overflow:visible;padding:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}div.code-toolbar>.toolbar>.toolbar-item>a,div.code-toolbar>.toolbar>.toolbar-item>button,div.code-toolbar>.toolbar>.toolbar-item>span{color:#bbb;font-size:.8em;padding:0 .5em;background:#f5f2f0;background:rgba(224,224,224,.2);box-shadow:0 2px 0 0 rgba(0,0,0,.2);border-radius:.5em}div.code-toolbar>.toolbar>.toolbar-item>a:focus,div.code-toolbar>.toolbar>.toolbar-item>a:hover,div.code-toolbar>.toolbar>.toolbar-item>button:focus,div.code-toolbar>.toolbar>.toolbar-item>button:hover,div.code-toolbar>.toolbar>.toolbar-item>span:focus,div.code-toolbar>.toolbar>.toolbar-item>span:hover{color:inherit;text-decoration:none}
|
||||
span.inline-color-wrapper{background:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyIDIiPjxwYXRoIGZpbGw9ImdyYXkiIGQ9Ik0wIDBoMnYySDB6Ii8+PHBhdGggZmlsbD0id2hpdGUiIGQ9Ik0wIDBoMXYxSDB6TTEgMWgxdjFIMXoiLz48L3N2Zz4=);background-position:center;background-size:110%;display:inline-block;height:1.333ch;width:1.333ch;margin:0 .333ch;box-sizing:border-box;border:1px solid #fff;outline:1px solid rgba(0,0,0,.5);overflow:hidden}span.inline-color{display:block;height:120%;width:120%}
|
||||
.prism-previewer,.prism-previewer:after,.prism-previewer:before{position:absolute;pointer-events:none}.prism-previewer,.prism-previewer:after{left:50%}.prism-previewer{margin-top:-48px;width:32px;height:32px;margin-left:-16px;z-index:10;opacity:0;-webkit-transition:opacity .25s;-o-transition:opacity .25s;transition:opacity .25s}.prism-previewer.flipped{margin-top:0;margin-bottom:-48px}.prism-previewer:after,.prism-previewer:before{content:'';position:absolute;pointer-events:none}.prism-previewer:before{top:-5px;right:-5px;left:-5px;bottom:-5px;border-radius:10px;border:5px solid #fff;box-shadow:0 0 3px rgba(0,0,0,.5) inset,0 0 10px rgba(0,0,0,.75)}.prism-previewer:after{top:100%;width:0;height:0;margin:5px 0 0 -7px;border:7px solid transparent;border-color:rgba(255,0,0,0);border-top-color:#fff}.prism-previewer.flipped:after{top:auto;bottom:100%;margin-top:0;margin-bottom:5px;border-top-color:rgba(255,0,0,0);border-bottom-color:#fff}.prism-previewer.active{opacity:1}.prism-previewer-angle:before{border-radius:50%;background:#fff}.prism-previewer-angle:after{margin-top:4px}.prism-previewer-angle svg{width:32px;height:32px;-webkit-transform:rotate(-90deg);-moz-transform:rotate(-90deg);-ms-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg)}.prism-previewer-angle[data-negative] svg{-webkit-transform:scaleX(-1) rotate(-90deg);-moz-transform:scaleX(-1) rotate(-90deg);-ms-transform:scaleX(-1) rotate(-90deg);-o-transform:scaleX(-1) rotate(-90deg);transform:scaleX(-1) rotate(-90deg)}.prism-previewer-angle circle{fill:transparent;stroke:#2d3438;stroke-opacity:.9;stroke-width:32;stroke-dasharray:0,500}.prism-previewer-gradient{background-image:linear-gradient(45deg,#bbb 25%,transparent 25%,transparent 75%,#bbb 75%,#bbb),linear-gradient(45deg,#bbb 25%,#eee 25%,#eee 75%,#bbb 75%,#bbb);background-size:10px 10px;background-position:0 0,5px 5px;width:64px;margin-left:-32px}.prism-previewer-gradient:before{content:none}.prism-previewer-gradient div{position:absolute;top:-5px;left:-5px;right:-5px;bottom:-5px;border-radius:10px;border:5px solid #fff;box-shadow:0 0 3px rgba(0,0,0,.5) inset,0 0 10px rgba(0,0,0,.75)}.prism-previewer-color{background-image:linear-gradient(45deg,#bbb 25%,transparent 25%,transparent 75%,#bbb 75%,#bbb),linear-gradient(45deg,#bbb 25%,#eee 25%,#eee 75%,#bbb 75%,#bbb);background-size:10px 10px;background-position:0 0,5px 5px}.prism-previewer-color:before{background-color:inherit;background-clip:padding-box}.prism-previewer-easing{margin-top:-76px;margin-left:-30px;width:60px;height:60px;background:#333}.prism-previewer-easing.flipped{margin-bottom:-116px}.prism-previewer-easing svg{width:60px;height:60px}.prism-previewer-easing circle{fill:#2d3438;stroke:#fff}.prism-previewer-easing path{fill:none;stroke:#fff;stroke-linecap:round;stroke-width:4}.prism-previewer-easing line{stroke:#fff;stroke-opacity:.5;stroke-width:2}@-webkit-keyframes prism-previewer-time{0%{stroke-dasharray:0,500;stroke-dashoffset:0}50%{stroke-dasharray:100,500;stroke-dashoffset:0}100%{stroke-dasharray:0,500;stroke-dashoffset:-100}}@-o-keyframes prism-previewer-time{0%{stroke-dasharray:0,500;stroke-dashoffset:0}50%{stroke-dasharray:100,500;stroke-dashoffset:0}100%{stroke-dasharray:0,500;stroke-dashoffset:-100}}@-moz-keyframes prism-previewer-time{0%{stroke-dasharray:0,500;stroke-dashoffset:0}50%{stroke-dasharray:100,500;stroke-dashoffset:0}100%{stroke-dasharray:0,500;stroke-dashoffset:-100}}@keyframes prism-previewer-time{0%{stroke-dasharray:0,500;stroke-dashoffset:0}50%{stroke-dasharray:100,500;stroke-dashoffset:0}100%{stroke-dasharray:0,500;stroke-dashoffset:-100}}.prism-previewer-time:before{border-radius:50%;background:#fff}.prism-previewer-time:after{margin-top:4px}.prism-previewer-time svg{width:32px;height:32px;-webkit-transform:rotate(-90deg);-moz-transform:rotate(-90deg);-ms-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg)}.prism-previewer-time circle{fill:transparent;stroke:#2d3438;stroke-opacity:.9;stroke-width:32;stroke-dasharray:0,500;stroke-dashoffset:0;-webkit-animation:prism-previewer-time linear infinite 3s;-moz-animation:prism-previewer-time linear infinite 3s;-o-animation:prism-previewer-time linear infinite 3s;animation:prism-previewer-time linear infinite 3s}
|
||||
[class*=lang-] script[type='text/plain'],[class*=language-] script[type='text/plain'],script[type='text/plain'][class*=lang-],script[type='text/plain'][class*=language-]{display:block;font:100% Consolas,Monaco,monospace;white-space:pre;overflow:auto}
|
||||
.token.punctuation.brace-hover,.token.punctuation.brace-selected{outline:solid 1px}.rainbow-braces .token.punctuation.brace-level-1,.rainbow-braces .token.punctuation.brace-level-5,.rainbow-braces .token.punctuation.brace-level-9{color:#e50;opacity:1}.rainbow-braces .token.punctuation.brace-level-10,.rainbow-braces .token.punctuation.brace-level-2,.rainbow-braces .token.punctuation.brace-level-6{color:#0b3;opacity:1}.rainbow-braces .token.punctuation.brace-level-11,.rainbow-braces .token.punctuation.brace-level-3,.rainbow-braces .token.punctuation.brace-level-7{color:#26f;opacity:1}.rainbow-braces .token.punctuation.brace-level-12,.rainbow-braces .token.punctuation.brace-level-4,.rainbow-braces .token.punctuation.brace-level-8{color:#e0e;opacity:1}
|
||||
pre.diff-highlight>code .token.deleted:not(.prefix),pre>code.diff-highlight .token.deleted:not(.prefix){background-color:rgba(255,0,0,.1);color:inherit;display:block}pre.diff-highlight>code .token.inserted:not(.prefix),pre>code.diff-highlight .token.inserted:not(.prefix){background-color:rgba(0,255,128,.1);color:inherit;display:block}
|
||||
|
||||
/*gruvbox light*/
|
||||
code[class*=language-],pre[class*=language-]{color:#3c3836;font-family:Consolas,Monaco,"Andale Mono",monospace;direction:ltr;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{color:#282828;background:#a89984}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{color:#282828;background:#a89984}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f9f5d7}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em}.token.attr-name,.token.attr-value,.token.attr-value .punctuation,.token.cdata,.token.comment,.token.operator,.token.prolog,.token.punctuation{color:#7c6f64}.token.atrule,.token.boolean,.token.constant,.token.delimiter,.token.important,.token.keyword,.token.property,.token.selector,.token.variable{color:#9d0006}.token.builtin,.token.doctype,.token.function,.token.tag,.token.tag .punctuation{color:#b57614}.token.entity,.token.number,.token.symbol{color:#8f3f71}.token.char,.token.string,.token.url{color:#797403}.token.url{text-decoration:underline}.token.regex{background:#797403}.token.bold{font-weight:700}.token.italic{font-style:italic}.token.inserted{background:#7c6f64}.token.deleted{background:#9d0006}
|
||||
@@ -15,6 +15,7 @@
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="language" content="English">
|
||||
<meta name="author" content="Rohit Pai">
|
||||
<link rel="stylesheet" href="/blog/css/prism.css">
|
||||
<link rel="stylesheet" href="/blog/css/main.css">
|
||||
<script src="https://kit.fontawesome.com/ed3c25598e.js" crossorigin="anonymous"></script>
|
||||
<script type='text/javascript'
|
||||
@@ -100,6 +101,7 @@
|
||||
</footer>
|
||||
|
||||
<script src="/js/typewriter.js"></script>
|
||||
<script src="/blog/js/prism.js"></script>
|
||||
<script src="/blog/js/index.js"></script>
|
||||
<script id="dsq-count-scr" src="https://rohitpaiportfolio.disqus.com/count.js" async></script>
|
||||
</body>
|
||||
|
||||
+199
-2
@@ -41,7 +41,6 @@ function goToURL(url)
|
||||
if (url === '/blog' || url === 'blog' || url === '/blog/')
|
||||
{
|
||||
loadHomeContent();
|
||||
// window.history.pushState(null, null, url);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -162,6 +161,10 @@ function submitNewsletter()
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* unsubscribe by email
|
||||
* @param email the email to unsubscribe
|
||||
*/
|
||||
function unsubscribe(email)
|
||||
{
|
||||
fetch(`/api/blog/newsletter/${email}`, {
|
||||
@@ -243,6 +246,32 @@ function createLargePost(post)
|
||||
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
|
||||
*/
|
||||
@@ -250,6 +279,30 @@ function loadHomeContent()
|
||||
{
|
||||
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++)
|
||||
{
|
||||
if (json[i].featured === 1)
|
||||
@@ -278,10 +331,150 @@ function loadHomeContent()
|
||||
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
|
||||
* @returns {Promise<any[]>} the latest and featured posts
|
||||
@@ -390,7 +583,7 @@ async function createSideContent()
|
||||
<div class="authorInfo">
|
||||
<div class="picture">
|
||||
<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"
|
||||
class="profile">
|
||||
<p>Rohit Pai</p>
|
||||
@@ -589,6 +782,7 @@ async function loadIndividualPost(title)
|
||||
s.setAttribute('data-timestamp', +new Date());
|
||||
d.body.appendChild(s);
|
||||
})();
|
||||
Prism.highlightAll();
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -847,6 +1041,9 @@ function loadPrivacyPolicy()
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the cookie policy
|
||||
*/
|
||||
function loadCookiePolicy()
|
||||
{
|
||||
document.querySelector('#main').innerHTML = `
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1
-1
@@ -120,4 +120,4 @@ div.message.hidden {
|
||||
|
||||
div.message button:hover {
|
||||
text-shadow: -1px 2px var(--mutedBlack);
|
||||
}
|
||||
}
|
||||
|
||||
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
+36
-11
@@ -858,6 +858,31 @@ function createEditors(...ids)
|
||||
{language: 'zephir', label: 'Zephir'},
|
||||
],
|
||||
},
|
||||
mediaEmbed: {
|
||||
previewsInData: true,
|
||||
providers: [
|
||||
{
|
||||
name: 'youtube',
|
||||
url: [
|
||||
/^(?:m\.)?youtube\.com\/watch\?v=([\w-]+)(?:&t=(\d+))?/,
|
||||
/^(?:m\.)?youtube\.com\/v\/([\w-]+)(?:\?t=(\d+))?/,
|
||||
/^youtube\.com\/embed\/([\w-]+)(?:\?start=(\d+))?/,
|
||||
/^youtu\.be\/([\w-]+)(?:\?t=(\d+))?/,
|
||||
],
|
||||
html: match =>
|
||||
{
|
||||
const id = match[1];
|
||||
const time = match[2];
|
||||
|
||||
return (
|
||||
`<iframe width="560" height="315" style="text-align:center;" src="https://www.youtube.com/embed/${id}${time ? `?start=${time}` : ''}" ` +
|
||||
'allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen>' +
|
||||
'</iframe>'
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}).then(CKEditor =>
|
||||
{
|
||||
editors[id] = CKEditor;
|
||||
@@ -1197,15 +1222,15 @@ function updateProjectItem(id, e)
|
||||
{
|
||||
e.preventDefault();
|
||||
let data = {}
|
||||
data["title"] = document.querySelector(`#title${id}`).value;
|
||||
data["isMainProject"] = document.querySelector(`#isMainProject${id}`).checked ? "true" : "false";
|
||||
data["information"] = document.querySelector(`#info${id}`).value;
|
||||
data["projectLink"] = document.querySelector(`#viewProj${id}`).value;
|
||||
data["gitLink"] = document.querySelector(`#git${id}`).value;
|
||||
data['title'] = document.querySelector(`#title${id}proj`).value;
|
||||
data['isMainProject'] = document.querySelector(`#isMainProject${id}proj`).checked ? 'true' : 'false';
|
||||
data['information'] = document.querySelector(`#info${id}proj`).value;
|
||||
data['projectLink'] = document.querySelector(`#viewProj${id}proj`).value;
|
||||
data['gitLink'] = document.querySelector(`#git${id}proj`).value;
|
||||
|
||||
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, {
|
||||
method: "PATCH",
|
||||
body: JSON.stringify(data),
|
||||
@@ -1229,8 +1254,8 @@ function updateProjectItem(id, e)
|
||||
}
|
||||
|
||||
document.querySelector(`#projectItem${id}`).classList.toggle("editing");
|
||||
document.querySelector(`#title${id}`).setAttribute("disabled", "");
|
||||
document.querySelector(`#info${id}`).setAttribute("disabled", "");
|
||||
document.querySelector(`#title${id}proj`).setAttribute('disabled', '');
|
||||
document.querySelector(`#info${id}proj`).setAttribute('disabled', '');
|
||||
return;
|
||||
}
|
||||
console.log("updating image")
|
||||
@@ -1268,8 +1293,8 @@ function updateProjectItem(id, e)
|
||||
}
|
||||
|
||||
document.querySelector(`#projectItem${id}`).classList.toggle("editing");
|
||||
document.querySelector(`#title${id}`).setAttribute("disabled", "");
|
||||
document.querySelector(`#info${id}`).setAttribute("disabled", "");
|
||||
document.querySelector(`#title${id}proj`).setAttribute('disabled', '');
|
||||
document.querySelector(`#info${id}proj`).setAttribute('disabled', '');
|
||||
document.querySelector(`#projectImage${id}`).src = updatedProjectImage.imgLocation;
|
||||
return;
|
||||
}
|
||||
|
||||
+11
-9
@@ -32,6 +32,7 @@
|
||||
<li><a href="/blog" class="textShadow link">blog</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<header>
|
||||
<div>
|
||||
<h1>full stack developer</h1>
|
||||
@@ -108,7 +109,7 @@
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<a href="#">
|
||||
<a href="https://rohitpai.co.uk/blog">
|
||||
<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"/>
|
||||
</svg>
|
||||
@@ -173,15 +174,16 @@
|
||||
</form>
|
||||
</div>
|
||||
</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>
|
||||
|
||||
<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/typewriter.js"></script>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user