mirror of
https://codeberg.org/vlw/victorwesterlund.com.git
synced 2025-09-14 11:33:41 +02:00
dev21w43a
This commit is contained in:
parent
7cd3bdb6f4
commit
8f7939aca7
9 changed files with 144 additions and 17 deletions
52
public/api.php
Normal file
52
public/api.php
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
require_once dirname(__DIR__,1)."/src/Globals.php";
|
||||
|
||||
class APIRouter {
|
||||
public function __construct($path) {
|
||||
// List of implemented API services
|
||||
$this->services = [
|
||||
"search" => function() {
|
||||
require_once dirname(__DIR__,1)."/src/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"]);
|
|
@ -69,8 +69,7 @@ header h1 {
|
|||
}
|
||||
|
||||
#results > p.error::before {
|
||||
content: "oh crap, ";
|
||||
font-weight: bold;
|
||||
content: "😰 ";
|
||||
}
|
||||
|
||||
.card {
|
||||
|
|
|
@ -42,18 +42,22 @@ export default class Search {
|
|||
url.searchParams.set("q",query);
|
||||
|
||||
const timeout = new Promise(reject => setTimeout(() => reject("Request timed out"),3000));
|
||||
const api = fetch(url);
|
||||
const api = fetch(url,{
|
||||
headers: {
|
||||
"Content-Type": "text/html"
|
||||
}
|
||||
});
|
||||
|
||||
const result = Promise.race([api,timeout]);
|
||||
result.then(response => {
|
||||
if(!response.ok) {
|
||||
this.status("something went wrong on my side","error");
|
||||
console.error("Response from server:",response);
|
||||
return;
|
||||
throw new Error("Invalid response from server");
|
||||
}
|
||||
this.output(response.text);
|
||||
});
|
||||
result.catch(error => this.status(error,"error"));
|
||||
return response.text();
|
||||
})
|
||||
.then(html => this.output(html))
|
||||
.catch(error => this.status(error,"error"));
|
||||
}
|
||||
|
||||
// Wait until the user stops typing for a few miliseconds
|
||||
|
@ -62,9 +66,10 @@ export default class Search {
|
|||
this.throttle = setTimeout(() => this.search(query),500);
|
||||
}
|
||||
|
||||
async keyEvent(event) {
|
||||
keyEvent(event) {
|
||||
const query = event.target.value;
|
||||
if(query.length < 1) {
|
||||
this.lastQuery = "";
|
||||
this.status("search results will appear here as you type");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -18,14 +18,6 @@
|
|||
<input type="text" placeholder="start typing to search..">
|
||||
</div>
|
||||
<div id="results">
|
||||
<!--<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>github/​victorwesterlund.com</p>
|
||||
</div>
|
||||
<p>Lorem ipsum</p>
|
||||
<p class="button">read more</p>
|
||||
</div>-->
|
||||
<p>search results will appear here as you type</p>
|
||||
</div>
|
||||
<script type="module" src="assets/js/search.js"></script>
|
||||
|
|
14
src/Globals.php
Normal file
14
src/Globals.php
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
class Import {
|
||||
public static function file($file) {
|
||||
$content = file_get_contents($file);
|
||||
return $content;
|
||||
}
|
||||
|
||||
public static function json($file) {
|
||||
$contents = Import::file($file);
|
||||
$json = json_decode($contents);
|
||||
return $json;
|
||||
}
|
||||
}
|
15
src/database/Database.php
Normal file
15
src/database/Database.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
include_once dirname(__DIR__,1)."/Globals.php";
|
||||
|
||||
class Database extends mysqli {
|
||||
public function __construct() {
|
||||
$this->config = Import::json("config.json");
|
||||
}
|
||||
|
||||
private function get_server() {
|
||||
foreach($this->config->servers as $server) {
|
||||
yield $server;
|
||||
}
|
||||
}
|
||||
}
|
10
src/database/config.json
Normal file
10
src/database/config.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"servers": [
|
||||
{
|
||||
"host": "",
|
||||
"user": "",
|
||||
"pass": "",
|
||||
"db": ""
|
||||
}
|
||||
]
|
||||
}
|
32
src/search/Search.php
Normal file
32
src/search/Search.php
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
require_once dirname(__DIR__,1)."/Globals.php";
|
||||
require_once dirname(__DIR__,1)."/database/Database.php";
|
||||
|
||||
class Search extends Database {
|
||||
public function __construct() {
|
||||
$this->query = $query;
|
||||
|
||||
switch($_SERVER["HTTP_CONTENT_TYPE"]) {
|
||||
case "text/html":
|
||||
$this->get_html();
|
||||
break;
|
||||
|
||||
default:
|
||||
case "application/json":
|
||||
$this->get_json();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private function get_html() {
|
||||
header("Content-Type: text/html");
|
||||
$template = Import::file("templates/default.html");
|
||||
echo $template;
|
||||
}
|
||||
|
||||
private function get_json() {
|
||||
header("Content-Type: application/json");
|
||||
echo "{}";
|
||||
}
|
||||
}
|
8
src/search/templates/default.html
Normal file
8
src/search/templates/default.html
Normal file
|
@ -0,0 +1,8 @@
|
|||
<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 class="button">read more</p>
|
||||
</div>
|
Loading…
Add table
Reference in a new issue