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 {
|
#results > p.error::before {
|
||||||
content: "oh crap, ";
|
content: "😰 ";
|
||||||
font-weight: bold;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
|
|
|
@ -42,18 +42,22 @@ export default class Search {
|
||||||
url.searchParams.set("q",query);
|
url.searchParams.set("q",query);
|
||||||
|
|
||||||
const timeout = new Promise(reject => setTimeout(() => reject("Request timed out"),3000));
|
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]);
|
const result = Promise.race([api,timeout]);
|
||||||
result.then(response => {
|
result.then(response => {
|
||||||
if(!response.ok) {
|
if(!response.ok) {
|
||||||
this.status("something went wrong on my side","error");
|
|
||||||
console.error("Response from server:",response);
|
console.error("Response from server:",response);
|
||||||
return;
|
throw new Error("Invalid response from server");
|
||||||
}
|
}
|
||||||
this.output(response.text);
|
return response.text();
|
||||||
});
|
})
|
||||||
result.catch(error => this.status(error,"error"));
|
.then(html => this.output(html))
|
||||||
|
.catch(error => this.status(error,"error"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait until the user stops typing for a few miliseconds
|
// 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);
|
this.throttle = setTimeout(() => this.search(query),500);
|
||||||
}
|
}
|
||||||
|
|
||||||
async keyEvent(event) {
|
keyEvent(event) {
|
||||||
const query = event.target.value;
|
const query = event.target.value;
|
||||||
if(query.length < 1) {
|
if(query.length < 1) {
|
||||||
|
this.lastQuery = "";
|
||||||
this.status("search results will appear here as you type");
|
this.status("search results will appear here as you type");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,14 +18,6 @@
|
||||||
<input type="text" placeholder="start typing to search..">
|
<input type="text" placeholder="start typing to search..">
|
||||||
</div>
|
</div>
|
||||||
<div id="results">
|
<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>
|
<p>search results will appear here as you type</p>
|
||||||
</div>
|
</div>
|
||||||
<script type="module" src="assets/js/search.js"></script>
|
<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