mirror of
https://codeberg.org/vlw/victorwesterlund.com.git
synced 2025-09-14 11:33:41 +02:00
wip(22w6b): add content and more glitching
This commit is contained in:
parent
405fbe0f28
commit
a610af6ce6
17 changed files with 170 additions and 306 deletions
|
@ -1,9 +1,12 @@
|
||||||
:root {
|
:root {
|
||||||
--color-base: 0, 0, 0;
|
--color-base: 0, 0, 0;
|
||||||
--color-: 33, 33, 33;
|
--color-contrast: 256, 256, 256;
|
||||||
--color-contrast: 255, 255, 225;
|
|
||||||
|
|
||||||
--padding: 30px;
|
--padding: 40px;
|
||||||
|
|
||||||
|
--font-min: 30px;
|
||||||
|
--font-tar: 10vw;
|
||||||
|
--font-max: 4vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- Cornerstones -- */
|
/* -- Cornerstones -- */
|
||||||
|
@ -16,16 +19,7 @@
|
||||||
|
|
||||||
*::selection {
|
*::selection {
|
||||||
background-color: rgb(var(--color-contrast));
|
background-color: rgb(var(--color-contrast));
|
||||||
color: rgb(var(--color-background));
|
color: rgb(var(--color-base));
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 15px 30px;
|
|
||||||
border-radius: 100px;
|
|
||||||
border: solid 4px rgba(var(--color-contrast), .3);
|
|
||||||
text-decoration: none;
|
|
||||||
margin: var(--padding) 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
html,
|
html,
|
||||||
|
@ -33,53 +27,120 @@ body {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
background-color: rgba(var(--color-base), .8);
|
background-color: rgba(var(--color-base), .7);
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-blend-mode: overlay;
|
background-blend-mode: overlay;
|
||||||
background-position: fixed;
|
background-position: fixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:is(p, h1) {
|
||||||
|
font-size: var(--font-min);
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
display: inline-block;
|
||||||
|
text-decoration: none;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: clamp(var(--font-min), var(--font-tar), var(--font-max));
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: clamp(calc(var(--font-min) / 2), calc(var(--font-tar) / 2), calc(var(--font-max) / 2));
|
||||||
|
}
|
||||||
|
|
||||||
/* -- Components -- */
|
/* -- Components -- */
|
||||||
|
|
||||||
body {
|
body {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-items: center;
|
||||||
gap: var(--padding, 30px);
|
gap: var(--padding, 30px);
|
||||||
}
|
}
|
||||||
|
|
||||||
body > div {
|
body > div {
|
||||||
padding: var(--padding);
|
padding: var(--padding);
|
||||||
justify-items: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
body > div:first-child {
|
/* --- */
|
||||||
--font-min: 20px;
|
|
||||||
|
#intro {
|
||||||
--font-tar: 13vw;
|
--font-tar: 13vw;
|
||||||
--font-max: 6vh;
|
--font-max: 6vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
body > div:first-child :is(a, p, h1) {
|
#intro a {
|
||||||
font-size: var(--font-min);
|
padding: 15px 30px;
|
||||||
user-select: none;
|
border-radius: 100px;
|
||||||
|
border: solid 4px rgba(var(--color-contrast), .3);
|
||||||
|
margin: var(--padding) 0;
|
||||||
|
width: calc(100% - (var(--padding) * 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
body > div:first-child p {
|
#intro p {
|
||||||
font-size: clamp(calc(var(--font-min) / 2), calc(var(--font-tar) / 2), calc(var(--font-max) / 2));
|
margin: 10px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
body > div:first-child h1 {
|
/* --- */
|
||||||
font-size: clamp(var(--font-min), var(--font-tar), var(--font-max));
|
|
||||||
|
#card,
|
||||||
|
#card > div {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: calc(var(--padding) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#card {
|
||||||
|
--portrait-size: 128px;
|
||||||
|
|
||||||
|
gap: var(--padding);
|
||||||
|
position: relative;
|
||||||
|
max-width: 500px;
|
||||||
|
background-color: rgb(var(--color-base));
|
||||||
|
padding: var(--padding);
|
||||||
|
padding-top: calc(var(--portrait-size) - (var(--padding) / 2));
|
||||||
|
border-radius: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#card > img {
|
||||||
|
width: var(--portrait-size);
|
||||||
|
height: var(--portrait-size);
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 100%;
|
||||||
|
top: calc((var(--portrait-size) / 2) * -1);
|
||||||
|
box-shadow: 0 0 0 15px rgb(var(--color-base));
|
||||||
|
}
|
||||||
|
|
||||||
|
#card a {
|
||||||
|
width: 100%;
|
||||||
|
padding: 15px 0;
|
||||||
|
border-radius: 9px;
|
||||||
|
background-color: rgba(var(--color-contrast), .13);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- Media Queries -- */
|
/* -- Media Queries -- */
|
||||||
|
|
||||||
@media (pointer: fine) {
|
@media (pointer: fine) {
|
||||||
a:hover {
|
#intro a:hover {
|
||||||
background: rgba(var(--color-contrast), .1);
|
background-color: rgba(var(--color-contrast), .1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#card a:hover {
|
||||||
|
background-color: rgba(var(--color-contrast), .2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-aspect-ratio: 14/9) and (min-height: 500px) {
|
@media (min-aspect-ratio: 14/9) and (min-height: 450px) {
|
||||||
|
#intro a {
|
||||||
|
width: unset;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(2, 1fr);
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
|
45
public/assets/js/modules/Background.mjs
Normal file
45
public/assets/js/modules/Background.mjs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
export default class Background {
|
||||||
|
constructor(target) {
|
||||||
|
this.images = {
|
||||||
|
dir: "assets/media/b64/",
|
||||||
|
count: 2
|
||||||
|
}
|
||||||
|
|
||||||
|
this.image = null;
|
||||||
|
this.target = target ? target : document.body;
|
||||||
|
|
||||||
|
this.updateBg = setInterval(() => this.randBg(), 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the target CSS background
|
||||||
|
setBg(image = this.image) {
|
||||||
|
this.target.style.setProperty("background-image", `url(${image})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Genrate random int in range
|
||||||
|
randInt(min, max) {
|
||||||
|
return Math.round(Math.random() * (max - min) + min);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch a base64 encoded background image
|
||||||
|
async fetchBg(id) {
|
||||||
|
const url = new URL(window.location);
|
||||||
|
|
||||||
|
url.pathname += this.images.dir;
|
||||||
|
url.pathname += id + ".txt";
|
||||||
|
|
||||||
|
const image = await fetch(url);
|
||||||
|
if(!image.ok) throw new Error("Failed to fetch background image");
|
||||||
|
|
||||||
|
return image.text();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load a random background from the image set
|
||||||
|
async randBg() {
|
||||||
|
const id = this.randInt(1, this.images.count);
|
||||||
|
const image = await this.fetchBg(id);
|
||||||
|
|
||||||
|
this.image = image;
|
||||||
|
this.setBg(image);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
export default class Glitch {
|
import { default as Background } from "./Background.mjs";
|
||||||
constructor(image, target) {
|
|
||||||
this.image = image;
|
export default class Glitch extends Background {
|
||||||
this.target = target ? target : document.body;
|
constructor(target) {
|
||||||
|
super(target);
|
||||||
|
|
||||||
this.interval = {
|
this.interval = {
|
||||||
_this: this,
|
_this: this,
|
||||||
|
@ -13,17 +14,12 @@ export default class Glitch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.interval.next = 2000;
|
this.interval.next = 500;
|
||||||
this.setBackground();
|
this.randBg();
|
||||||
}
|
|
||||||
|
|
||||||
// Update the target CSS background
|
|
||||||
setBackground(image = this.image) {
|
|
||||||
this.target.style.setProperty("background-image", `url(${image})`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate random string of length from charset
|
// Generate random string of length from charset
|
||||||
randomString(length = 2) {
|
randStr(length = 2) {
|
||||||
const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||||
let output = "";
|
let output = "";
|
||||||
for(let i = 0; i < length; i++) {
|
for(let i = 0; i < length; i++) {
|
||||||
|
@ -32,16 +28,10 @@ export default class Glitch {
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Genrate random int in range
|
|
||||||
randomInt(min, max) {
|
|
||||||
return Math.random() * (max - min) + min;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a glitchy image
|
// Create a glitchy image
|
||||||
glitch() {
|
glitch() {
|
||||||
const glitched = this.image.replaceAll(this.randomString(), this.randomString());
|
const image = this.image.replaceAll(this.randStr(), this.randStr());
|
||||||
this.setBackground(glitched);
|
this.setBg(image);
|
||||||
|
this.interval.next = this.randInt(100, 3500);
|
||||||
this.interval.next = this.randomInt(100, 1500);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
1
public/assets/media/b64/1.txt
Executable file
1
public/assets/media/b64/1.txt
Executable file
File diff suppressed because one or more lines are too long
0
public/assets/media/bg64.txt → public/assets/media/b64/2.txt
Executable file → Normal file
0
public/assets/media/bg64.txt → public/assets/media/b64/2.txt
Executable file → Normal file
|
@ -8,30 +8,21 @@
|
||||||
<link rel="icon" href="/assets/media/favicon-dark.png" media="(prefers-color-scheme:no-preference)">
|
<link rel="icon" href="/assets/media/favicon-dark.png" media="(prefers-color-scheme:no-preference)">
|
||||||
<link rel="icon" href="/assets/media/favicon-dark.png" media="(prefers-color-scheme:light)">
|
<link rel="icon" href="/assets/media/favicon-dark.png" media="(prefers-color-scheme:light)">
|
||||||
<link rel="icon" href="/assets/media/favicon-light.png" media="(prefers-color-scheme:dark)">
|
<link rel="icon" href="/assets/media/favicon-light.png" media="(prefers-color-scheme:dark)">
|
||||||
<link rel="stylesheet" href="/assets/css/style.css">
|
|
||||||
<link rel="stylesheet" href="/assets/css/components.css">
|
|
||||||
<style>
|
<style>
|
||||||
main { align-items: center; gap: unset; }
|
html, body { margin: 30px; font-family: monospace; color: black; }
|
||||||
h1 { font-size: clamp(25px,40px,3vw); }
|
span { background: black; color: white; }
|
||||||
.button { margin-top: calc(var(--padding) * 2); }
|
@media (prefers-color-scheme: dark) {
|
||||||
footer { background-color: transparent; }
|
html, body, a { background: black; color: white; }
|
||||||
|
span { background: white; color: black; }
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<h1>there is nothing here</h1>
|
||||||
<p><a href="/">victor westerlund</a></p>
|
<p>and that is all I know</p>
|
||||||
</header>
|
<a href="/"><h2>take me home</h2></a>
|
||||||
<main>
|
|
||||||
<h1>there is nothing here</h1>
|
|
||||||
<p>and that is all I know</p>
|
|
||||||
<a href="/">
|
|
||||||
<div class="button">
|
|
||||||
<p>take me home</p>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</main>
|
|
||||||
<footer>
|
<footer>
|
||||||
<p>404 not found</p>
|
<span>victorwesterlund.com</span>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div id="intro">
|
||||||
<p>hello, my name is</p>
|
<p>hello, my name is</p>
|
||||||
<h1>victor</h1>
|
<h1>victor</h1>
|
||||||
<p>I'm a</p>
|
<p>I'm a</p>
|
||||||
|
@ -23,11 +23,23 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
<div id="card">
|
||||||
|
<img src="https://lh3.googleusercontent.com/a-/AOh14Ggkm-Fr7rjHKeJHKHNOZoM72lARq25kIJS73Wo0SU4=s128-c-rg-br100" alt="portrait of victor"/>
|
||||||
|
<div>
|
||||||
|
<p>I create things with code. When I'm not creating things with code, I enjoy skiing, watching movies and some occasional gaming</p>
|
||||||
|
<p>Beyond computer science, I'm also a armchair rabbit-holer for engineering, astronomy and physics</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h1>☕</h1>
|
||||||
|
<p>...and coffee, full-time</p>
|
||||||
|
</div>
|
||||||
|
<a href="#">stalk me 😬</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import { default as Glitch } from "./assets/js/modules/Glitch.mjs";
|
import { default as Glitch } from "./assets/js/modules/Glitch.mjs";
|
||||||
fetch("assets/media/bg64.txt").then((resp) => resp.text().then(bg64 => new Glitch(bg64, document.body)));
|
//fetch("assets/media/bg64.txt").then((resp) => resp.text().then(bg64 => new Glitch(bg64, document.body)));
|
||||||
|
new Glitch(document.body)
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
50
src/api.php
50
src/api.php
|
@ -1,50 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
class APIRouter {
|
|
||||||
public function __construct($path) {
|
|
||||||
// List of implemented API services
|
|
||||||
$this->services = [
|
|
||||||
"search" => function() {
|
|
||||||
require_once "/search/Search.php";
|
|
||||||
new Search();
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->url = parse_url($path);
|
|
||||||
$this->run();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the requested service by looking at the next URI breadcrumb after "api"
|
|
||||||
private function get_service() {
|
|
||||||
$path = explode("/",$this->url["path"]);
|
|
||||||
|
|
||||||
$service = array_search("api",$path) + 1; // Next array value
|
|
||||||
$service = $path[$service];
|
|
||||||
return $service;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function error($message,$code = 500) {
|
|
||||||
$output = [
|
|
||||||
"ok" => false,
|
|
||||||
"code" => strval($code),
|
|
||||||
"message" => $message
|
|
||||||
];
|
|
||||||
|
|
||||||
header("Content-Type: application/json");
|
|
||||||
http_response_code($code);
|
|
||||||
echo json_encode($output);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run the requested service if it exists in services list
|
|
||||||
private function run() {
|
|
||||||
$service = $this->get_service();
|
|
||||||
if(!array_key_exists($service,$this->services)) {
|
|
||||||
$this->error("Inavlid API");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Import and run requested service
|
|
||||||
$this->services[$service]();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
new APIRouter($_SERVER["REQUEST_URI"]);
|
|
|
@ -1,16 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
class Import {
|
|
||||||
// Import assets from disk
|
|
||||||
public static function file($file) {
|
|
||||||
$content = file_get_contents($file);
|
|
||||||
return $content;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Import JSON to PHP list
|
|
||||||
public static function json($file) {
|
|
||||||
$contents = Import::file($file);
|
|
||||||
$json = json_decode($contents);
|
|
||||||
return $json;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
include_once dirname(__DIR__,1)."/core/Import.php";
|
|
||||||
|
|
||||||
class Database extends mysqli {
|
|
||||||
public function __construct($table) {
|
|
||||||
// Load config file from this directory
|
|
||||||
$config_path = dirname(__FILE__,1)."/config.json";
|
|
||||||
$config = Import::json($config_path);
|
|
||||||
|
|
||||||
parent::__construct();
|
|
||||||
//$this->ssl_set();
|
|
||||||
|
|
||||||
// Attempt to connect to MySQL servers in order (moving to the next on failure)
|
|
||||||
foreach($config->servers as $server) {
|
|
||||||
$db = $this->real_connect($server->host,$server->user,$server->pass,$server->db);
|
|
||||||
if($db) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exit with error code
|
|
||||||
private function error($message) {
|
|
||||||
http_response_code(500);
|
|
||||||
header("Content-Type: application/json");
|
|
||||||
$output = json_encode([
|
|
||||||
"error" => $message
|
|
||||||
]);
|
|
||||||
die($output);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return affected rows as an array of arrays
|
|
||||||
protected function get_rows($sql) {
|
|
||||||
if(!$this->ping()) {
|
|
||||||
$this->error("No database connected");
|
|
||||||
}
|
|
||||||
|
|
||||||
$query = $this->query($sql);
|
|
||||||
|
|
||||||
$rows = [];
|
|
||||||
while($row = $query->fetch_row()) {
|
|
||||||
$rows[] = $row;
|
|
||||||
}
|
|
||||||
return $rows;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"servers": [
|
|
||||||
{
|
|
||||||
"host": "",
|
|
||||||
"user": "",
|
|
||||||
"pass": "",
|
|
||||||
"db": ""
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,87 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require_once dirname(__DIR__,1)."/core/Import.php";
|
|
||||||
require_once dirname(__DIR__,1)."/database/Database.php";
|
|
||||||
|
|
||||||
class Search extends Database {
|
|
||||||
public function __construct() {
|
|
||||||
parent::__construct("search");
|
|
||||||
|
|
||||||
$this->query = $this->real_escape_string($_GET["q"]); // Escape the user-provided query
|
|
||||||
|
|
||||||
// Determine response type from request header or search param
|
|
||||||
$mime_type = $_SERVER["HTTP_CONTENT_TYPE"] ? $_SERVER["HTTP_CONTENT_TYPE"] : $_GET["f"];
|
|
||||||
switch($mime_type) {
|
|
||||||
case "html":
|
|
||||||
case "text/html":
|
|
||||||
$this->get_html();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
case "json":
|
|
||||||
case "application/json":
|
|
||||||
$this->get_json();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perform a seach on the given query and return the results as an array
|
|
||||||
private function get_results() {
|
|
||||||
$sql = "SELECT template,title,content,href FROM `search` WHERE `title` LIKE '%{$this->query}%' OR `content` LIKE '%{$this->query}%'";
|
|
||||||
$rows = $this->get_rows($sql);
|
|
||||||
return $rows;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load HTML template from disk
|
|
||||||
private function get_html_template($name) {
|
|
||||||
$path = dirname(__FILE__,1)."/templates/${name}.html";
|
|
||||||
if(!is_file($path)) {
|
|
||||||
return $this->get_html_template("card_error_display");
|
|
||||||
}
|
|
||||||
$html = Import::file($path);
|
|
||||||
return $html;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return query as HTML from templates
|
|
||||||
private function get_html() {
|
|
||||||
$results = $this->get_results();
|
|
||||||
|
|
||||||
if(count($results) < 1) {
|
|
||||||
$results[] = ["message","info","no results 😞"];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load HTML and format each response from template
|
|
||||||
$results = array_map(function($result) {
|
|
||||||
// Use first row as template name
|
|
||||||
$template = $this->get_html_template($result[0]);
|
|
||||||
// Use remaining rows as format arguments
|
|
||||||
$format = array_shift($result);
|
|
||||||
return sprintf($template,...$result);
|
|
||||||
},$results);
|
|
||||||
|
|
||||||
header("Content-Type: text/html");
|
|
||||||
echo implode("",$results);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return query as JSON
|
|
||||||
private function get_json() {
|
|
||||||
$results = $this->get_results();
|
|
||||||
$data = [
|
|
||||||
"results" => []
|
|
||||||
];
|
|
||||||
|
|
||||||
// Assign custom keys to each value (not db columns)
|
|
||||||
foreach($results as $result) {
|
|
||||||
$data["results"][] = [
|
|
||||||
"html_template" => $result[0],
|
|
||||||
"title" => $result[1],
|
|
||||||
"content" => $result[2],
|
|
||||||
"href" => $result[3]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
$json = json_encode($data);
|
|
||||||
header("Content-Type: application/json");
|
|
||||||
echo $json;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
<div class="card">
|
|
||||||
<div>
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path fill-rule="evenodd" d="M3 2.75A2.75 2.75 0 0 1 5.75 0h14.5a.75.75 0 0 1 .75.75v20.5a.75.75 0 0 1-.75.75h-6a.75.75 0 0 1 0-1.5h5.25v-4H6A1.5 1.5 0 0 0 4.5 18v.75c0 .716.43 1.334 1.05 1.605a.75.75 0 0 1-.6 1.374A3.25 3.25 0 0 1 3 18.75v-16zM19.5 1.5V15H6c-.546 0-1.059.146-1.5.401V2.75c0-.69.56-1.25 1.25-1.25H19.5z" fill="currentColor"/><path d="M7 18.25a.25.25 0 0 1 .25-.25h5a.25.25 0 0 1 .25.25v5.01a.25.25 0 0 1-.397.201l-2.206-1.604a.25.25 0 0 0-.294 0L7.397 23.46a.25.25 0 0 1-.397-.2v-5.01z" fill="currentColor"/></svg>
|
|
||||||
<p>%s</p>
|
|
||||||
</div>
|
|
||||||
<p>%s</p>
|
|
||||||
<p href="%s" class="button">read more</p>
|
|
||||||
</div>
|
|
|
@ -1,4 +0,0 @@
|
||||||
<div class="card error">
|
|
||||||
<p><strong>There was a problem displaying this result</strong></p>
|
|
||||||
<p>This is a problem on my side, sorry about that</p>
|
|
||||||
</div>
|
|
|
@ -1,8 +0,0 @@
|
||||||
<div class="card">
|
|
||||||
<div>
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path fill-rule="evenodd" d="M3 2.75A2.75 2.75 0 0 1 5.75 0h14.5a.75.75 0 0 1 .75.75v20.5a.75.75 0 0 1-.75.75h-6a.75.75 0 0 1 0-1.5h5.25v-4H6A1.5 1.5 0 0 0 4.5 18v.75c0 .716.43 1.334 1.05 1.605a.75.75 0 0 1-.6 1.374A3.25 3.25 0 0 1 3 18.75v-16zM19.5 1.5V15H6c-.546 0-1.059.146-1.5.401V2.75c0-.69.56-1.25 1.25-1.25H19.5z" fill="currentColor"/><path d="M7 18.25a.25.25 0 0 1 .25-.25h5a.25.25 0 0 1 .25.25v5.01a.25.25 0 0 1-.397.201l-2.206-1.604a.25.25 0 0 0-.294 0L7.397 23.46a.25.25 0 0 1-.397-.2v-5.01z" fill="currentColor"/></svg>
|
|
||||||
<p>%s</p>
|
|
||||||
</div>
|
|
||||||
<p>%s</p>
|
|
||||||
<p href="%s" class="button">read more</p>
|
|
||||||
</div>
|
|
|
@ -1 +0,0 @@
|
||||||
<p class="%s">%s</p>
|
|
|
@ -1,5 +0,0 @@
|
||||||
<div class="resultsFooter">
|
|
||||||
<svg id="previous"><polygon points="40,10 0,20 40,30"/></svg>
|
|
||||||
<p>showing %s/%s results<span> (query took %s seconds)</span></p>
|
|
||||||
<svg id="next"><polygon points="0,10 40,20 0,30"/></svg>
|
|
||||||
</div>
|
|
Loading…
Add table
Reference in a new issue