2.5.0 commit part 1, whew

This commit is contained in:
are0h 2022-03-19 19:41:02 -07:00
commit 7cefc12692
90 changed files with 5063 additions and 3883 deletions

View file

@ -49,7 +49,7 @@
"no-unsafe-finally": 2,
"no-unsafe-negation": 2,
"no-unused-labels": 2,
"no-unused-vars": 2,
"no-unused-vars": 1,
"no-useless-escape": 1,
"require-yield": 2,
"use-isnan": 2,

7
.prettierignore Normal file
View file

@ -0,0 +1,7 @@
.babelrc
README.md
*.twig
*.sass
*.json
*.php
*.md

17
.prettierrc Normal file
View file

@ -0,0 +1,17 @@
{
"arrowParens": "avoid",
"bracketSpacing": true,
"htmlWhitespaceSensitivity": "css",
"insertPragma": false,
"bracketSameLine": false,
"jsxSingleQuote": true,
"parser": "babel",
"proseWrap": "preserve",
"requirePragma": false,
"semi": true,
"singleQuote": true,
"trailingComma": "none",
"useTabs": true,
"tabWidth": 4,
"printWidth": 90
}

View file

@ -1,48 +0,0 @@
<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
use Slim\Views\Twig;
use Slim\Views\TwigMiddleware;
include "../brain/controller/RouteControl.inc.php";
include "../brain/data/Settings.inc.php";
include "../brain/data/Session.inc.php";
include "../brain/data/Member.inc.php";
include "../brain/data/Auth.inc.php";
include "../brain/data/Render.inc.php";
include "../brain/data/Themes.inc.php";
include "../brain/data/Contents.inc.php";
include "../brain/utility/StringTools.inc.php";
include "../brain/utility/FileUploader.inc.php";
include "../brain/utility/DocTools.inc.php";
include "../brain/utility/Sorting.inc.php";
include "../brain/utility/Setup.inc.php";
include "../brain/utility/Maintenance.inc.php";
include "../brain/utility/Mailer.inc.php";
include "../brain/utility/HandleCors.inc.php";
class App
{
public function __construct()
{
// set up cors
new HandleCors();
$app = AppFactory::create();
$twig = Twig::create("../brain/views/");
$app->add(TwigMiddleware::create($app, $twig));
//set up routing
$app->get(
"/[{first}[/{second}[/{third}[/{fourth}[/{fifth}]]]]]",
"\RouteControl:get"
);
$app->post(
"/[{first}[/{second}[/{third}[/{fourth}]]]]",
"\RouteControl:post"
);
//start the app
$app->run();
}
}

View file

@ -1,74 +0,0 @@
<?php
class AuthAPI
{
public function __construct()
{
}
public static function status()
{
$result = [];
//internal check for admin action
if (Auth::status()) {
$result = [
"message" => "Authorized",
"type" => "apiUseAuthorized",
"token" => Session::get("token"),
];
} else {
$result = [
"message" => "Not Authorized",
"type" => "apiUseNotAuthorized",
];
}
return $result;
}
public static function login($body)
{
$result = [];
switch (Auth::login($body)) {
case "no_name":
$result = [
"message" => "Need to see some id, champ",
"type" => "requestLame",
];
break;
case "bad_pass":
$result = [
"message" => "Check your password, sport",
"type" => "requestLame",
];
break;
default:
$result = [
"message" => "Welcome back",
"type" => "requestGood",
];
break;
}
return $result;
}
public static function logout($body)
{
Auth::logout($body);
$result = [
"message" => "Till next time, g.",
"type" => "TASK_LOGOUT",
];
return $result;
}
public static function requestSecret($body)
{
$result = Auth::findSecret($body);
return $result;
}
public static function resetPassword($body)
{
$result = Auth::makeNewPassword($body);
return $result;
}
}

79
brain/api/v1/AuthAPI.php Normal file
View file

@ -0,0 +1,79 @@
<?php
namespace brain\api\v1;
use brain\data\Auth;
use brain\data\Session;
class AuthAPI
{
public function __construct()
{
}
public static function status()
{
$result = [];
//internal check for admin action
if (Auth::status()) {
$result = [
"message" => "Authorized",
"type" => "apiUseAuthorized",
"token" => Session::get("token"),
];
} else {
$result = [
"message" => "Not Authorized",
"type" => "apiUseNotAuthorized",
];
}
return $result;
}
public static function login($body)
{
$result = [];
switch (Auth::login($body)) {
case "no_name":
$result = [
"message" => "Need to see some id, champ",
"type" => "requestLame",
];
break;
case "bad_pass":
$result = [
"message" => "Check your password, sport",
"type" => "requestLame",
];
break;
default:
$result = [
"message" => "Welcome back",
"type" => "requestGood",
];
break;
}
return $result;
}
public static function logout($body)
{
Auth::logout($body);
$result = [
"message" => "Till next time, g.",
"type" => "TASK_LOGOUT",
];
return $result;
}
public static function requestSecret($body)
{
$result = Auth::findSecret($body);
return $result;
}
public static function resetPassword($body)
{
$result = Auth::makeNewPassword($body);
return $result;
}
}

View file

@ -1,76 +0,0 @@
<?php
class ImagesAPI
{
public function __construct()
{
}
public static function uploadImage($request, $type = null)
{
$file = $request->getUploadedFiles();
$uploadPath = "";
$path = date("Y") . "/" . date("m");
$response = [];
switch ($type) {
case "avatar":
$image = $file["avatar_upload"];
$uploadPath = "../public/assets/images/user/" . $path;
break;
case "background":
$image = $file["background_upload"];
$uploadPath = "../public/assets/images/user/" . $path;
break;
default:
$image = $file["post_image"];
$path = date("Y") . "/" . date("m");
$uploadPath = "../public/assets/images/blog/" . $path;
break;
}
$result = FileUploader::uploadFile($uploadPath, $image);
switch ($type) {
case "avatar":
$response = [
"message" => "Avatar Added. You look great!",
"type" => "avatarUploaded",
"url" =>
"/assets/images/user/" . $path . "/" . $image->getClientFileName(),
];
//update member data
Member::updateData(
"avi",
"/assets/images/user/" . $path . "/" . $image->getClientFileName()
);
break;
case "background":
$response = [
"message" => "Background plugged in. That's nice!",
"type" => "siteBackgroundUploaded",
"url" =>
"/assets/images/user/" . $path . "/" . $image->getClientFileName(),
];
//update settings file
Settings::updateGlobalData(
"background",
"/assets/images/user/" . $path . "/" . $image->getClientFileName()
);
break;
default:
$response = [
"message" => "Image Added. Very slick",
"type" => "postImageAdded",
"url" =>
"/assets/images/blog/" . $path . "/" . $image->getClientFileName(),
];
break;
}
return $response;
}
}

View file

@ -0,0 +1,81 @@
<?php
namespace brain\api\v1;
use brain\data\Member;
use brain\data\Settings;
class ImagesAPI
{
public function __construct()
{
}
public static function uploadImage($request, $type = null)
{
$file = $request->getUploadedFiles();
$uploadPath = "";
$path = date("Y") . "/" . date("m");
$response = [];
switch ($type) {
case "avatar":
$image = $file["avatar_upload"];
$uploadPath = "../public/assets/images/user/" . $path;
break;
case "background":
$image = $file["background_upload"];
$uploadPath = "../public/assets/images/user/" . $path;
break;
default:
$image = $file["post_image"];
$path = date("Y") . "/" . date("m");
$uploadPath = "../public/assets/images/blog/" . $path;
break;
}
$result = FileUploader::uploadFile($uploadPath, $image);
switch ($type) {
case "avatar":
$response = [
"message" => "Avatar Added. You look great!",
"type" => "avatarUploaded",
"url" =>
"/assets/images/user/" . $path . "/" . $image->getClientFileName(),
];
//update member data
Member::updateData(
"avi",
"/assets/images/user/" . $path . "/" . $image->getClientFileName()
);
break;
case "background":
$response = [
"message" => "Background plugged in. That's nice!",
"type" => "siteBackgroundUploaded",
"url" =>
"/assets/images/user/" . $path . "/" . $image->getClientFileName(),
];
//update settings file
Settings::updateGlobalData(
"background",
"/assets/images/user/" . $path . "/" . $image->getClientFileName()
);
break;
default:
$response = [
"message" => "Image Added. Very slick",
"type" => "postImageAdded",
"url" =>
"/assets/images/blog/" . $path . "/" . $image->getClientFileName(),
];
break;
}
return $response;
}
}

View file

@ -1,30 +0,0 @@
<?php
class InitAPI
{
public function __construct()
{
}
public static function handleInitTasks($task, $request)
{
//check if a site config already exists. if it does, deny set up request
//restore to previous version of site while a config exists is only accessible
//through settings.
if (Setup::status()) {
$result = ["type" => "blogInitFail", "message" => "Site already set up"];
} else {
switch ($task) {
case "init":
$result = Setup::init($request);
break;
case "restore":
$result = Setup::restore($request);
break;
}
}
return $result;
}
}

34
brain/api/v1/InitAPI.php Normal file
View file

@ -0,0 +1,34 @@
<?php
namespace brain\api\v1;
use brain\utility\Setup;
class InitAPI
{
public function __construct()
{
}
public static function handleInitTasks($task, $request)
{
//check if a site config already exists. if it does, deny set up request
//restore to previous version of site while a config exists is only accessible
//through settings.
if (Setup::status()) {
$result = ["type" => "blogInitFail", "message" => "Site already set up"];
} else {
switch ($task) {
case "init":
$result = Setup::init($request);
break;
case "restore":
$result = Setup::restore($request);
break;
}
}
return $result;
}
}

View file

@ -1,26 +0,0 @@
<?php
class MailerAPI
{
public function __construct()
{
}
public static function handleMail($request, $body, $response)
{
//if testing, verify session is active
if ($body["mail_task"] == "TESTING") {
if (Session::active()) {
$result = Mailer::sendmail($body);
} else {
$result = [
"message" => "You need to be logged in for this, champ.",
"type" => "MAILER_ERROR",
];
}
} else {
}
return $result;
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace brain\api\v1;
use brain\data\Session;
use brain\utility\Mailer;
class MailerAPI
{
public function __construct()
{
}
public static function handleMail($request, $body, $response)
{
//if testing, verify session is active
if ($body["mail_task"] == "TESTING") {
if (Session::active()) {
$result = Mailer::sendmail($body);
} else {
$result = [
"message" => "You need to be logged in for this, champ.",
"type" => "MAILER_ERROR",
];
}
} else {
}
return $result;
}
}

View file

@ -1,171 +0,0 @@
<?php
use function _\filter;
use Mni\FrontYAML\Parser;
class PagesAPI
{
public function __construct()
{
}
public static function getPageContent($request, $args)
{
$task = $args["fourth"];
$pages = (new Book("../content/pages"))->getContents();
$content = [];
foreach ($pages as $page) {
$entry = [
"id" => $page["id"],
"uuid" => $page["uuid"],
"title" => $page["title"],
"feature" => $page["feature"],
"path" => $page["path"],
"layout" => $page["layout"],
"tags" => $page["tags"],
"author" => $page["author"],
"created" => $page["created"],
"updated" => $page["updated"],
"deleted" => $page["deleted"],
"menu" => $page["menu"],
"featured" => $page["featured"],
"published" => $page["published"],
"slug" => $page["slug"],
"content" => StringTools::sanitizeContent($page["content"]),
];
array_push($content, $entry);
}
switch ($task) {
case "published":
$published = filter($content, function ($item) {
return $item["published"] == true && $item["deleted"] == false;
});
$result = ["pages" => $published, "totalItems" => count($published)];
break;
case "featured":
$featured = filter($content, function ($item) {
return $item["featured"] == true && $item["deleted"] == false;
});
$result = [
"pages" => $featured,
"totalItems" => count($featured),
];
break;
case "menu":
$menu = filter($content, function ($item) {
return $item["menu"] == true && $item["deleted"] == false;
});
$result = ["pages" => $menu, "totalItems" => count($menu)];
break;
case "single":
$uuid = $args["fifth"];
$page = (new Book("../content/pages"))->findPageById($uuid);
$entry = [
"id" => $page["id"],
"uuid" => $page["uuid"],
"title" => $page["title"],
"feature" => $page["feature"],
"path" => $page["path"],
"layout" => $page["layout"],
"tags" => $page["tags"],
"author" => $page["author"],
"created" => $page["created"],
"updated" => $page["updated"],
"deleted" => $page["deleted"],
"menu" => $page["menu"],
"featured" => $page["featured"],
"published" => $page["published"],
"slug" => $page["slug"],
"content" => StringTools::sanitizeContent($page["content"]),
];
$result = $entry;
break;
case "tags":
$result = Settings::getTags();
break;
default:
$result = [
"message" => "Hm, no task. That's unfortunate",
"type" => "TASK_NONE",
];
break;
}
return $result;
}
public static function handlePageTask($request, $args)
{
$task = $args["fourth"];
switch ($task) {
case "delete":
case "create":
case "write":
$body = $request->getParsedBody();
$passed = true;
if (!isset($body["form_token"])) {
$result = [
"message" => "No form token. Not good, sport.",
"type" => "TASK_FORM_AUTH",
];
} else {
if ($body["form_token"] == Session::get("form_token")) {
//TODO: Verify form fields
$keys = [
"id",
"uuid",
"layout",
"current_title",
"content",
"title",
"created",
"slug",
"tags",
"menu",
"featured",
"published",
"form_token",
"feature_image",
];
foreach ($body as $key => $item) {
if (!in_array($key, $keys)) {
//found unnecessary key, so reject submission
$passed = false;
}
}
if ($passed) {
$result = (new Book())->editPage($task, $request);
} else {
$result = [
"message" =>
"Unneccessary key found. Post not authorized, slick.",
"type" => "TASK_FORM_AUTH",
];
}
} else {
$result = [
"message" => "Form token, auth failed. Uh oh.",
"type" => "TASK_FORM_AUTH",
];
}
}
break;
case "add-entry-image":
$result = ImagesAPI::uploadImage($request);
break;
default:
$result = [
"message" => "Hm, no task. That's unfortunate",
"type" => "TASK_NONE",
];
break;
}
return $result;
}
}

180
brain/api/v1/PagesAPI.php Normal file
View file

@ -0,0 +1,180 @@
<?php
namespace brain\api\v1;
use Mni\FrontYAML\Parser;
use brain\api\v1\ImagesAPI;
use brain\data\Book;
use brain\data\Settings;
use brain\data\Session;
use brain\utility\StringTools;
use function _\filter;
class PagesAPI
{
public function __construct()
{
}
public static function getPageContent($request, $args)
{
$task = $args["fourth"];
$pages = (new Book("../content/pages"))->getContents();
$content = [];
foreach ($pages as $page) {
$entry = [
"id" => $page["id"],
"uuid" => $page["uuid"],
"title" => $page["title"],
"feature" => $page["feature"],
"path" => $page["path"],
"layout" => $page["layout"],
"tags" => $page["tags"],
"author" => $page["author"],
"created" => $page["created"],
"updated" => $page["updated"],
"deleted" => $page["deleted"],
"menu" => $page["menu"],
"featured" => $page["featured"],
"published" => $page["published"],
"slug" => $page["slug"],
"content" => StringTools::sanitizeContent($page["content"]),
];
array_push($content, $entry);
}
switch ($task) {
case "published":
$published = filter($content, function ($item) {
return $item["published"] == true && $item["deleted"] == false;
});
$result = ["pages" => $published, "totalItems" => count($published)];
break;
case "featured":
$featured = filter($content, function ($item) {
return $item["featured"] == true && $item["deleted"] == false;
});
$result = [
"pages" => $featured,
"totalItems" => count($featured),
];
break;
case "menu":
$menu = filter($content, function ($item) {
return $item["menu"] == true && $item["deleted"] == false;
});
$result = ["pages" => $menu, "totalItems" => count($menu)];
break;
case "single":
$uuid = $args["fifth"];
$page = (new Book("../content/pages"))->findPageById($uuid);
$entry = [
"id" => $page["id"],
"uuid" => $page["uuid"],
"title" => $page["title"],
"feature" => $page["feature"],
"path" => $page["path"],
"layout" => $page["layout"],
"tags" => $page["tags"],
"author" => $page["author"],
"created" => $page["created"],
"updated" => $page["updated"],
"deleted" => $page["deleted"],
"menu" => $page["menu"],
"featured" => $page["featured"],
"published" => $page["published"],
"slug" => $page["slug"],
"content" => StringTools::sanitizeContent($page["content"]),
];
$result = $entry;
break;
case "tags":
$result = Settings::getTags();
break;
default:
$result = [
"message" => "Hm, no task. That's unfortunate",
"type" => "TASK_NONE",
];
break;
}
return $result;
}
public static function handlePageTask($request, $args)
{
$task = $args["fourth"];
switch ($task) {
case "delete":
case "create":
case "write":
$body = $request->getParsedBody();
$passed = true;
if (!isset($body["form_token"])) {
$result = [
"message" => "No form token. Not good, sport.",
"type" => "TASK_FORM_AUTH",
];
} else {
if ($body["form_token"] == Session::get("form_token")) {
//TODO: Verify form fields
$keys = [
"id",
"uuid",
"layout",
"current_title",
"content",
"title",
"created",
"slug",
"tags",
"menu",
"featured",
"published",
"form_token",
"feature_image",
];
foreach ($body as $key => $item) {
if (!in_array($key, $keys)) {
//found unnecessary key, so reject submission
$passed = false;
}
}
if ($passed) {
$result = (new Book())->editPage($task, $request);
} else {
$result = [
"message" =>
"Unneccessary key found. Post not authorized, slick.",
"type" => "TASK_FORM_AUTH",
];
}
} else {
$result = [
"message" => "Form token, auth failed. Uh oh.",
"type" => "TASK_FORM_AUTH",
];
}
}
break;
case "add-entry-image":
$result = ImagesAPI::uploadImage($request);
break;
default:
$result = [
"message" => "Hm, no task. That's unfortunate",
"type" => "TASK_NONE",
];
break;
}
return $result;
}
}

View file

@ -1,147 +0,0 @@
<?php
use Slim\Views\Twig;
class SettingsAPI
{
public function __construct()
{
}
public static function handleSettingsTask($request, $args, $body = null)
{
$task = $args["fourth"];
switch ($task) {
case "publish":
//check settings to see if site is a one pager
$config = new Settings();
$settings = $config->getSettings();
$theme = $settings["global"]["theme"];
$themeConfig = json_decode(
file_get_contents("../content/themes/" . $theme . "/theme.json"),
true
);
//check to see if dynamic rendering is active
if (
isset($settings["global"]["dynamicRender"]) &&
$settings["global"]["dynamicRender"] === "true"
) {
$result = [
"message" => "Dynamic Render Active! You're good!",
"type" => "RENDER_SUCCESS",
];
} else {
$render = new Render();
if (isset($themeConfig["render"])) {
if (!$themeConfig["render"] || $themeConfig["render"] === "false") {
$render->renderIndex();
$result = [
"message" => "Index Rendered. HAND CLAPS",
"type" => "RENDER_SUCCESS",
];
} else {
$render->renderTags();
$render->renderArchive();
$render->renderPages();
$result = [
"message" => "Site Rendered. GOOD EFFORT",
"type" => "RENDER_SUCCESS",
];
}
} else {
// just incase the render flag is missing
$render->renderTags();
$render->renderArchive();
$render->renderPages();
$result = [
"message" => "Site Rendered. GOOD EFFORT",
"type" => "RENDER_SUCCESS",
];
}
}
//if render flag is set and false, just render index page for one page sites
//otherwise, render all pages according to theme template files
break;
case "add-avatar":
$result = ImagesAPI::uploadImage($request, "avatar");
break;
case "add-feature-background":
$result = ImagesAPI::uploadImage($request, "background");
break;
case "sync":
Settings::sync($body);
$result = [
"message" => "Settings Synced. You're doing great!",
"type" => "settingsUpdated",
];
break;
case "nav-sync":
Settings::navSync($body);
$result = [
"message" => "Navigation updated. Very slick!",
"type" => "menuUpdated",
];
break;
default:
$result = [
"message" => "Hm, no task. That's unfortunate",
"type" => "TASK_NONE",
];
break;
}
return $result;
}
public static function getInfo($request, $args)
{
$task = $args["fourth"];
switch ($task) {
case "site":
$config = new Settings();
$settings = $config->getSettings();
$data = [
"title" => $settings["global"]["title"],
"base_url" => $settings["global"]["base_url"],
"description" => $settings["global"]["descriptions"],
];
$result = [
"message" => "Settings Found",
"type" => "GET_SETTINGS",
"data" => $data,
];
break;
case "member":
if (Session::active()) {
$member = $member = Session::get("member");
$data = ["handle" => $member["handle"], "email" => $member["email"]];
$result = [
"message" => "Member Info Found",
"type" => "GET_MEMBER_INFO",
"data" => $data,
];
} else {
$result = [
"message" => "Not logged in. C'mon, bruh",
"type" => "TASK_NONE",
];
}
break;
default:
$result = [
"message" => "No Settings found. Frowny Face",
"type" => "TASK_NONE",
];
break;
}
return $result;
}
public static function createBackup()
{
$result = Maintenance::makeBackup();
return $result;
}
}

View file

@ -0,0 +1,154 @@
<?php
namespace brain\api\v1;
use Slim\Views\Twig;
use brain\api\v1\ImagesApi;
use brain\data\Render;
use brain\data\Settings;
use brain\data\Session;
use brain\utility\Maintenance;
class SettingsAPI
{
public function __construct()
{
}
public static function handleSettingsTask($request, $args, $body = null)
{
$task = $args["fourth"];
switch ($task) {
case "publish":
//check settings to see if site is a one pager
$config = new Settings();
$settings = $config->getSettings();
$theme = $settings["global"]["theme"];
$themeConfig = json_decode(
file_get_contents("../content/themes/" . $theme . "/theme.json"),
true
);
//check to see if dynamic rendering is active
if (
isset($settings["global"]["dynamicRender"]) &&
$settings["global"]["dynamicRender"] === "true"
) {
$result = [
"message" => "Dynamic Render Active! You're good!",
"type" => "RENDER_SUCCESS",
];
} else {
$render = new Render();
if (isset($themeConfig["render"])) {
if (!$themeConfig["render"] || $themeConfig["render"] === "false") {
$render->renderIndex();
$result = [
"message" => "Index Rendered. HAND CLAPS",
"type" => "RENDER_SUCCESS",
];
} else {
$render->renderTags();
$render->renderArchive();
$render->renderPages();
$result = [
"message" => "Site Rendered. GOOD EFFORT",
"type" => "RENDER_SUCCESS",
];
}
} else {
// just incase the render flag is missing
$render->renderTags();
$render->renderArchive();
$render->renderPages();
$result = [
"message" => "Site Rendered. GOOD EFFORT",
"type" => "RENDER_SUCCESS",
];
}
}
//if render flag is set and false, just render index page for one page sites
//otherwise, render all pages according to theme template files
break;
case "add-avatar":
$result = ImagesAPI::uploadImage($request, "avatar");
break;
case "add-feature-background":
$result = ImagesAPI::uploadImage($request, "background");
break;
case "sync":
Settings::sync($body);
$result = [
"message" => "Settings Synced. You're doing great!",
"type" => "settingsUpdated",
];
break;
case "nav-sync":
Settings::navSync($body);
$result = [
"message" => "Navigation updated. Very slick!",
"type" => "menuUpdated",
];
break;
default:
$result = [
"message" => "Hm, no task. That's unfortunate",
"type" => "TASK_NONE",
];
break;
}
return $result;
}
public static function getInfo($request, $args)
{
$task = $args["fourth"];
switch ($task) {
case "site":
$config = new Settings();
$settings = $config->getSettings();
$data = [
"title" => $settings["global"]["title"],
"base_url" => $settings["global"]["base_url"],
"description" => $settings["global"]["descriptions"],
];
$result = [
"message" => "Settings Found",
"type" => "GET_SETTINGS",
"data" => $data,
];
break;
case "member":
if (Session::active()) {
$member = $member = Session::get("member");
$data = ["handle" => $member["handle"], "email" => $member["email"]];
$result = [
"message" => "Member Info Found",
"type" => "GET_MEMBER_INFO",
"data" => $data,
];
} else {
$result = [
"message" => "Not logged in. C'mon, bruh",
"type" => "TASK_NONE",
];
}
break;
default:
$result = [
"message" => "No Settings found. Frowny Face",
"type" => "TASK_NONE",
];
break;
}
return $result;
}
public static function createBackup()
{
$result = Maintenance::makeBackup();
return $result;
}
}

View file

@ -1,227 +0,0 @@
<?php
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
include "../brain/api/v1/AuthAPI.inc.php";
include "../brain/api/v1/ImagesAPI.inc.php";
include "../brain/api/v1/PagesAPI.inc.php";
include "../brain/api/v1/SettingsAPI.inc.php";
include "../brain/api/v1/InitAPI.inc.php";
include "../brain/api/v1/MailerAPI.inc.php";
class APIControl
{
public static function get(
ServerRequestInterface $request,
ResponseInterface $response,
array $args
): ResponseInterface {
$filename = "";
switch (isset($args["third"]) ? $args["third"] : "none") {
case "status":
$result = AuthAPI::status();
break;
case "page":
//echo
if (Member::verifyKey($_GET["key"])) {
$result = PagesAPI::getPageContent($request, $args);
} else {
$result = [
"message" => "API access denied, homie",
"type" => "API_ERROR",
];
}
break;
case "settings":
$token = $request->getHeader("fipamo-access-token");
//Verify token to get site info
if (isset($token[0])) {
if (Session::verifyToken($token[0])) {
$result = SettingsAPI::getInfo($request, $args);
} else {
$result = [
"message" => "Invalid token, API access denied, homie",
"type" => "API_ERROR",
];
}
} else {
$result = [
"message" => "No token, API access denied, homie",
"type" => "API_ERROR",
];
}
break;
case "files":
if (Session::active()) {
if ($args["third"] == "backup") {
$filename = "../config/backups/latest_backup.zip";
if (file_exists($filename)) {
header("Content-Type: application/zip");
header(
'Content-Disposition: attachment; filename="' .
basename($filename) .
'"'
);
header("Content-Length: " . filesize($filename));
flush();
// return readfile($filename);
//readfile($filename);
// delete file
//unlink($filename);
}
}
} else {
$result = [
"message" => "API access denied, homie",
"type" => "API_ERROR",
];
}
default:
break;
}
$freshResponse = $response;
if ($args["third"] == "files") {
$freshResponse
->getBody()
->write(file_get_contents("../config/backups/latest_back.zip"));
$freshResponse->withHeader("Content-Type", "application/zip");
return $freshResponse->withAddedHeader(
"Content-Disposition",
"attachment; filename=latest_backup.zip"
);
} else {
$response->getBody()->write(json_encode($result));
return $response->withHeader("Content-Type", "application/json");
}
}
public static function post(
ServerRequestInterface $request,
ResponseInterface $response,
array $args
): ResponseInterface {
$contentType = $request->getHeader("Content-Type");
switch ($contentType[0]) {
case "application/json":
$body = json_decode(file_get_contents("php://input"), true);
break;
default:
break;
}
switch (isset($args["third"]) ? $args["third"] : "none") {
case "restore": //move to 'api/auth'
case "init": //move to 'api/auth'
$task = $args["third"];
$result = InitApi::handleInitTasks(
$task,
$task == "init" ? $body : $request
);
break;
case "backup": //move to 'api/auth'
$token = $request->getHeader("fipamo-access-token");
//Verify token for admin tasks
$result = SettingsAPI::createBackup();
/*
if (Session::verifyToken($token[0])) {
$result = SettingsAPI::createBackup();
} else {
$result = [
"message" => "API access denied, homie",
"type" => "API_ERROR",
];
}
*/
break;
case "login": //move to 'api/auth'
//check if request is remote and if so, verify token
if ($body["remote"] || $body["remote"] == "true") {
if (Member::verifyKey($body["key"])) {
$result = AuthAPI::login($body);
} else {
$result = [
"message" => "API access denied, homie",
"type" => "API_ERROR",
];
}
} else {
//request is local, so it's cool
$result = AuthAPI::login($body);
}
break;
case "logout": //move to 'api/auth'
$result = AuthAPI::logout($body);
break;
case "get-secret": //move to 'api/auth'
$result = AuthAPI::requestSecret($body);
break;
case "reset-password": //move to 'api/auth'
$result = AuthAPI::resetPassword($body);
break;
case "page":
$token = $request->getHeader("fipamo-access-token");
//Verify token for admin tasks
if (isset($token[0])) {
if (Session::verifyToken($token[0])) {
$result = PagesAPI::handlePageTask($request, $args);
} else {
$result = [
"message" => "Invalid token, API access denied, homie",
"type" => "API_ERROR",
];
}
} else {
$result = [
"message" => "No token, API access denied, homie",
"type" => "API_ERROR",
];
}
break;
case "settings":
if (isset($body)) {
$postBody = $body;
} else {
$postBody = null;
}
$task = $args["fourth"];
if ($task == "add-feature-background" || $task == "add-avatar") {
$result = SettingsAPI::handleSettingsTask($request, $args, $postBody);
} else {
$token = $request->getHeader("fipamo-access-token");
if (Session::verifyToken($token[0])) {
$result = SettingsAPI::handleSettingsTask(
$request,
$args,
$postBody
);
} else {
$result = [
"message" => "API access denied, homie",
"type" => "API_ERROR",
];
}
}
break;
case "mailer":
$result = MailerAPI::handleMail($request, $body, $response);
break;
default:
$result = [
"message" => "Oh, nothing to do. That's unfortunate",
"type" => "TASK_NONE",
];
break;
}
$response->getBody()->write(json_encode($result));
return $response->withHeader("Content-Type", "application/json");
}
}

View file

@ -0,0 +1,232 @@
<?php
namespace brain\controller;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use brain\api\v1\AuthAPI;
use brain\api\v1\ImagesAPI;
use brain\api\v1\PagesAPI;
use brain\api\v1\SettingsAPI;
use brain\api\v1\InitAPI;
use brain\api\v1\MailerAPI;
use brain\data\Member;
use brain\data\Session;
class APIControl
{
public static function get(
ServerRequestInterface $request,
ResponseInterface $response,
array $args
): ResponseInterface {
$filename = "";
switch (isset($args["third"]) ? $args["third"] : "none") {
case "status":
$result = AuthAPI::status();
break;
case "page":
//echo
if (Member::verifyKey($_GET["key"])) {
$result = PagesAPI::getPageContent($request, $args);
} else {
$result = [
"message" => "API access denied, homie",
"type" => "API_ERROR",
];
}
break;
case "settings":
$token = $request->getHeader("fipamo-access-token");
//Verify token to get site info
if (isset($token[0])) {
if (Session::verifyToken($token[0])) {
$result = SettingsAPI::getInfo($request, $args);
} else {
$result = [
"message" => "Invalid token, API access denied, homie",
"type" => "API_ERROR",
];
}
} else {
$result = [
"message" => "No token, API access denied, homie",
"type" => "API_ERROR",
];
}
break;
case "files":
if (Session::active()) {
if ($args["third"] == "backup") {
$filename = "../config/backups/latest_backup.zip";
if (file_exists($filename)) {
header("Content-Type: application/zip");
header(
'Content-Disposition: attachment; filename="' .
basename($filename) .
'"'
);
header("Content-Length: " . filesize($filename));
flush();
// return readfile($filename);
//readfile($filename);
// delete file
//unlink($filename);
}
}
} else {
$result = [
"message" => "API access denied, homie",
"type" => "API_ERROR",
];
}
// no break
default:
break;
}
$freshResponse = $response;
if ($args["third"] == "files") {
$freshResponse
->getBody()
->write(file_get_contents("../config/backups/latest_back.zip"));
$freshResponse->withHeader("Content-Type", "application/zip");
return $freshResponse->withAddedHeader(
"Content-Disposition",
"attachment; filename=latest_backup.zip"
);
} else {
$response->getBody()->write(json_encode($result));
return $response->withHeader("Content-Type", "application/json");
}
}
public static function post(
ServerRequestInterface $request,
ResponseInterface $response,
array $args
): ResponseInterface {
$contentType = $request->getHeader("Content-Type");
switch ($contentType[0]) {
case "application/json":
$body = json_decode(file_get_contents("php://input"), true);
break;
default:
break;
}
switch (isset($args["third"]) ? $args["third"] : "none") {
case "restore": //move to 'api/auth'
case "init": //move to 'api/auth'
$task = $args["third"];
$result = InitApi::handleInitTasks(
$task,
$task == "init" ? $body : $request
);
break;
case "backup": //move to 'api/auth'
$token = $request->getHeader("fipamo-access-token");
//Verify token for admin tasks
$result = SettingsAPI::createBackup();
/*
if (Session::verifyToken($token[0])) {
$result = SettingsAPI::createBackup();
} else {
$result = [
"message" => "API access denied, homie",
"type" => "API_ERROR",
];
}
*/
break;
case "login": //move to 'api/auth'
//check if request is remote and if so, verify token
if ($body["remote"] || $body["remote"] == "true") {
if (Member::verifyKey($body["key"])) {
$result = AuthAPI::login($body);
} else {
$result = [
"message" => "API access denied, homie",
"type" => "API_ERROR",
];
}
} else {
//request is local, so it's cool
$result = AuthAPI::login($body);
}
break;
case "logout": //move to 'api/auth'
$result = AuthAPI::logout($body);
break;
case "get-secret": //move to 'api/auth'
$result = AuthAPI::requestSecret($body);
break;
case "reset-password": //move to 'api/auth'
$result = AuthAPI::resetPassword($body);
break;
case "page":
$token = $request->getHeader("fipamo-access-token");
//Verify token for admin tasks
if (isset($token[0])) {
if (Session::verifyToken($token[0])) {
$result = PagesAPI::handlePageTask($request, $args);
} else {
$result = [
"message" => "Invalid token, API access denied, homie",
"type" => "API_ERROR",
];
}
} else {
$result = [
"message" => "No token, API access denied, homie",
"type" => "API_ERROR",
];
}
break;
case "settings":
if (isset($body)) {
$postBody = $body;
} else {
$postBody = null;
}
$task = $args["fourth"];
if ($task == "add-feature-background" || $task == "add-avatar") {
$result = SettingsAPI::handleSettingsTask($request, $args, $postBody);
} else {
$token = $request->getHeader("fipamo-access-token");
if (Session::verifyToken($token[0])) {
$result = SettingsAPI::handleSettingsTask(
$request,
$args,
$postBody
);
} else {
$result = [
"message" => "API access denied, homie",
"type" => "API_ERROR",
];
}
}
break;
case "mailer":
$result = MailerAPI::handleMail($request, $body, $response);
break;
default:
$result = [
"message" => "Oh, nothing to do. That's unfortunate",
"type" => "TASK_NONE",
];
break;
}
$response->getBody()->write(json_encode($result));
return $response->withHeader("Content-Type", "application/json");
}
}

View file

@ -1,189 +0,0 @@
<?php
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Views\Twig;
include "../brain/data/Book.inc.php";
class DashControl
{
public static function start(
ServerRequestInterface $request,
ResponseInterface $response,
array $args
): ResponseInterface {
$view = Twig::fromRequest($request);
$pageOptions = [];
$template = "";
if (Setup::status()) {
switch (isset($args["second"]) ? $args["second"] : "index") {
case "settings":
if (Session::active()) {
$config = new Settings();
$settings = $config->getSettings();
$themes = (new Themes())->getThemes(); //$config->getThemes();
$template = "dash/settings.twig";
$member = Session::get("member");
$form_token = Session::get("form_token");
$updated = new \Moment\Moment($settings["global"]["last_backup"]);
$pageOptions = [
"title" => "Dash Settings",
"private" => $settings["global"]["private"],
"renderOnSave" => $settings["global"]["renderOnSave"],
"background" => $settings["global"]["background"],
"member" => $member,
"ftoken" => $form_token,
"siteTitle" => $settings["global"]["title"],
"baseUrl" => $settings["global"]["base_url"],
"desc" => $settings["global"]["descriptions"],
"lastBackup" => $updated->format("Y M D d"),
"currentTheme" => $settings["global"]["theme"],
"themes" => $themes,
"apiStatus" => isset($settings["global"]["externalAPI"])
? $settings["global"]["externalAPI"]
: "false",
"dynamicRenderStatus" => isset(
$settings["global"]["dynamicRender"]
)
? $settings["global"]["dynamicRender"]
: "false",
"mailOption" => $settings["email"]["active"],
"mailConfig" => $settings["email"],
"status" => Session::active(),
];
} else {
header("Location: /dashboard");
die();
}
break;
case "navigation":
if (Session::active()) {
$config = new Settings();
$settings = $config->getSettings();
$template = "dash/navigation.twig";
$pageOptions = [
"title" => "Edit Dash Navigation",
"status" => Session::active(),
"menu" => $settings["menu"],
];
} else {
header("Location: /dashboard");
die();
}
break;
case "pages":
if (Session::active()) {
$currentPage = isset($args["fourth"]) ? $args["fourth"] : 1;
$filter = isset($args["third"]) ? $args["third"] : "all";
$data = (new Book())->getPages($currentPage, 4, $filter);
$template = "dash/book.twig";
$pageOptions = [
"entryCount" => $data["entryCount"],
"numOfPages" => $data["numOfPages"],
"currentPage" => $currentPage,
"filter" => $data["paginate"]["sort"],
"stats" => $data["stats"],
"pages" => $data["pages"],
"paginate" => $data["paginate"],
"status" => Session::active(),
];
} else {
header("Location: /dashboard");
die();
}
break;
case "page":
if (Session::active()) {
$template = "dash/page-edit.twig";
$mode = $args["third"];
$uuid = $args["fourth"];
switch ($mode) {
case "edit":
$page = (new Book())->findPageById($uuid);
$views = [];
if (str_contains($page["layout"], "index")) {
$views = (new Themes())->getCustomIndex();
} else {
$views = (new Themes())->getCustomViews();
}
$pageOptions = [
"title" => "Fipamo | Edit Page",
"page" => $page,
"mode" => $mode,
"token" => Session::get("form_token"),
"status" => Session::active(),
"views" => $views,
];
break;
case "preview":
$config = new Settings();
$settings = $config->getSettings();
$loader = new \Twig\Loader\FilesystemLoader(
"../content/themes"
);
$display = new \Twig\Environment($loader, []);
$book = new Book();
$page = $book->findPageById($uuid);
$pageOptions = Sorting::page($page);
$preview =
$settings["global"]["theme"] .
"/" .
$page["layout"] .
".twig";
$html = $display->render($preview, $pageOptions);
$response->getBody()->write($html);
return $response;
break;
default:
$pageOptions = [
"title" => "Fipamo | Create Page",
"token" => Session::get("form_token"),
"mode" => $mode,
"status" => Session::active(),
];
break;
}
} else {
header("Location: /dashboard");
die();
}
break;
case "logout":
Session::kill();
header("Location: /dashboard");
die();
break;
case "reset-password":
$template = "dash/reset-password.twig";
$pageOptions = [
"title" => "Reset Password",
];
break;
default:
$template = "dash/start.twig";
if (Session::active()) {
$pageOptions = [
"title" => "Welcome Back",
"status" => Session::active(),
"data" => (new Book())->getPages(1, 4),
];
} else {
$pageOptions = [
"title" => "Welcome to Fipamo",
"status" => Session::active(),
];
}
break;
}
} else {
$template = "dash/init.twig";
$pageOptions = ["title" => "Fipamo Setup"];
}
return $view->render($response, $template, $pageOptions);
}
}

View file

@ -0,0 +1,218 @@
<?php
namespace brain\controller;
use brain\data\Book;
use brain\data\Session;
use brain\data\Settings;
use brain\data\Themes;
use brain\utility\Setup;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Views\Twig;
class DashControl
{
public static function start(
ServerRequestInterface $request,
ResponseInterface $response,
array $args
): ResponseInterface {
$view = Twig::fromRequest($request);
$pageOptions = [];
$template = '';
if (Setup::status()) {
switch (isset($args['second']) ? $args['second'] : 'index') {
case 'settings':
if (Session::active()) {
$config = new Settings();
$settings = $config->getSettings();
$themes = (new Themes())->getThemes(); // $config->getThemes();
$template = 'dash/settings.twig';
$member = Session::get('member');
$form_token = Session::get('form_token');
$updated = new \Moment\Moment($settings['global']['last_backup']);
$pageOptions = [
'title' => 'Dash Settings',
'private' => $settings['global']['private'],
'renderOnSave' => $settings['global']['renderOnSave'],
'background' => $settings['global']['background'],
'member' => $member,
'ftoken' => $form_token,
'siteTitle' => $settings['global']['title'],
'baseUrl' => $settings['global']['base_url'],
'desc' => $settings['global']['descriptions'],
'lastBackup' => $updated->format('Y M D d'),
'currentTheme' => $settings['global']['theme'],
'themes' => $themes,
'apiStatus' => isset($settings['global']['externalAPI'])
? $settings['global']['externalAPI']
: 'false',
'dynamicRenderStatus' => isset(
$settings['global']['dynamicRender']
)
? $settings['global']['dynamicRender']
: 'false',
'mailOption' => $settings['email']['active'],
'mailConfig' => $settings['email'],
'status' => Session::active(),
];
} else {
header('Location: /dashboard');
exit();
}
break;
case 'navigation':
if (Session::active()) {
$config = new Settings();
$settings = $config->getSettings();
$template = 'dash/navigation.twig';
$pageOptions = [
'title' => 'Edit Dash Navigation',
'status' => Session::active(),
'menu' => $settings['menu'],
];
} else {
header('Location: /dashboard');
exit();
}
break;
case 'pages':
if (Session::active()) {
$currentPage = isset($args['fourth']) ? $args['fourth'] : 1;
$filter = isset($args['third']) ? $args['third'] : 'all';
$data = (new Book())->getPages($currentPage, 4, $filter);
$template = 'dash/book.twig';
$pageOptions = [
'title' => 'Contents',
'entryCount' => $data['entryCount'],
'numOfPages' => $data['numOfPages'],
'currentPage' => $currentPage,
'filter' => $data['paginate']['sort'],
'stats' => $data['stats'],
'pages' => $data['pages'],
'paginate' => $data['paginate'],
'status' => Session::active(),
];
} else {
header('Location: /dashboard');
exit();
}
break;
case 'page':
if (Session::active()) {
$template = 'dash/page-edit.twig';
$mode = $args['third'];
$uuid = $args['fourth'];
switch ($mode) {
case 'edit':
$page = (new Book())->findPageById($uuid);
$views = [];
if (str_contains($page['layout'], 'index')) {
$views = (new Themes())->getCustomIndex();
} else {
$views = (new Themes())->getCustomViews();
}
$imageList = explode(',', $page['feature']);
$fileList = explode(',', $page['files']);
$images = [];
$files = [];
foreach ($imageList as $item) {
$image = trim($item);
if (!empty($image)) {
array_push($images, $image);
}
}
foreach ($fileList as $item) {
$file = trim($item);
if (!empty($file)) {
array_push($files, $file);
}
}
$pageOptions = [
'title' => 'Fipamo | Edit Page',
'page' => $page,
'mode' => $mode,
'token' => Session::get('form_token'),
'status' => Session::active(),
'images' => $images,
'files' => $files,
'views' => $views,
];
break;
case 'preview':
$config = new Settings();
$settings = $config->getSettings();
$loader = new \Twig\Loader\FilesystemLoader(
'../content/themes'
);
$display = new \Twig\Environment($loader, []);
$book = new Book();
$page = $book->findPageById($uuid);
$pageOptions = Sorting::page($page);
$preview =
$settings['global']['theme'].
'/'.
$page['layout'].
'.twig';
$html = $display->render($preview, $pageOptions);
$response->getBody()->write($html);
return $response;
break;
default:
$pageOptions = [
'title' => 'Fipamo | Create Page',
'token' => Session::get('form_token'),
'mode' => $mode,
'status' => Session::active(),
];
break;
}
} else {
header('Location: /dashboard');
exit();
}
break;
case 'logout':
Session::kill();
header('Location: /dashboard');
exit();
break;
case 'reset-password':
$template = 'dash/reset-password.twig';
$pageOptions = [
'title' => 'Reset Password',
];
break;
default:
$template = 'dash/start.twig';
if (Session::active()) {
$pageOptions = [
'title' => 'Welcome Back',
'status' => Session::active(),
'data' => (new Book())->getPages(1, 4),
];
} else {
$pageOptions = [
'title' => 'Welcome to Fipamo',
'status' => Session::active(),
];
}
break;
}
} else {
$template = 'dash/init.twig';
$pageOptions = ['title' => 'Fipamo Setup'];
}
return $view->render($response, $template, $pageOptions);
}
}

View file

@ -1,107 +0,0 @@
<?php
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Views\Twig;
use function _\find;
class IndexControl
{
public static function start(
ServerRequestInterface $request,
ResponseInterface $response,
array $args
): ResponseInterface {
//unset($_SESSION);
$config = new Settings();
$settings = $config->getSettings();
$view = Twig::fromRequest($request);
//checks dynamic render flag for site render status
if ($settings["global"]["dynamicRender"]) {
if ($settings["global"]["dynamicRender"] == "true") {
$loader = new \Twig\Loader\FilesystemLoader("../content/themes");
$display = new \Twig\Environment($loader, []);
$template = "";
$pageOptions = [];
$pageInfo = [
"keywords" => isset($settings["global"]["keywords"])
? $settings["global"]["keywords"]
: "fipamo, blog, jamstack, php, markdown, js",
"description" => $settings["global"]["descriptions"],
"image" =>
$settings["global"]["base_url"] . $settings["global"]["background"],
"baseURL" => $settings["global"]["base_url"],
];
if (isset($args["first"])) {
switch ($args["first"]) {
case "tags":
$template = $settings["global"]["theme"] . "/tags.twig";
$tag = trim($args["second"]);
$taglist = Sorting::tags();
$item = find($taglist, ["tag_name" => $tag]);
$pageOptions = [
"title" => "Pages Tagged as " . $item["tag_name"],
"background" => $pageInfo["image"],
"tag_list" => $item["pages"],
"info" => $pageInfo,
"menu" => $settings["menu"],
"dynamicRender" => $settings["global"]["dynamicRender"],
];
break;
case "archives":
$archive = Sorting::archive();
$template = $settings["global"]["theme"] . "/archive.twig";
$pageOptions = [
"title" => "Archive",
"background" => $pageInfo["image"],
"archives" => $archive,
"info" => $pageInfo,
"menu" => $settings["menu"],
"dynamicRender" => $settings["global"]["dynamicRender"],
];
break;
default:
//check if page is a menu item, if not render along path as usual
$page = [];
$book = new Book();
if (is_numeric($args["first"])) {
$page = $book->findPageBySlug($args["third"]);
} else {
$page = $book->findPageBySlug($args["first"]);
}
$template =
$settings["global"]["theme"] . "/" . $page["layout"] . ".twig";
$pageOptions = Sorting::page($page);
break;
}
} else {
//index
$template =
$settings["global"]["theme"] . "/" . $page["layout"] . ".twig";
$book = new Book("");
$page = $book->findPageBySlug();
$pageOptions = Sorting::page($page);
}
$html = $display->render($template, $pageOptions);
$response->getBody()->write($html);
return $response;
} else {
//if dynamic flag is false, load up html
$view = Twig::fromRequest($request);
$html = file_get_contents("../public/index.html");
$response->getBody()->write($html);
return $response;
}
} else {
//if flag is not present, default to static html
$view = Twig::fromRequest($request);
$html = file_get_contents("../public/index.html");
$response->getBody()->write($html);
return $response;
}
}
}

View file

@ -0,0 +1,113 @@
<?php
namespace brain\controller;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Views\Twig;
use brain\data\Settings;
use brain\utility\Sorting;
use function _\find;
class IndexControl
{
public static function start(
ServerRequestInterface $request,
ResponseInterface $response,
array $args
): ResponseInterface {
//unset($_SESSION);
$config = new Settings();
$settings = $config->getSettings();
$view = Twig::fromRequest($request);
//checks dynamic render flag for site render status
if ($settings["global"]["dynamicRender"]) {
if ($settings["global"]["dynamicRender"] == "true") {
$loader = new \Twig\Loader\FilesystemLoader("../content/themes");
$display = new \Twig\Environment($loader, []);
$template = "";
$pageOptions = [];
$pageInfo = [
"keywords" => isset($settings["global"]["keywords"])
? $settings["global"]["keywords"]
: "fipamo, blog, jamstack, php, markdown, js",
"description" => $settings["global"]["descriptions"],
"image" =>
$settings["global"]["base_url"] . $settings["global"]["background"],
"baseURL" => $settings["global"]["base_url"],
];
if (isset($args["first"])) {
switch ($args["first"]) {
case "tags":
$template = $settings["global"]["theme"] . "/tags.twig";
$tag = trim($args["second"]);
$taglist = Sorting::tags();
$item = find($taglist, ["tag_name" => $tag]);
$pageOptions = [
"title" => "Pages Tagged as " . $item["tag_name"],
"background" => $pageInfo["image"],
"tag_list" => $item["pages"],
"info" => $pageInfo,
"menu" => $settings["menu"],
"dynamicRender" => $settings["global"]["dynamicRender"],
];
break;
case "archives":
$archive = Sorting::archive();
$template = $settings["global"]["theme"] . "/archive.twig";
$pageOptions = [
"title" => "Archive",
"background" => $pageInfo["image"],
"archives" => $archive,
"info" => $pageInfo,
"menu" => $settings["menu"],
"dynamicRender" => $settings["global"]["dynamicRender"],
];
break;
default:
//check if page is a menu item, if not render along path as usual
$page = [];
$book = new Book();
if (is_numeric($args["first"])) {
$page = $book->findPageBySlug($args["third"]);
} else {
$page = $book->findPageBySlug($args["first"]);
}
$template =
$settings["global"]["theme"] . "/" . $page["layout"] . ".twig";
$pageOptions = Sorting::page($page);
break;
}
} else {
//index
$template =
$settings["global"]["theme"] . "/" . $page["layout"] . ".twig";
$book = new Book("");
$page = $book->findPageBySlug();
$pageOptions = Sorting::page($page);
}
$html = $display->render($template, $pageOptions);
$response->getBody()->write($html);
return $response;
} else {
//if dynamic flag is false, load up html
$view = Twig::fromRequest($request);
$html = file_get_contents("../public/index.html");
$response->getBody()->write($html);
return $response;
}
} else {
//if flag is not present, default to static html
$view = Twig::fromRequest($request);
$html = file_get_contents("../public/index.html");
$response->getBody()->write($html);
return $response;
}
}
}

View file

@ -1,44 +0,0 @@
<?php
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
include "../brain/controller/IndexControl.inc.php";
include "../brain/controller/DashControl.inc.php";
include "../brain/controller/APIControl.inc.php";
class RouteControl
{
public function get(
ServerRequestInterface $request,
ResponseInterface $response,
array $args
): ResponseInterface {
switch (isset($args["first"]) ? $args["first"] : "index") {
case "dashboard":
return DashControl::start($request, $response, $args);
break;
case "api":
return APIControl::get($request, $response, $args);
break;
default:
return IndexControl::start($request, $response, $args);
break;
}
}
public function post(
ServerRequestInterface $request,
ResponseInterface $response,
array $args
): ResponseInterface {
switch (isset($args["first"]) ? $args["first"] : "index") {
case "api":
return APIControl::post($request, $response, $args);
break;
default:
//echo "YES";
//return IndexControl::start($request, $response, $args);
break;
}
}
}

View file

@ -0,0 +1,48 @@
<?php
namespace brain\controller;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use brain\controller\DashControl;
use brain\controller\APIControl;
use brain\controller\IndexControl;
class RouteControl
{
public function get(
ServerRequestInterface $request,
ResponseInterface $response,
array $args
): ResponseInterface {
switch (isset($args["first"]) ? $args["first"] : "index") {
case "dashboard":
return DashControl::start($request, $response, $args);
break;
case "api":
return APIControl::get($request, $response, $args);
break;
default:
return IndexControl::start($request, $response, $args);
break;
}
}
public function post(
ServerRequestInterface $request,
ResponseInterface $response,
array $args
): ResponseInterface {
switch (isset($args["first"]) ? $args["first"] : "index") {
case "api":
//$result = APIControl::post($request, $response, $args);
//var_dump($result);
return APIControl::post($request, $response, $args);
break;
default:
//echo "YES";
//return IndexControl::start($request, $response, $args);
break;
}
}
}

View file

@ -1,154 +0,0 @@
<?php
use function _\find;
use ReallySimpleJWT\Token;
class Auth
{
public function __construct()
{
}
public static function sessionStatus()
{
if (isset($_SESSION["member"])) {
return true;
} else {
return false;
}
//return $this->secret;
}
public static function status()
{
$result = "";
if (Session::active()) {
$result = true;
} else {
$result = false;
}
return $result;
}
public static function login($who)
{
//grab member list
$folks = (new Settings())->getFolks();
$found = find($folks, ["handle" => $who["handle"]]);
if ($found) {
//name is found, verify password
if (password_verify($who["password"], $found["password"])) {
$member = [
"handle" => $found["handle"],
"email" => $found["email"],
"role" => $found["role"],
"avatar" => $found["avi"],
"key" => $found["key"],
];
$token = Token::create(
$found["key"],
$found["secret"],
time() + 3600,
"localhost"
); //expires in an hour
$form_token = md5(uniqid(microtime(), true));
Session::start();
Session::set("member", $member);
Session::set("token", $token);
Session::set("form_token", $form_token);
$result = "good_login";
} else {
$result = "bad_pass";
}
} else {
//if name is not found
$result = "no_name";
}
return $result;
}
public static function findSecret($data)
{
$result = [];
$folks = (new Settings())->getFolks();
if (
!empty($data["email"]) &&
filter_var($data["email"], FILTER_VALIDATE_EMAIL)
) {
$found = find($folks, ["email" => $data["email"]]);
if ($found) {
//if email is cool, check mail relay status
//if set up, send secret there, if not just return it
$config = new Settings();
$settings = $config->getSettings();
$email = $settings["email"]["active"];
if ($email != "option-none") {
$data["mail_task"] = "SEND_SECRET";
$data["secret"] = $found["secret"];
$result = Mailer::sendmail($data);
} else {
$result = [
"message" => "Valid email, but no email set up!",
"type" => "secretFound",
"secret" => $found["secret"],
];
}
} else {
$result = [
"message" => "No valid email, no goodies, pleighboi",
"type" => "secretNotFound",
];
}
} else {
$result = [
"message" => "Aye, this address is not right, slick.",
"type" => "secretNotFound",
];
}
return $result;
}
public static function makeNewPassword($data)
{
//check if passwordsmatch
if ($data["newPass"] == $data["newPassConfirm"]) {
//verify secret
$folks = (new Settings())->getFolks();
$found = find($folks, ["secret" => $data["secret"]]);
if ($found) {
//create new pass and secret key, then update file
$hash = password_hash($data["newPass"], PASSWORD_DEFAULT);
$freshSecret = StringTools::randomString(12);
Member::updateData("password", $hash, $data["secret"]);
Member::updateData("secret", $freshSecret, $data["secret"]);
$result = [
"message" => "Password Updated. Very nice!",
"type" => "passCreated",
];
} else {
$result = [
"message" => "Secret key is invalid. Try to retrieve it again",
"type" => "passNotCreated",
];
}
} else {
$result = [
"message" => "Passwords don't match. Try it again.",
"type" => "passNotCreated",
];
}
return $result;
}
public static function logout()
{
Session::kill();
}
}

159
brain/data/Auth.php Normal file
View file

@ -0,0 +1,159 @@
<?php
namespace brain\data;
use ReallySimpleJWT\Token;
use brain\data\Settings;
use brain\data\Session;
use function _\find;
class Auth
{
public function __construct()
{
}
public static function sessionStatus()
{
if (isset($_SESSION["member"])) {
return true;
} else {
return false;
}
//return $this->secret;
}
public static function status()
{
$result = "";
if (Session::active()) {
$result = true;
} else {
$result = false;
}
return $result;
}
public static function login($who)
{
//grab member list
$folks = (new Settings())->getFolks();
$found = find($folks, ["handle" => $who["handle"]]);
if ($found) {
//name is found, verify password
if (password_verify($who["password"], $found["password"])) {
$member = [
"handle" => $found["handle"],
"email" => $found["email"],
"role" => $found["role"],
"avatar" => $found["avi"],
"key" => $found["key"],
];
$token = Token::create(
$found["key"],
$found["secret"],
time() + 3600,
"localhost"
); //expires in an hour
$form_token = md5(uniqid(microtime(), true));
Session::start();
Session::set("member", $member);
Session::set("token", $token);
Session::set("form_token", $form_token);
$result = "good_login";
} else {
$result = "bad_pass";
}
} else {
//if name is not found
$result = "no_name";
}
return $result;
}
public static function findSecret($data)
{
$result = [];
$folks = (new Settings())->getFolks();
if (
!empty($data["email"]) &&
filter_var($data["email"], FILTER_VALIDATE_EMAIL)
) {
$found = find($folks, ["email" => $data["email"]]);
if ($found) {
//if email is cool, check mail relay status
//if set up, send secret there, if not just return it
$config = new Settings();
$settings = $config->getSettings();
$email = $settings["email"]["active"];
if ($email != "option-none") {
$data["mail_task"] = "SEND_SECRET";
$data["secret"] = $found["secret"];
$result = Mailer::sendmail($data);
} else {
$result = [
"message" => "Valid email, but no email set up!",
"type" => "secretFound",
"secret" => $found["secret"],
];
}
} else {
$result = [
"message" => "No valid email, no goodies, pleighboi",
"type" => "secretNotFound",
];
}
} else {
$result = [
"message" => "Aye, this address is not right, slick.",
"type" => "secretNotFound",
];
}
return $result;
}
public static function makeNewPassword($data)
{
//check if passwordsmatch
if ($data["newPass"] == $data["newPassConfirm"]) {
//verify secret
$folks = (new Settings())->getFolks();
$found = find($folks, ["secret" => $data["secret"]]);
if ($found) {
//create new pass and secret key, then update file
$hash = password_hash($data["newPass"], PASSWORD_DEFAULT);
$freshSecret = StringTools::randomString(12);
Member::updateData("password", $hash, $data["secret"]);
Member::updateData("secret", $freshSecret, $data["secret"]);
$result = [
"message" => "Password Updated. Very nice!",
"type" => "passCreated",
];
} else {
$result = [
"message" => "Secret key is invalid. Try to retrieve it again",
"type" => "passNotCreated",
];
}
} else {
$result = [
"message" => "Passwords don't match. Try it again.",
"type" => "passNotCreated",
];
}
return $result;
}
public static function logout()
{
Session::kill();
}
}

View file

@ -1,265 +0,0 @@
<?php
use function _\filter;
use function _\find;
class Book
{
public function __construct()
{
}
public function findPageById(string $uuid)
{
$content = $this->getContents();
$page = find($content, ["uuid" => $uuid]);
return $page;
}
public function findPageBySlug(string $slug = null)
{
$content = $this->getContents();
if (isset($slug)) {
$page = find($content, ["slug" => $slug]);
} else {
$page = find($content, ["layout" => "index"]);
}
return $page;
}
public function editPage($task, $request)
{
$content = $this->getContents();
if ($task == "delete") {
//$parsed = json_decode(file_get_contents("php://input"), true);
//$body = find($content, ["uuid" => $parsed["id"]]);
$body = $request->getParsedBody();
} else {
$body = $request->getParsedBody();
}
$page = find($content, ["uuid" => $body["uuid"]]);
$image = $request->getUploadedFiles();
$member = Session::get("member");
if ($task != "create") {
$path =
date("Y", date($page["rawCreated"])) .
"/" .
date("m", date($page["rawCreated"]));
} else {
$path = date("Y") . "/" . date("m");
}
if (isset($image["feature_image"])) {
if ($task != "create") {
$feature =
"/assets/images/blog/" .
$path .
"/" .
$image["feature_image"]->getClientFileName();
} else {
$feature =
"/assets/images/blog/" .
$path .
"/" .
$image["feature_image"]->getClientFileName();
}
FileUploader::uploadFile(
"../public/assets/images/blog/" . $path . "/",
$image["feature_image"]
);
} else {
if (isset($body["feature_image"])) {
$url = explode("/", $body["feature_image"]);
$feature =
"/" .
$url[3] .
"/" .
$url[4] .
"/" .
$url[5] .
"/" .
$url[6] .
"/" .
$url[7] .
"/" .
$url[8];
} else {
$task == "create" ? ($feature = "") : ($feature = $body["feature"]);
}
}
if ($task == "delete") {
$deleted = "true";
$body["menu"] = "false";
$body["published"] = "false";
$body["featured"] = "false";
} else {
$deleted = isset($page["deleted"]) ? $page["deleted"] : "false";
}
$created =
$task != "create"
? new \Moment\Moment($page["rawCreated"])
: new \Moment\Moment();
$updated = new \Moment\Moment();
//grab current index from settings and update
$id = $task != "create" ? $body["id"] : Settings::getCurrentIndex();
$uuid = $task != "create" ? $body["uuid"] : StringTools::createUUID();
// now that variables are done, set to body object and then convert to markdown to save
$body["id"] = $id;
$body["uuid"] = $uuid;
$body["feature"] = $feature;
$body["path"] = $path;
$body["author"] = $member["handle"];
$body["created"] = $created->format("Y-m-d\TH:i:sP");
$body["updated"] = $updated->format("Y-m-d\TH:i:sP");
$body["deleted"] = $deleted;
$write = DocTools::objectToMD($body);
// if layout is index, change path to file
if ($body["layout"] == "index") {
$writePath = "../content/pages/start/index.md";
} else {
$writePath = "../content/pages/" . $path . "/" . $body["slug"] . ".md";
}
$status = DocTools::writePages($task, $path, $writePath, $write);
if ($status) {
$config = new Settings();
$settings = $config->getSettings();
$message = "";
if (
$settings["global"]["renderOnSave"] == "true" &&
$settings["global"]["dynamicRender"] == "false"
) {
$render = new Render();
$render->renderTags();
$render->renderArchive();
$render->renderPages();
$message = "Filed edited and rendered. NOICE.";
} else {
$message = "File edited. Nice work";
}
$response = [
"message" => $message,
"type" => $task == "write" ? "postUpdated" : "postAdded",
"id" => $uuid,
];
//TODO: When form submission is successful, make new form token
//Session token doesn't reset on the front end, so turning this off for now
//$form_token = md5(uniqid(microtime(), true));
//Session::set("form_token", $form_token);
//once saved, update menu
$body["path"] = $path;
Settings::updateMenu($body);
Settings::updateTags();
//if new page added, update current index in Settings file
if ($task == "create") {
Settings::updateIndex();
}
} else {
$response = [
"message" => "Uh oh. File save problem. Don't panic",
"type" => "postError",
"id" => $uuid,
];
}
return $response;
}
public function getPages(int $page, int $limit, string $sort = null)
{
$content = $this->getContents();
$published = filter($content, function ($item) {
return $item["published"] == true && $item["deleted"] == false;
});
$deleted = filter($content, function ($item) {
return $item["deleted"] == true;
});
//$all = $content;
$all = filter($content, function ($item) {
return $item["deleted"] == false;
});
$filter = isset($sort) ? $sort : "all";
switch ($filter) {
case "published":
$filtered = $published;
break;
case "deleted":
$filtered = $deleted;
break;
default:
$filtered = $all;
break;
}
$numOfPages = ceil(count($filtered) / ($limit + 1));
$folder = [];
if (count($filtered) != 0) {
if (count($filtered) < $limit) {
$limit = count($filtered) - 1;
}
$range = $page * $limit - $limit;
if ($range != 0) {
$range = $range + 1;
}
for ($i = 0; $i <= $limit; $i++) {
if (isset($filtered[$i + $range])) {
array_push($folder, $filtered[$i + $range]);
} else {
//chill out
}
}
}
$prev = $page - 1;
if ($prev <= 0) {
$prev = $numOfPages;
}
$next = $page + 1;
if ($next > $numOfPages) {
$next = 1;
}
return [
"pages" => $folder,
"numOfPages" => $numOfPages,
"entryCount" => count($filtered),
"paginate" => [
"sort" => $sort,
"nextPage" => $next,
"prevPage" => $prev,
],
"stats" => [
"all" => count($all),
"published" => count($published),
"deleted" => count($deleted),
],
];
}
public function getContents()
{
//test new contents data class
//$new = (new Contents("../content/pages"))->getAll();
$contents = (new Contents("../content/pages"))->getAll();
return $contents;
}
}

298
brain/data/Book.php Normal file
View file

@ -0,0 +1,298 @@
<?php
namespace brain\data;
use function _\filter;
use function _\find;
use brain\utility\DocTools;
use brain\utility\FileUploader;
use brain\utility\StringTools;
class Book
{
public function __construct()
{
}
public function findPageById(string $uuid)
{
$content = $this->getContents();
$page = find($content, ['uuid' => $uuid]);
return $page;
}
public function findPageBySlug(string $slug = null)
{
$content = $this->getContents();
if (isset($slug)) {
$page = find($content, ['slug' => $slug]);
} else {
$page = find($content, ['layout' => 'index']);
}
return $page;
}
public function editPage($task, $request)
{
$content = $this->getContents();
if ($task == 'delete') {
// $parsed = json_decode(file_get_contents("php://input"), true);
// $body = find($content, ["uuid" => $parsed["id"]]);
$body = $request->getParsedBody();
} else {
$body = $request->getParsedBody();
}
$page = find($content, ['uuid' => $body['uuid']]);
$files = $request->getUploadedFiles();
$member = Session::get('member');
if ($task != 'create') {
$path =
date('Y', date($page['rawCreated'])).
'/'.
date('m', date($page['rawCreated']));
} else {
$path = date('Y').'/'.date('m');
}
$page_feature = '';
$page_files = '';
if (isset($files['page_files'])) {
$imageList = '';
$fileList = '';
// var_dump($files["page_files"] );
foreach ($files['page_files'] as $file) {
$type = $file->getClientMediaType();
switch ($type) {
case 'image/jpeg':
case 'image/png':
case 'image/gif':
case 'image/svg':
$imagesPath = '/assets/images/blog/'.$path.'/';
$imageList =
$imageList.$imagesPath.urlencode($file->getClientFileName()).', ';
FileUploader::uploadFile(
'../public/assets/images/blog/'.$path.'/',
$file
);
break;
case 'video/mp4':
$videosPath = '/assets/video/blog/'.$path.'/';
$imageList =
$imageList.$videosPath.urlencode($file->getClientFileName()).', ';
FileUploader::uploadFile(
'../public/assets/video/blog/'.$path.'/',
$file
);
break;
case 'audio/mpeg':
$soundPath = '/assets/sound/blog/'.$path.'/';
$fileList = $fileList.$soundPath.urlencode($file->getClientFileName()).', ';
FileUploader::uploadFile(
'../public/assets/sound/blog/'.$path.'/',
$file
);
break;
case 'application/pdf':
case 'text/plain':
case 'text/rtf':
$docPath = '/assets/docs/blog/'.$path.'/';
$fileList = $fileList.$docPath.urlencode($file->getClientFileName()).', ';
FileUploader::uploadFile(
'../public/assets/docs/blog/'.$path.'/',
$file
);
break;
}
}
$page_feature = $imageList;
$page_files = $fileList;
} else {
// if no files, just reset string from page object
$page_feature = $page['feature'];
$page_files = $page['files'];
}
if ($task == 'delete') {
$deleted = 'true';
$body['menu'] = 'false';
$body['published'] = 'false';
$body['featured'] = 'false';
} else {
$deleted = isset($page['deleted']) ? $page['deleted'] : 'false';
}
$created =
$task != 'create'
? new \Moment\Moment($page['rawCreated'])
: new \Moment\Moment();
$updated = new \Moment\Moment();
// grab current index from settings and update
$id = $task != 'create' ? $body['id'] : Settings::getCurrentIndex();
$uuid = $task != 'create' ? $body['uuid'] : StringTools::createUUID();
// now that variables are done, set to body object and then convert to markdown to save
$body['id'] = $id;
$body['uuid'] = $uuid;
$body['feature'] = $page_feature;
$body['files'] = $page_files;
$body['path'] = $path;
$body['author'] = $member['handle'];
$body['created'] = $created->format("Y-m-d\TH:i:sP");
$body['updated'] = $updated->format("Y-m-d\TH:i:sP");
$body['deleted'] = $deleted;
$write = DocTools::objectToMD($body);
// if layout is index, change path to file
if ($body['layout'] == 'index') {
$writePath = '../content/pages/start/index.md';
} else {
$writePath = '../content/pages/'.$path.'/'.$body['slug'].'.md';
}
$status = DocTools::writePages($task, $path, $writePath, $write);
if ($status) {
$config = new Settings();
$settings = $config->getSettings();
$message = '';
if (
$settings['global']['renderOnSave'] == 'true' &&
$settings['global']['dynamicRender'] == 'false'
) {
$render = new Render();
$render->renderTags();
$render->renderArchive();
$render->renderPages();
$message = 'Filed edited and rendered. NOICE.';
} else {
$message = 'File edited. Nice work';
}
$response = [
'message' => $message,
'type' => $task == 'write' ? 'postUpdated' : 'postAdded',
'id' => $uuid,
];
// TODO: When form submission is successful, make new form token
// Session token doesn't reset on the front end, so turning this off for now
// $form_token = md5(uniqid(microtime(), true));
// Session::set("form_token", $form_token);
// once saved, update menu
$body['path'] = $path;
Settings::updateMenu($body);
Settings::updateTags();
// if new page added, update current index in Settings file
if ($task == 'create') {
Settings::updateIndex();
}
} else {
$response = [
'message' => "Uh oh. File save problem. Don't panic",
'type' => 'postError',
'id' => $uuid,
];
}
return $response;
}
public function getPages(int $page, int $limit, string $sort = null)
{
$content = $this->getContents();
$published = filter($content, function ($item) {
return $item['published'] == true && $item['deleted'] == false;
});
$deleted = filter($content, function ($item) {
return $item['deleted'] == true;
});
// $all = $content;
$all = filter($content, function ($item) {
return $item['deleted'] == false;
});
$filter = isset($sort) ? $sort : 'all';
switch ($filter) {
case 'published':
$filtered = $published;
break;
case 'deleted':
$filtered = $deleted;
break;
default:
$filtered = $all;
break;
}
$numOfPages = ceil(count($filtered) / ($limit + 1));
$folder = [];
if (count($filtered) != 0) {
if (count($filtered) < $limit) {
$limit = count($filtered) - 1;
}
$range = $page * $limit - $limit;
if ($range != 0) {
$range = $range + 1;
}
for ($i = 0; $i <= $limit; ++$i) {
if (isset($filtered[$i + $range])) {
array_push($folder, $filtered[$i + $range]);
} else {
// chill out
}
}
}
$prev = $page - 1;
if ($prev <= 0) {
$prev = $numOfPages;
}
$next = $page + 1;
if ($next > $numOfPages) {
$next = 1;
}
return [
'pages' => $folder,
'numOfPages' => $numOfPages,
'entryCount' => count($filtered),
'paginate' => [
'sort' => $sort,
'nextPage' => $next,
'prevPage' => $prev,
],
'stats' => [
'all' => count($all),
'published' => count($published),
'deleted' => count($deleted),
],
];
}
public function getContents()
{
// test new contents data class
// $new = (new Contents("../content/pages"))->getAll();
$contents = (new Contents('../content/pages'))->getAll();
return $contents;
}
}

View file

@ -1,144 +0,0 @@
<?php
use League\CommonMark\Environment\Environment;
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
use League\CommonMark\Extension\Attributes\AttributesExtension;
use League\CommonMark\Extension\FrontMatter\FrontMatterExtension;
use League\CommonMark\Extension\FrontMatter\Output\RenderedContentWithFrontMatter;
use League\CommonMark\MarkdownConverter;
use League\CommonMark\CommonMarkConverter;
use HtmlSanitizer\Extension\Basic\BasicExtension;
use HtmlSanitizer\Extension\Iframe\IframeExtension;
use HtmlSanitizer\SanitizerBuilder;
use function _\orderBy;
class Contents
{
public $files = [];
public $config = [];
public function __construct($folder)
{
$this->read($folder);
}
public function read($folder)
{
$folders = glob("$folder/*", GLOB_ONLYDIR);
foreach ($folders as $folder) {
//$this->files[] = $folder . "/";
$this->read($folder);
}
$files = array_filter(glob("$folder/*md"), "is_file");
foreach ($files as $file) {
$this->files[] = $file;
}
}
function getAll()
{
$environment = new Environment($this->config);
$environment->addExtension(new CommonMarkCoreExtension());
// Add the extension
$environment->addExtension(new FrontMatterExtension());
//Add Strikethrough rendering
$environment->addExtension(new StrikethroughExtension());
//add attributes to elements in markdown
$environment->addExtension(new AttributesExtension());
// Instantiate the converter engine and start converting some Markdown!
$converter = new MarkdownConverter($environment);
$contents = [];
foreach ($this->files as $file) {
//get meta and html from file
$result = $converter->convertToHtml(file_get_contents($file));
$meta = [];
if ($result instanceof RenderedContentWithFrontMatter) {
$meta = $result->getFrontMatter();
}
//get raw markdown from file
$frontMatterExtension = new FrontMatterExtension();
$parsed = $frontMatterExtension
->getFrontMatterParser()
->parse(file_get_contents($file));
//never trust the front end. clean it up
$builder = new SanitizerBuilder();
$builder->registerExtension(new BasicExtension());
$builder->registerExtension(new IframeExtension());
//relative-a and relative-image
$builder->registerExtension(
new \HtmlSanitizer\Extension\Relative\A\AExtension()
);
$builder->registerExtension(
new \HtmlSanitizer\Extension\Relative\Image\ImageExtension()
);
$detergent = [
"extensions" => ["basic", "relative-a", "relative-image", "iframe"],
"tags" => [
"div" => [
"allowed_attributes" => ["class", "title"],
],
"img" => [
"allowed_attributes" => ["src", "alt", "title", "class"],
],
"iframe" => [
"allowed_attributes" => ["height", "width", "title", "src"],
],
],
];
$sanitizer = $builder->build($detergent);
$scrubbed = $sanitizer->sanitize($result->getContent());
//sort attributes into page object
$page = [
"id" => $meta["id"],
"uuid" => $meta["uuid"],
"title" => $meta["title"],
"feature" => $meta["feature"],
"path" => $meta["path"],
"layout" => $meta["layout"],
"tags" => $meta["tags"],
"author" => $meta["author"],
"created" => date("Y M D d", $meta["created"]),
"updated" => date("Y M D d", $meta["updated"]),
"rawCreated" => $meta["created"],
"rawUpdated" => $meta["updated"],
"createdYear" => date("Y", $meta["created"]),
"createdMonth" => date("m", $meta["created"]),
"deleted" => $meta["deleted"],
"menu" => $meta["menu"],
"featured" => $meta["featured"],
"published" => $meta["published"],
"slug" => $meta["slug"],
"filePath" => $file,
"content" => $parsed->getContent(),
"html" => $scrubbed,
];
//checks for duplicates
$uuid = $meta["uuid"];
$found = current(
array_filter($contents, function ($item) use ($uuid) {
return isset($item["uuid"]) && $uuid == $item["uuid"];
})
);
// if uuid is not present, add it
if (!$found) {
array_push($contents, $page);
}
}
$contents = orderBy($contents, ["id"], ["desc"]);
return $contents;
}
}

178
brain/data/Contents.php Normal file
View file

@ -0,0 +1,178 @@
<?php
namespace brain\data;
use League\CommonMark\Environment\Environment;
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
use League\CommonMark\Extension\Attributes\AttributesExtension;
use League\CommonMark\Extension\FrontMatter\FrontMatterExtension;
use League\CommonMark\Extension\FrontMatter\Output\RenderedContentWithFrontMatter;
use League\CommonMark\MarkdownConverter;
use League\CommonMark\CommonMarkConverter;
use HtmlSanitizer\Extension\Basic\BasicExtension;
use HtmlSanitizer\Extension\Iframe\IframeExtension;
use HtmlSanitizer\Extension\Listing\ListExtension;
use HtmlSanitizer\SanitizerBuilder;
use function _\orderBy;
class Contents
{
public $files = [];
public $config = [];
public function __construct($folder)
{
$this->read($folder);
}
public function read($folder)
{
$folders = glob("$folder/*", GLOB_ONLYDIR);
foreach ($folders as $folder) {
//$this->files[] = $folder . "/";
$this->read($folder);
}
$files = array_filter(glob("$folder/*md"), "is_file");
foreach ($files as $file) {
$this->files[] = $file;
}
}
public function getAll()
{
$environment = new Environment($this->config);
$environment->addExtension(new CommonMarkCoreExtension());
// Add the extension
$environment->addExtension(new FrontMatterExtension());
//Add Strikethrough rendering
$environment->addExtension(new StrikethroughExtension());
//add attributes to elements in markdown
$environment->addExtension(new AttributesExtension());
// Instantiate the converter engine and start converting some Markdown!
$converter = new MarkdownConverter($environment);
$contents = [];
foreach ($this->files as $file) {
//get meta and html from file
$result = $converter->convertToHtml(file_get_contents($file));
$meta = [];
if ($result instanceof RenderedContentWithFrontMatter) {
$meta = $result->getFrontMatter();
}
//get raw markdown from file
$frontMatterExtension = new FrontMatterExtension();
$parsed = $frontMatterExtension
->getFrontMatterParser()
->parse(file_get_contents($file));
//never trust the front end. clean it up
//add what sanitizer extensions we need manually
$builder = new SanitizerBuilder();
$builder->registerExtension(new BasicExtension());
$builder->registerExtension(new IframeExtension());
$builder->registerExtension(new ListExtension());
//relative-a and relative-image
$builder->registerExtension(
new \HtmlSanitizer\Extension\Relative\A\AExtension()
);
$builder->registerExtension(
new \HtmlSanitizer\Extension\Relative\Image\ImageExtension()
);
$detergent = [
"extensions" => ["basic", "list","relative-a", "relative-image", "iframe"],
"tags" => [
"div" => [
"allowed_attributes" => ["class", "title", "id", "style"],
],
"img" => [
"allowed_attributes" => ["src", "alt", "title", "class"],
],
"iframe" => [
"allowed_attributes" => ["height", "width", "title", "src"],
],
],
];
$sanitizer = $builder->build($detergent);
$scrubbed = $sanitizer->sanitize($result->getContent());
$featureList = explode(",", $meta["feature"]);
$docs = '';
if (isset($meta["files"])) {
$fileList = explode(",", $meta["files"]);
$docs = $meta["files"];
} else {
$fileList = [];
$docs = '';
}
$media = [];
$files = [];
foreach ($featureList as $file) {
$item = trim($file);
$ext = pathinfo($item, PATHINFO_EXTENSION);
if ($item != null || $item != "") {
array_push($media, ["file" => $item, "type" => trim($ext)]);
}
}
foreach ($fileList as $file) {
$item = trim($file);
$ext = pathinfo($item, PATHINFO_EXTENSION);
if ($item != null || $item != "") {
array_push($files, ["file" => $item, "type" => trim($ext)]);
}
}
//sort attributes into page object
$page = [
"id" => $meta["id"],
"uuid" => $meta["uuid"],
"title" => $meta["title"],
"feature" => $meta["feature"],
"files" => $docs,
"path" => $meta["path"],
"layout" => $meta["layout"],
"tags" => $meta["tags"],
"author" => $meta["author"],
"created" => date("Y M D d", $meta["created"]),
"updated" => date("Y M D d", $meta["updated"]),
"rawCreated" => $meta["created"],
"rawUpdated" => $meta["updated"],
"createdYear" => date("Y", $meta["created"]),
"createdMonth" => date("m", $meta["created"]),
"deleted" => $meta["deleted"],
"menu" => $meta["menu"],
"featured" => $meta["featured"],
"published" => $meta["published"],
"slug" => $meta["slug"],
"filePath" => $file,
"content" => $parsed->getContent(),
"html" => $scrubbed,
"media" => $media,
"docs" => $files
];
//checks for duplicates
$uuid = $meta["uuid"];
$found = current(
array_filter($contents, function ($item) use ($uuid) {
return isset($item["uuid"]) && $uuid == $item["uuid"];
})
);
// if uuid is not present, add it
if (!$found) {
array_push($contents, $page);
}
}
$contents = orderBy($contents, ["id"], ["desc"]);
return $contents;
}
}

View file

@ -1,55 +0,0 @@
<?php
use function _\find;
class Member
{
public function __construct()
{
}
public static function verifyKey(string $key)
{
if (isset($key)) {
$folks = (new Settings())->getFolks();
$found = find($folks, ["key" => $key]);
if ($found) {
return true;
} else {
return false;
}
} else {
return false;
}
}
public static function updateData(string $key, string $data, $secret = null)
{
$folks = (new Settings())->getFolks();
if (isset($secret)) {
$found = find($folks, ["secret" => $secret]);
} else {
$member = Session::get("member");
$found = find($folks, ["handle" => $member["handle"]]);
}
$found[$key] = $data;
//record time updated
$updated = new \Moment\Moment();
$found["updated"] = $updated->format("Y-m-d\TH:i:sP");
$newFolks = [];
array_push($newFolks, $found);
//save updated file
DocTools::writeSettings("../config/folks.json", $newFolks);
//update member data in session
if (!isset($secret)) {
$member = [
"handle" => $found["handle"],
"email" => $found["email"],
"role" => $found["role"],
"avatar" => $found["avi"],
"key" => $found["key"],
];
Session::set("member", $member);
}
}
}

62
brain/data/Member.php Normal file
View file

@ -0,0 +1,62 @@
<?php
namespace brain\data;
use brain\data\Settings;
use brain\data\Session;
use brain\utility\DocTools;
use function _\find;
class Member
{
public function __construct()
{
}
public static function verifyKey(string $key)
{
if (isset($key)) {
$folks = (new Settings())->getFolks();
$found = find($folks, ["key" => $key]);
if ($found) {
return true;
} else {
return false;
}
} else {
return false;
}
}
public static function updateData(string $key, string $data, $secret = null)
{
$folks = (new Settings())->getFolks();
if (isset($secret)) {
$found = find($folks, ["secret" => $secret]);
} else {
$member = Session::get("member");
$found = find($folks, ["handle" => $member["handle"]]);
}
$found[$key] = $data;
//record time updated
$updated = new \Moment\Moment();
$found["updated"] = $updated->format("Y-m-d\TH:i:sP");
$newFolks = [];
array_push($newFolks, $found);
//save updated file
DocTools::writeSettings("../config/folks.json", $newFolks);
//update member data in session
if (!isset($secret)) {
$member = [
"handle" => $found["handle"],
"email" => $found["email"],
"role" => $found["role"],
"avatar" => $found["avi"],
"key" => $found["key"],
];
Session::set("member", $member);
}
}
}

View file

@ -1,179 +0,0 @@
<?php
use Mni\FrontYAML\Parser;
use function _\find;
class Render
{
public $loader;
public $twig;
public $pageInfo;
public $menu;
public $background;
public function __construct()
{
$config = new Settings();
$this->loader = new \Twig\Loader\FilesystemLoader("../content/themes");
$this->twig = new \Twig\Environment($this->loader, []);
$settings = $config->getSettings();
$this->menu = $settings["menu"];
$this->theme = $settings["global"]["theme"];
$this->pageInfo = [
"keywords" => isset($settings["global"]["keywords"])
? $settings["global"]["keywords"]
: "fipamo, blog, jamstack, php, markdown, js",
"description" => $settings["global"]["descriptions"],
"image" =>
$settings["global"]["base_url"] . $settings["global"]["background"],
"baseURL" => $settings["global"]["base_url"],
];
//move global theme image assets to public folder
foreach (
new DirectoryIterator(
"../content/themes/" . $this->theme . "/assets/images/global/"
)
as $file
) {
if ($file->isDot()) {
continue;
}
if (!is_file("../public/assets/images/global/" . $file->getFileName())) {
copy(
"../content/themes/" .
$this->theme .
"/assets/images/global/" .
$file->getFileName(),
"../public/assets/images/global/" . $file->getFileName()
);
} else {
//image is already there, so chill
}
//print $file->getFilename() . "\n";
}
//copy current theme assets to public
if (is_file("../public/assets/css/base.css")) {
unlink("../public/assets/css/base.css");
}
copy(
"../content/themes/" . $this->theme . "/assets/css/base.css",
"../public/assets/css/base.css"
);
if (is_file("../public/assets/scripts/start.min.js")) {
unlink("../public/assets/scripts/start.min.js");
}
copy(
"../content/themes/" . $this->theme . "/assets/scripts/start.min.js",
"../public/assets/scripts/start.min.js"
);
}
public function renderPages()
{
$pages = (new Book())->getContents();
$recent = [];
$featured = [];
$limit = 4;
foreach ($pages as $page) {
$pageOptions = Sorting::page($page);
$layout = $page["layout"];
//new pages have no layout, so defautl for now
if ($layout == "" || $layout == null) {
$layout = "page";
}
$template = $this->theme . "/" . $layout . ".twig";
if (str_contains($page["layout"], "index")) {
$location = "../public/index.html";
$dir = null;
} else {
// if page is a menu item, render the page on public root
if ($page["menu"] == "true") {
$location = "../public/" . $page["slug"] . ".html";
$dir = "../public/";
} else {
$location =
"../public/" . $page["path"] . "/" . $page["slug"] . ".html";
$dir = "../public/" . $page["path"];
}
}
$html = $this->twig->render($template, $pageOptions);
DocTools::writeHTML($location, $html, $dir);
}
}
public function renderArchive()
{
$archive = Sorting::archive();
$template = $this->theme . "/archive.twig";
$pageOptions = [
"title" => "Archive",
"background" => $this->pageInfo["image"],
"archives" => $archive,
"info" => $this->pageInfo,
"menu" => $this->menu,
];
$html = $this->twig->render($template, $pageOptions);
$location = "../public/archives.html";
DocTools::writeHTML($location, $html);
}
public function renderTags()
{
$list = Sorting::tags();
foreach ($list as $item) {
$template = $this->theme . "/tags.twig";
$pageOptions = [
"title" => "Pages Tagged as " . $item["tag_name"],
"background" => $this->pageInfo["image"],
"tag_list" => $item["pages"],
"info" => $this->pageInfo,
"menu" => $this->menu,
];
$html = $this->twig->render($template, $pageOptions);
$location = "../public/tags/" . $item["slug"] . ".html";
//if tags folder doesn't exist, make it
if (!is_dir("../public/tags")) {
mkdir("../public/tags", 0755, true);
} else {
}
if (!is_file($location)) {
file_put_contents($location, $html);
} else {
($new = fopen($location, "w")) or die("Unable to open file!");
fwrite($new, $html);
fclose($new);
}
}
}
public function renderIndex()
{
//TODO: Need to fix this to account for new index templating system
$pages = (new Book())->getContents();
$index = find($pages, ["layout" => "index"]);
$template = $this->theme . "/index.twig";
$location = "../public/index.html";
$dir = null;
$meta = [
"who" => $index["author"],
"when" => $index["created"],
];
$pageOptions = [
"title" => $index["title"],
"background" => $index["feature"],
"meta" => $meta,
];
$html = $this->twig->render($template, $pageOptions);
DocTools::writeHTML($location, $html, $dir);
}
}

206
brain/data/Render.php Normal file
View file

@ -0,0 +1,206 @@
<?php
namespace brain\data;
use Mni\FrontYAML\Parser;
use brain\data\Settings;
use brain\data\Book;
use brain\utility\Sorting;
use brain\utility\DocTools;
use function _\find;
class Render
{
public $loader;
public $twig;
public $pageInfo;
public $menu;
public $background;
public function __construct()
{
$config = new Settings();
//TODO: Add theme folder to loader
$settings = $config->getSettings();
$this->menu = $settings["menu"];
$this->theme = $settings["global"]["theme"];
$this->loader = new \Twig\Loader\FilesystemLoader("../content/themes/" . $this->theme);
$this->twig = new \Twig\Environment($this->loader, []);
$this->pageInfo = [
"keywords" => isset($settings["global"]["keywords"])
? $settings["global"]["keywords"]
: "fipamo, blog, jamstack, php, markdown, js",
"description" => $settings["global"]["descriptions"],
"image" =>
$settings["global"]["base_url"] . $settings["global"]["background"],
"baseURL" => $settings["global"]["base_url"],
];
//move global theme image assets to public folder
foreach (
new \DirectoryIterator("../content/themes/" . $this->theme . "/assets/images/global/") as $file
) {
if ($file->isDot()) {
continue;
}
if (!is_file("../public/assets/images/global/" . $file->getFileName())) {
copy(
"../content/themes/" .
$this->theme .
"/assets/images/global/" .
$file->getFileName(),
"../public/assets/images/global/" . $file->getFileName()
);
} else {
//image is already there, so chill
}
//print $file->getFilename() . "\n";
}
//copy current theme assets to public
//clear files in css and scripts folder
$styles = glob('../public/assets/css/*'); // get all file names
foreach ($styles as $file) { // iterate files
if (is_file($file)) {
//don't erase dashboard css
if (!$file == '../public/assets/css/dash.css') {
unlink($file); // delete file
}
}
}
$scripts = glob('../public/assets/scripts/*'); // get all file names
foreach ($scripts as $file) { // iterate files
if (is_file($file)) {
if (!$file == "../public/assets/scripts/Start.js") {
unlink($file); // delete file
}
}
}
//copy theme assets to public
$newcss = glob("../content/themes/" . $this->theme . "/assets/css/*");
foreach ($newcss as $file) { // iterate files
if (is_file($file)) {
$path = explode("/", $file);
copy($file, "../public/assets/css/" . $path[6]);
}
}
$newjs = glob("../content/themes/" . $this->theme . "/assets/scripts/*");
foreach ($newjs as $file) { // iterate files
if (is_file($file)) {
$path = explode("/", $file);
copy($file, "../public/assets/scripts/" . $path[6]);
}
}
}
public function renderPages()
{
$pages = (new Book())->getContents();
$recent = [];
$featured = [];
$limit = 4;
foreach ($pages as $page) {
$pageOptions = Sorting::page($page);
$layout = $page["layout"];
//new pages have no layout, so defautl for now
if ($layout == "" || $layout == null) {
$layout = "page";
}
$template = $layout . ".twig";
if (str_contains($page["layout"], "index")) {
$location = "../public/index.html";
$dir = null;
} else {
// if page is a menu item, render the page on public root
if ($page["menu"] == "true") {
$location = "../public/" . $page["slug"] . ".html";
$dir = "../public/";
} else {
$location =
"../public/" . $page["path"] . "/" . $page["slug"] . ".html";
$dir = "../public/" . $page["path"];
}
}
$html = $this->twig->render($template, $pageOptions);
DocTools::writeHTML($location, $html, $dir);
}
}
public function renderArchive()
{
$archive = Sorting::archive();
$template = "archive.twig";
$pageOptions = [
"title" => "Archive",
"background" => $this->pageInfo["image"],
"archives" => $archive,
"info" => $this->pageInfo,
"menu" => $this->menu,
];
$html = $this->twig->render($template, $pageOptions);
$location = "../public/archives.html";
DocTools::writeHTML($location, $html);
}
public function renderTags()
{
$list = Sorting::tags();
foreach ($list as $item) {
$template = "tags.twig";
$pageOptions = [
"title" => "Pages Tagged as " . $item["tag_name"],
"background" => $this->pageInfo["image"],
"tag_list" => $item["pages"],
"info" => $this->pageInfo,
"menu" => $this->menu,
];
$html = $this->twig->render($template, $pageOptions);
$location = "../public/tags/" . $item["slug"] . ".html";
//if tags folder doesn't exist, make it
if (!is_dir("../public/tags")) {
mkdir("../public/tags", 0755, true);
} else {
}
if (!is_file($location)) {
file_put_contents($location, $html);
} else {
($new = fopen($location, "w")) or die("Unable to open file!");
fwrite($new, $html);
fclose($new);
}
}
}
public function renderIndex()
{
//TODO: Need to fix this to account for new index templating system
$pages = (new Book())->getContents();
$index = find($pages, ["layout" => "index"]);
$template = "index.twig";
$location = "../public/index.html";
$dir = null;
$meta = [
"who" => $index["author"],
"when" => $index["created"],
];
$pageOptions = [
"title" => $index["title"],
"background" => $index["feature"],
"meta" => $meta,
];
$html = $this->twig->render($template, $pageOptions);
DocTools::writeHTML($location, $html, $dir);
}
}

View file

@ -1,90 +0,0 @@
<?php
use function _\find;
use ReallySimpleJWT\Token;
class Session
{
private static $file = "../content/.session";
private static $data = [
"member" => "",
"token" => "",
"form_token" => "",
];
public static function start()
{
if (!is_file(self::$file)) {
file_put_contents(self::$file, json_encode(self::$data));
} else {
($new = fopen(self::$file, "w")) or die("Unable to open file!");
fwrite($new, json_encode(self::$data));
fclose($new);
}
}
public static function active()
{
if (!is_file(self::$file)) {
return false;
} else {
$data = json_decode(file_get_contents(self::$file), true);
if ($data["member"] != null) {
$secret = (new Settings())->getFolks("secret");
if ($secret == null) {
return false;
} else {
if (
Token::validate($data["token"], $secret) &&
Token::validateExpiration($data["token"], $secret)
) {
return true;
} else {
return false;
}
}
} else {
return false;
}
}
}
public static function verifyToken($token)
{
$data = json_decode(file_get_contents(self::$file), true);
if ($data["member"] != null) {
$secret = (new Settings())->getFolks("secret");
if (
Token::validate($token, $secret) &&
Token::validateExpiration($token, $secret)
) {
return true;
} else {
return false;
}
} else {
return false;
}
}
public static function set($key, $value)
{
$data = json_decode(file_get_contents(self::$file), true);
$data[$key] = $value;
($fresh = fopen(self::$file, "w")) or die("Unable to open file!");
fwrite($fresh, json_encode($data));
fclose($fresh);
}
public static function get($key)
{
$data = json_decode(file_get_contents(self::$file), true);
return $data[$key];
}
public static function kill()
{
($fresh = fopen(self::$file, "w")) or die("Unable to open file!");
fwrite($fresh, json_encode(self::$data));
fclose($fresh);
}
}

94
brain/data/Session.php Normal file
View file

@ -0,0 +1,94 @@
<?php
namespace brain\data;
use ReallySimpleJWT\Token;
use function _\find;
class Session
{
private static $file = "../content/.session";
private static $data = [
"member" => "",
"token" => "",
"form_token" => "",
];
public static function start()
{
if (!is_file(self::$file)) {
file_put_contents(self::$file, json_encode(self::$data));
} else {
($new = fopen(self::$file, "w")) or die("Unable to open file!");
fwrite($new, json_encode(self::$data));
fclose($new);
}
}
public static function active()
{
if (!is_file(self::$file)) {
return false;
} else {
$data = json_decode(file_get_contents(self::$file), true);
if ($data["member"] != null) {
$secret = (new Settings())->getFolks("secret");
if ($secret == null) {
return false;
} else {
if (
Token::validate($data["token"], $secret) &&
Token::validateExpiration($data["token"], $secret)
) {
return true;
} else {
return false;
}
}
} else {
return false;
}
}
}
public static function verifyToken($token)
{
$data = json_decode(file_get_contents(self::$file), true);
if ($data["member"] != null) {
$secret = (new Settings())->getFolks("secret");
if (
Token::validate($token, $secret) &&
Token::validateExpiration($token, $secret)
) {
return true;
} else {
return false;
}
} else {
return false;
}
}
public static function set($key, $value)
{
$data = json_decode(file_get_contents(self::$file), true);
$data[$key] = $value;
($fresh = fopen(self::$file, "w")) or die("Unable to open file!");
fwrite($fresh, json_encode($data));
fclose($fresh);
}
public static function get($key)
{
$data = json_decode(file_get_contents(self::$file), true);
return $data[$key];
}
public static function kill()
{
($fresh = fopen(self::$file, "w")) or die("Unable to open file!");
fwrite($fresh, json_encode(self::$data));
fclose($fresh);
}
}

View file

@ -1,169 +0,0 @@
<?php
use function _\find;
use function _\pull;
use function _\remove;
class Settings
{
private $folks;
private static $tags;
private static $settings;
public function __construct()
{
//gets all settings files and converts to php objects
$this->folks = json_decode(file_get_contents("../config/folks.json"), true);
self::$tags = json_decode(file_get_contents("../config/tags.json"), true);
self::$settings = json_decode(
file_get_contents("../config/settings.json"),
true
);
}
public static function sync($data)
{
$settings = self::$settings;
$settings["global"]["base_url"] = $data["global"]["base_url"];
$settings["global"]["title"] = $data["global"]["title"];
$settings["global"]["descriptions"] = $data["global"]["descriptions"];
$settings["global"]["base_url"] = $data["global"]["base_url"];
$settings["global"]["private"] = $data["global"]["private"];
$settings["global"]["renderOnSave"] = $data["global"]["renderOnSave"];
$settings["global"]["theme"] = $data["global"]["theme"];
$settings["global"]["externalAPI"] = $data["global"]["externalAPI"];
$settings["global"]["dynamicRender"] = $data["global"]["dynamicRender"];
Member::updateData("handle", $data["member"]["handle"]);
Member::updateData("email", $data["member"]["email"]);
$settings["email"]["active"] = $data["email"]["active"];
$settings["email"]["smtp"] = $data["email"]["smtp"];
$settings["email"]["mailgun"] = $data["email"]["mailgun"];
DocTools::writeSettings("../config/settings.json", $settings);
}
public static function navSync($data)
{
$settings = self::$settings;
$remove = $data["remove"];
//if remove contains id, find nav item page and set menu to false
if ($remove != null || $remove != "") {
$page = (new Book("../content/pages"))->findPageById($remove);
$page["menu"] = "false";
$page["published"]
? ($page["published"] = "true")
: ($page["published"] = "false");
$page["featured"]
? ($page["featured"] = "true")
: ($page["featured"] = "false");
$page["deleted"]
? ($page["deleted"] = "true")
: ($page["deleted"] = "false");
$updated = new \Moment\Moment();
$created = new \Moment\Moment($page["rawCreated"]);
$page["created"] = $created->format("Y-m-d\TH:i:sP");
$page["updated"] = $updated->format("Y-m-d\TH:i:sP");
$md = DocTools::objectToMD($page);
if ($page["layout"] == "index") {
$writePath = "../content/pages/start/index.md";
} else {
$writePath =
"../content/pages/" . $page["path"] . "/" . $page["slug"] . ".md";
}
DocTools::writePages("write", $page["path"], $writePath, $md);
}
$settings["menu"] = [];
$items = $data["menu"];
foreach ($items as $item) {
array_push($settings["menu"], [
"title" => $item["title"],
"id" => $item["id"],
"uuid" => $item["uuid"],
"slug" => $item["slug"],
"path" => $item["path"],
]);
}
DocTools::writeSettings("../config/settings.json", $settings);
}
public function getFolks($key = null)
{
if (isset($key)) {
$member = Session::get("member");
$found = find($this->folks, ["handle" => $member["handle"]]);
if ($found) {
return $found[$key];
}
} else {
return $this->folks;
}
}
public function getSettings($key = null)
{
return self::$settings;
}
public static function getTags()
{
return self::$tags;
}
public static function updateGlobalData($key, $data)
{
$settings = self::$settings;
$settings["global"][$key] = $data;
DocTools::writeSettings("../config/settings.json", $settings);
}
public static function getCurrentIndex()
{
$settings = self::$settings;
return $settings["library_stats"]["current_index"];
}
public static function updateIndex()
{
$settings = self::$settings;
$settings["library_stats"]["current_index"] =
$settings["library_stats"]["current_index"] + 1;
DocTools::writeSettings("../config/settings.json", $settings);
}
public static function updateMenu($body)
{
$settings = self::$settings;
//$menu = $settings["menu"];
$item = [
"title" => $body["title"],
"id" => $body["id"],
"uuid" => $body["uuid"],
"slug" => $body["slug"],
"path" => $body["path"],
];
if ($body["menu"] == "true") {
if (!find($settings["menu"], ["uuid" => $item["uuid"]])) {
array_push($settings["menu"], $item);
}
} else {
if (find($settings["menu"], ["uuid" => $item["uuid"]])) {
pull($settings["menu"], $item);
}
}
DocTools::writeSettings("../config/settings.json", $settings);
}
public static function updateTags()
{
$tags = Sorting::tags();
DocTools::writeSettings("../config/tags.json", $tags);
}
}

177
brain/data/Settings.php Normal file
View file

@ -0,0 +1,177 @@
<?php
namespace brain\data;
use brain\data\Member;
use brain\utility\DocTools;
use brain\utility\Sorting;
use function _\find;
use function _\pull;
use function _\remove;
class Settings
{
private $folks;
private static $tags;
private static $settings;
public function __construct()
{
//gets all settings files and converts to php objects
$this->folks = json_decode(file_get_contents("../config/folks.json"), true);
self::$tags = json_decode(file_get_contents("../config/tags.json"), true);
self::$settings = json_decode(
file_get_contents("../config/settings.json"),
true
);
}
public static function sync($data)
{
$settings = self::$settings;
$settings["global"]["base_url"] = $data["global"]["base_url"];
$settings["global"]["title"] = $data["global"]["title"];
$settings["global"]["descriptions"] = $data["global"]["descriptions"];
$settings["global"]["base_url"] = $data["global"]["base_url"];
$settings["global"]["private"] = $data["global"]["private"];
$settings["global"]["renderOnSave"] = $data["global"]["renderOnSave"];
$settings["global"]["theme"] = $data["global"]["theme"];
$settings["global"]["externalAPI"] = $data["global"]["externalAPI"];
$settings["global"]["dynamicRender"] = $data["global"]["dynamicRender"];
Member::updateData("handle", $data["member"]["handle"]);
Member::updateData("email", $data["member"]["email"]);
$settings["email"]["active"] = $data["email"]["active"];
$settings["email"]["smtp"] = $data["email"]["smtp"];
$settings["email"]["mailgun"] = $data["email"]["mailgun"];
DocTools::writeSettings("../config/settings.json", $settings);
}
public static function navSync($data)
{
$settings = self::$settings;
$remove = $data["remove"];
//if remove contains id, find nav item page and set menu to false
if ($remove != null || $remove != "") {
$page = (new Book("../content/pages"))->findPageById($remove);
$page["menu"] = "false";
$page["published"]
? ($page["published"] = "true")
: ($page["published"] = "false");
$page["featured"]
? ($page["featured"] = "true")
: ($page["featured"] = "false");
$page["deleted"]
? ($page["deleted"] = "true")
: ($page["deleted"] = "false");
$updated = new \Moment\Moment();
$created = new \Moment\Moment($page["rawCreated"]);
$page["created"] = $created->format("Y-m-d\TH:i:sP");
$page["updated"] = $updated->format("Y-m-d\TH:i:sP");
$md = DocTools::objectToMD($page);
if ($page["layout"] == "index") {
$writePath = "../content/pages/start/index.md";
} else {
$writePath =
"../content/pages/" . $page["path"] . "/" . $page["slug"] . ".md";
}
DocTools::writePages("write", $page["path"], $writePath, $md);
}
$settings["menu"] = [];
$items = $data["menu"];
foreach ($items as $item) {
array_push($settings["menu"], [
"title" => $item["title"],
"id" => $item["id"],
"uuid" => $item["uuid"],
"slug" => $item["slug"],
"path" => $item["path"],
]);
}
DocTools::writeSettings("../config/settings.json", $settings);
}
public function getFolks($key = null)
{
if (isset($key)) {
$member = Session::get("member");
$found = find($this->folks, ["handle" => $member["handle"]]);
if ($found) {
return $found[$key];
}
} else {
return $this->folks;
}
}
public function getSettings($key = null)
{
return self::$settings;
}
public static function getTags()
{
return self::$tags;
}
public static function updateGlobalData($key, $data)
{
$settings = self::$settings;
$settings["global"][$key] = $data;
DocTools::writeSettings("../config/settings.json", $settings);
}
public static function getCurrentIndex()
{
$settings = self::$settings;
return $settings["library_stats"]["current_index"];
}
public static function updateIndex()
{
$settings = self::$settings;
$settings["library_stats"]["current_index"] =
$settings["library_stats"]["current_index"] + 1;
DocTools::writeSettings("../config/settings.json", $settings);
}
public static function updateMenu($body)
{
$settings = self::$settings;
//$menu = $settings["menu"];
$item = [
"title" => $body["title"],
"id" => $body["id"],
"uuid" => $body["uuid"],
"slug" => $body["slug"],
"path" => $body["path"],
];
if ($body["menu"] == "true") {
if (!find($settings["menu"], ["uuid" => $item["uuid"]])) {
array_push($settings["menu"], $item);
}
} else {
if (find($settings["menu"], ["uuid" => $item["uuid"]])) {
pull($settings["menu"], $item);
}
}
DocTools::writeSettings("../config/settings.json", $settings);
}
public static function updateTags()
{
$tags = Sorting::tags();
DocTools::writeSettings("../config/tags.json", $tags);
}
}

View file

@ -1,60 +0,0 @@
<?php
class Themes
{
private $themes = [];
public function __construct()
{
$_themes = glob("../content/themes/*", GLOB_ONLYDIR);
foreach ($_themes as $theme) {
array_push(
$this->themes,
json_decode(file_get_contents($theme . "/theme.json"), true)
);
}
}
public function getThemes()
{
return $this->themes;
}
public function getCustomIndex()
{
$settings = (new Settings())->getSettings();
$currentTheme = $settings["global"]["theme"];
$folder = "../content/themes/" . $currentTheme;
$files = array_filter(glob("$folder/*twig"), "is_file");
$views = [];
foreach ($files as $file) {
$path = explode("/", $file);
$fileName = $path[4];
if (str_contains($fileName, "index")) {
$page = explode(".", $fileName);
$views[] = $page[0];
}
}
return $views;
}
public function getCustomViews()
{
$settings = (new Settings())->getSettings();
$currentTheme = $settings["global"]["theme"];
$folder = "../content/themes/" . $currentTheme;
$files = array_filter(glob("$folder/*twig"), "is_file");
$views = [];
foreach ($files as $file) {
$path = explode("/", $file);
$fileName = $path[4];
if (str_contains($fileName, "page")) {
$page = explode(".", $fileName);
$views[] = $page[0];
}
}
return $views;
}
}

64
brain/data/Themes.php Normal file
View file

@ -0,0 +1,64 @@
<?php
namespace brain\data;
use brain\data\Settings;
class Themes
{
private $themes = [];
public function __construct()
{
$_themes = glob("../content/themes/*", GLOB_ONLYDIR);
foreach ($_themes as $theme) {
array_push(
$this->themes,
json_decode(file_get_contents($theme . "/theme.json"), true)
);
}
}
public function getThemes()
{
return $this->themes;
}
public function getCustomIndex()
{
$settings = (new Settings())->getSettings();
$currentTheme = $settings["global"]["theme"];
$folder = "../content/themes/" . $currentTheme;
$files = array_filter(glob("$folder/*twig"), "is_file");
$views = [];
foreach ($files as $file) {
$path = explode("/", $file);
$fileName = $path[4];
if (str_contains($fileName, "index")) {
$page = explode(".", $fileName);
$views[] = $page[0];
}
}
return $views;
}
public function getCustomViews()
{
$settings = (new Settings())->getSettings();
$currentTheme = $settings["global"]["theme"];
$folder = "../content/themes/" . $currentTheme;
$files = array_filter(glob("$folder/*twig"), "is_file");
$views = [];
foreach ($files as $file) {
$path = explode("/", $file);
$fileName = $path[4];
if (str_contains($fileName, "page")) {
$page = explode(".", $fileName);
$views[] = $page[0];
}
}
return $views;
}
}

36
brain/init/App.php Normal file
View file

@ -0,0 +1,36 @@
<?php
namespace brain\init;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
use Slim\Views\Twig;
use Slim\Views\TwigMiddleware;
// Fipamo Core Classes
use brain\utility\HandleCors;
class App
{
public function __construct()
{
// when a new class is made, run composer dump-autoload
// set up cors
new HandleCors();
$app = AppFactory::create();
$twig = Twig::create("../brain/views/");
$app->add(TwigMiddleware::create($app, $twig));
//set up routing
$app->get(
"/[{first}[/{second}[/{third}[/{fourth}[/{fifth}]]]]]",
"brain\controller\RouteControl:get"
);
$app->post(
"/[{first}[/{second}[/{third}[/{fourth}]]]]",
"brain\controller\RouteControl:post"
);
//start the app
$app->run();
}
}

View file

@ -1,140 +0,0 @@
<?php
class DocTools
{
public function __construct()
{
}
public static function writePages($task, $path, $fileLocation, $fileContents)
{
try {
if ($task == "create") {
if (!is_dir("../content/pages/" . $path)) {
//Directory does not exist, so lets create it.
mkdir("../content/pages/" . $path, 0755, true);
}
file_put_contents($fileLocation, $fileContents);
} else {
($new = fopen($fileLocation, "w")) or die("Unable to open file!");
fwrite($new, $fileContents);
fclose($new);
}
return true;
} catch (Error $error) {
return false;
}
}
public static function writeSettings($fileLocation, $fileContents)
{
if (!is_file($fileLocation)) {
file_put_contents($fileLocation, json_encode($fileContents));
} else {
($new = fopen($fileLocation, "w")) or die("Unable to open file!");
fwrite($new, json_encode($fileContents));
fclose($new);
}
}
public static function writeHTML($location, $html, $path = null)
{
if ($path != null) {
if (!is_dir($path)) {
//Directory does not exist, so lets create it.
mkdir($path, 0755, true);
}
}
if (!is_file($location)) {
file_put_contents($location, $html);
} else {
($new = fopen($location, "w")) or die("Unable to open file!");
fwrite($new, $html);
fclose($new);
}
}
public static function deleteFolder($path)
{
if (!empty($path) && is_dir($path)) {
$dir = new RecursiveDirectoryIterator(
$path,
RecursiveDirectoryIterator::SKIP_DOTS
); //upper dirs are not included,otherwise DISASTER HAPPENS :)
$files = new RecursiveIteratorIterator(
$dir,
RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($files as $f) {
if (is_file($f)) {
unlink($f);
} else {
$empty_dirs[] = $f;
}
}
if (!empty($empty_dirs)) {
foreach ($empty_dirs as $eachDir) {
rmdir($eachDir);
}
}
rmdir($path);
}
}
public static function objectToMD($object)
{
$markdown =
"---\n" .
"id: " .
$object["id"] .
"\n" .
"uuid: " .
$object["uuid"] .
"\n" .
"title: " .
"'" .
$object["title"] .
"'" .
"\n" .
"feature: " .
$object["feature"] .
"\n" .
"path: " .
$object["path"] .
"\n" .
"layout: " .
$object["layout"] .
"\n" .
"tags: " .
$object["tags"] .
"\n" .
"author: " .
$object["author"] .
"\n" .
"created: " .
$object["created"] .
"\n" .
"updated: " .
$object["updated"] .
"\n" .
"deleted: " .
$object["deleted"] .
"\n" .
"slug: " .
$object["slug"] .
"\n" .
"menu: " .
$object["menu"] .
"\n" .
"published: " .
$object["published"] .
"\n" .
"featured: " .
$object["featured"] .
"\n---\n" .
$object["content"];
return $markdown;
}
}

145
brain/utility/DocTools.php Normal file
View file

@ -0,0 +1,145 @@
<?php
namespace brain\utility;
class DocTools
{
public function __construct()
{
}
public static function writePages($task, $path, $fileLocation, $fileContents)
{
try {
if ($task == "create") {
if (!is_dir("../content/pages/" . $path)) {
//Directory does not exist, so lets create it.
mkdir("../content/pages/" . $path, 0755, true);
}
file_put_contents($fileLocation, $fileContents);
} else {
($new = fopen($fileLocation, "w")) or die("Unable to open file!");
fwrite($new, $fileContents);
fclose($new);
}
return true;
} catch (Error $error) {
return false;
}
}
public static function writeSettings($fileLocation, $fileContents)
{
if (!is_file($fileLocation)) {
file_put_contents($fileLocation, json_encode($fileContents));
} else {
($new = fopen($fileLocation, "w")) or die("Unable to open file!");
fwrite($new, json_encode($fileContents));
fclose($new);
}
}
public static function writeHTML($location, $html, $path = null)
{
if ($path != null) {
if (!is_dir($path)) {
//Directory does not exist, so lets create it.
mkdir($path, 0755, true);
}
}
if (!is_file($location)) {
file_put_contents($location, $html);
} else {
($new = fopen($location, "w")) or die("Unable to open file!");
fwrite($new, $html);
fclose($new);
}
}
public static function deleteFolder($path)
{
if (!empty($path) && is_dir($path)) {
$dir = new \RecursiveDirectoryIterator(
$path,
\RecursiveDirectoryIterator::SKIP_DOTS
); //upper dirs are not included,otherwise DISASTER HAPPENS :)
$files = new \RecursiveIteratorIterator(
$dir,
\RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($files as $f) {
if (is_file($f)) {
unlink($f);
} else {
$empty_dirs[] = $f;
}
}
if (!empty($empty_dirs)) {
foreach ($empty_dirs as $eachDir) {
rmdir($eachDir);
}
}
rmdir($path);
}
}
public static function objectToMD($object)
{
$markdown =
"---\n" .
"id: " .
$object["id"] .
"\n" .
"uuid: " .
$object["uuid"] .
"\n" .
"title: " .
"'" .
$object["title"] .
"'" .
"\n" .
"feature: " .
$object["feature"] .
"\n" .
"files: " .
$object["files"] .
"\n" .
"path: " .
$object["path"] .
"\n" .
"layout: " .
$object["layout"] .
"\n" .
"tags: " .
$object["tags"] .
"\n" .
"author: " .
$object["author"] .
"\n" .
"created: " .
$object["created"] .
"\n" .
"updated: " .
$object["updated"] .
"\n" .
"deleted: " .
$object["deleted"] .
"\n" .
"slug: " .
$object["slug"] .
"\n" .
"menu: " .
$object["menu"] .
"\n" .
"published: " .
$object["published"] .
"\n" .
"featured: " .
$object["featured"] .
"\n---\n" .
$object["content"];
return $markdown;
}
}

View file

@ -1,32 +0,0 @@
<?php
use Psr\Http\Message\UploadedFileInterface;
//include "brain/data/Auth.inc.php";
define("MAXIMUM_FILESIZE", "10485760"); //10 MB
class FileUploader
{
public static function uploadFile(string $directory, $file)
{
$response = [];
try {
if (!is_dir($directory)) {
//Directory does not exist, so lets create it.
mkdir($directory, 0755, true);
}
//$upload = move_uploaded_file($file->getClientFileName(), $directory);
//$extension = pathinfo($file->getClientFilename(), PATHINFO_EXTENSION);
// see http://php.net/manual/en/function.random-bytes.php
//$basename = bin2hex(random_bytes(8));
//$filename = sprintf("%s.%0.8s", $basename, $extension);
//echo "**FILE** " . $file->getClientFileName();
$file->moveTo($directory . "/" . $file->getClientFileName());
} catch (RuntimeException $e) {
echo "ERROR " . $e->getMessage();
//echo "failed to upload image: " . $e->getMessage();
//throw new Error("Failed to upload image file");
}
}
}

View file

@ -0,0 +1,32 @@
<?php
namespace brain\utility;
class FileUploader
{
public static function uploadFile(string $directory, $file)
{
$response = [];
try {
if (!is_dir($directory)) {
// Directory does not exist, so lets create it.
mkdir($directory, 0755, true);
}
// $upload = move_uploaded_file($file->getClientFileName(), $directory);
// $extension = pathinfo($file->getClientFilename(), PATHINFO_EXTENSION);
// see http://php.net/manual/en/function.random-bytes.php
// $basename = bin2hex(random_bytes(8));
// $filename = sprintf("%s.%0.8s", $basename, $extension);
// echo "**FILE** " . $file->getClientFileName();
$file->moveTo($directory.'/'.urlencode($file->getClientFileName()));
} catch (RuntimeException $e) {
echo 'ERROR '.$e->getMessage();
// echo "failed to upload image: " . $e->getMessage();
// throw new Error("Failed to upload image file");
}
}
}

View file

@ -1,6 +1,10 @@
<?php
class handleCors
namespace brain\utility;
use brain\data\Settings;
class HandleCors
{
public function __construct()
{

View file

@ -1,94 +0,0 @@
<?php
use Slim\Views\Twig;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
class Mailer
{
public static function sendMail($body)
{
$config = new Settings();
$settings = $config->getSettings();
$mailConfig = $settings["email"];
$mail = new PHPMailer();
switch ($body["mail_task"]) {
case "TESTING":
$html =
"<h1>Hi! It's Fipamo!</h1><br>" .
"<strong>It's just a test</strong><br>" .
$body["content"];
$member = Session::get("member");
$mail->addAddress($member["email"], ""); //pull email address from current user
$mail->Subject = "A test email";
break;
case "SEND_SECRET":
$html =
"<h1>Hi! It's Fipamo!</h1><br>" .
"<strong>This is your secret key.</strong><br><br>" .
"<h3>" .
$body["secret"] .
"</h3>" .
"<br> Use this key to reset your password.";
$mail->addAddress($body["email"], ""); //pull email address from current user
$mail->Subject = "Shhhh! It's a secret!";
break;
default:
return $result = [
"type" => "noMailService",
"message" => "Mail task is undefined. What are you doing??",
];
break;
}
//set values based on current active protocol
switch ($mailConfig["active"]) {
case "option-smtp":
$mail->setFrom($mailConfig["smtp"]["email"], "System Email");
$mail->Host = "playvicio.us";
$mail->Username = $mailConfig["smtp"]["email"];
$mail->Password = $mailConfig["smtp"]["password"];
break;
case "option-mg":
$mail->setFrom($mailConfig["mailgun"]["domain"], "No Reply");
$mail->Host = "smtp.mailgun.org";
$mail->Username = $mailConfig["mailgun"]["domain"];
$mail->Password = $mailConfig["mailgun"]["key"];
break;
default:
//no mail service
return $result = [
"type" => "noMailService",
"message" => "Mail is not configured. Handle that.",
];
break;
}
$mail->Body = $html;
$mail->IsHTML(true);
$mail->isSMTP();
$mail->SMTPAuth = true;
$mail->SMTPSecure = "ssl";
$mail->Port = 465;
// Uncomment for debug info
//$mail->SMTPDebug = 4;
/* Finally send the mail. */
try {
$mail->send();
$result = ["type" => "mailSent", "message" => "Message Away!"];
} catch (Exception $e) {
//echo $e->errorMessage();
$result = [
"type" => "mailNotSent",
"message" => "Message Not Away!",
"error" => $e->errorMessage(),
];
}
return $result;
}
}

98
brain/utility/Mailer.php Normal file
View file

@ -0,0 +1,98 @@
<?php
namespace brain\utility;
use Slim\Views\Twig;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
use brain\data\Settings;
use brain\data\Session;
class Mailer
{
public static function sendMail($body)
{
$config = new Settings();
$settings = $config->getSettings();
$mailConfig = $settings["email"];
$mail = new PHPMailer();
switch ($body["mail_task"]) {
case "TESTING":
$html =
"<h1>Hi! It's Fipamo!</h1><br>" .
"<strong>It's just a test</strong><br>" .
$body["content"];
$member = Session::get("member");
$mail->addAddress($member["email"], ""); //pull email address from current user
$mail->Subject = "A test email";
break;
case "SEND_SECRET":
$html =
"<h1>Hi! It's Fipamo!</h1><br>" .
"<strong>This is your secret key.</strong><br><br>" .
"<h3>" .
$body["secret"] .
"</h3>" .
"<br> Use this key to reset your password.";
$mail->addAddress($body["email"], ""); //pull email address from current user
$mail->Subject = "Shhhh! It's a secret!";
break;
default:
return $result = [
"type" => "noMailService",
"message" => "Mail task is undefined. What are you doing??",
];
break;
}
//set values based on current active protocol
switch ($mailConfig["active"]) {
case "option-smtp":
$mail->setFrom($mailConfig["smtp"]["email"], "System Email");
$mail->Host = "playvicio.us";
$mail->Username = $mailConfig["smtp"]["email"];
$mail->Password = $mailConfig["smtp"]["password"];
break;
case "option-mg":
$mail->setFrom($mailConfig["mailgun"]["domain"], "No Reply");
$mail->Host = "smtp.mailgun.org";
$mail->Username = $mailConfig["mailgun"]["domain"];
$mail->Password = $mailConfig["mailgun"]["key"];
break;
default:
//no mail service
return $result = [
"type" => "noMailService",
"message" => "Mail is not configured. Handle that.",
];
break;
}
$mail->Body = $html;
$mail->IsHTML(true);
$mail->isSMTP();
$mail->SMTPAuth = true;
$mail->SMTPSecure = "ssl";
$mail->Port = 465;
// Uncomment for debug info
//$mail->SMTPDebug = 4;
/* Finally send the mail. */
try {
$mail->send();
$result = ["type" => "mailSent", "message" => "Message Away!"];
} catch (Exception $e) {
//echo $e->errorMessage();
$result = [
"type" => "mailNotSent",
"message" => "Message Not Away!",
"error" => $e->errorMessage(),
];
}
return $result;
}
}

View file

@ -1,99 +0,0 @@
<?php
class Maintenance
{
public function __construct()
{
}
public static function makeBackup()
{
//make sure back directory is there
if (!is_dir("../config/backups")) {
mkdir("../config/backups", 0755, true);
}
//creat backup zip
$zip = new ZipArchive();
$zip->open(
"../config/backups/latest_back.zip",
ZipArchive::CREATE | ZipArchive::OVERWRITE
);
//gather data and path info for md pages
$pagePath = "../content/pages";
$yearPaths = glob($pagePath . "/*", GLOB_ONLYDIR);
foreach ($yearPaths as $years) {
$year = explode("/", $years);
//grap the index and save it
if (trim($year[3]) == "start") {
$options = [
"add_path" => "content/pages/" . $year[3] . "/",
"remove_all_path" => true,
];
$zip->addGlob($years . "/*.md", GLOB_BRACE, $options);
}
$monthsPath = glob($pagePath . "/" . $year[3] . "/*", GLOB_ONLYDIR);
foreach ($monthsPath as $months) {
$month = explode("/", $months);
//once info is collected, add md pages to zip
$options = [
"add_path" => "content/pages/" . $year[3] . "/" . $month[4] . "/",
"remove_all_path" => true,
];
$zip->addGlob($months . "/*.md", GLOB_BRACE, $options);
}
}
//gather data and path info for blog images
$blogImagesPath = "../public/assets/images/blog";
$yearPaths = glob($blogImagesPath . "/*", GLOB_ONLYDIR);
foreach ($yearPaths as $years) {
$year = explode("/", $years);
$monthsPath = glob($blogImagesPath . "/" . $year[5] . "/*", GLOB_ONLYDIR);
foreach ($monthsPath as $months) {
$month = explode("/", $months);
//once info is collected, add images pages to zip
$options = [
"add_path" =>
"public/assets/images/blog/" . $year[5] . "/" . $month[6] . "/",
"remove_all_path" => true,
];
$zip->addGlob($months . "/*.*", GLOB_BRACE, $options);
}
}
//gather data and path info for user images
$userImagesPath = "../public/assets/images/user";
$yearPaths = glob($userImagesPath . "/*", GLOB_ONLYDIR);
foreach ($yearPaths as $years) {
$year = explode("/", $years);
$monthsPath = glob($userImagesPath . "/" . $year[5] . "/*", GLOB_ONLYDIR);
foreach ($monthsPath as $months) {
$month = explode("/", $months);
//once info is collected, add images pages to zip
$options = [
"add_path" =>
"public/assets/images/user/" . $year[5] . "/" . $month[6] . "/",
"remove_all_path" => true,
];
$zip->addGlob($months . "/*.*", GLOB_BRACE, $options);
}
}
//add directory for settings and save them
$zip->addEmptyDir("settings");
$zip->addFile("../config/settings.json", "settings/settings.json");
$zip->addFile("../config/folks.json", "settings/folks.json");
$zip->addFile("../config/tags.json", "settings/tags.json");
//save zip file
$zip->close();
//update settings file with latest back up date
$updated = new \Moment\Moment();
Settings::updateGlobalData(
"last_backup",
$updated->format("Y-m-d\TH:i:sP")
);
$result = ["message" => "Backup created. THIS IS A SAFE SPACE!"];
return $result;
}
}

View file

@ -0,0 +1,104 @@
<?php
namespace brain\utility;
use brain\data\Settings;
class Maintenance
{
public function __construct()
{
}
public static function makeBackup()
{
//make sure back directory is there
if (!is_dir("../config/backups")) {
mkdir("../config/backups", 0755, true);
}
//creat backup zip
$zip = new \ZipArchive();
$zip->open(
"../config/backups/latest_back.zip",
\ZipArchive::CREATE | \ZipArchive::OVERWRITE
);
//gather data and path info for md pages
$pagePath = "../content/pages";
$yearPaths = glob($pagePath . "/*", GLOB_ONLYDIR);
foreach ($yearPaths as $years) {
$year = explode("/", $years);
//grap the index and save it
if (trim($year[3]) == "start") {
$options = [
"add_path" => "content/pages/" . $year[3] . "/",
"remove_all_path" => true,
];
$zip->addGlob($years . "/*.md", GLOB_BRACE, $options);
}
$monthsPath = glob($pagePath . "/" . $year[3] . "/*", GLOB_ONLYDIR);
foreach ($monthsPath as $months) {
$month = explode("/", $months);
//once info is collected, add md pages to zip
$options = [
"add_path" => "content/pages/" . $year[3] . "/" . $month[4] . "/",
"remove_all_path" => true,
];
$zip->addGlob($months . "/*.md", GLOB_BRACE, $options);
}
}
//gather data and path info for blog images
$blogImagesPath = "../public/assets/images/blog";
$yearPaths = glob($blogImagesPath . "/*", GLOB_ONLYDIR);
foreach ($yearPaths as $years) {
$year = explode("/", $years);
$monthsPath = glob($blogImagesPath . "/" . $year[5] . "/*", GLOB_ONLYDIR);
foreach ($monthsPath as $months) {
$month = explode("/", $months);
//once info is collected, add images pages to zip
$options = [
"add_path" =>
"public/assets/images/blog/" . $year[5] . "/" . $month[6] . "/",
"remove_all_path" => true,
];
$zip->addGlob($months . "/*.*", GLOB_BRACE, $options);
}
}
//gather data and path info for user images
$userImagesPath = "../public/assets/images/user";
$yearPaths = glob($userImagesPath . "/*", GLOB_ONLYDIR);
foreach ($yearPaths as $years) {
$year = explode("/", $years);
$monthsPath = glob($userImagesPath . "/" . $year[5] . "/*", GLOB_ONLYDIR);
foreach ($monthsPath as $months) {
$month = explode("/", $months);
//once info is collected, add images pages to zip
$options = [
"add_path" =>
"public/assets/images/user/" . $year[5] . "/" . $month[6] . "/",
"remove_all_path" => true,
];
$zip->addGlob($months . "/*.*", GLOB_BRACE, $options);
}
}
//add directory for settings and save them
$zip->addEmptyDir("settings");
$zip->addFile("../config/settings.json", "settings/settings.json");
$zip->addFile("../config/folks.json", "settings/folks.json");
$zip->addFile("../config/tags.json", "settings/tags.json");
//save zip file
$zip->close();
//update settings file with latest back up date
$updated = new \Moment\Moment();
Settings::updateGlobalData(
"last_backup",
$updated->format("Y-m-d\TH:i:sP")
);
$result = ["message" => "Backup created. THIS IS A SAFE SPACE!"];
return $result;
}
}

View file

@ -1,223 +0,0 @@
<?php
use function _\find;
class SetUp
{
public static function status()
{
if (file_exists("../config/settings.json")) {
return true;
} else {
return false;
}
}
public static function init($body)
{
//grab template files
$newFolks = json_decode(
file_get_contents("../config/init/folks-template.json"),
true
);
$newSettings = json_decode(
file_get_contents("../config/init/settings-template.json"),
true
);
//get form values
//$body = $request->getParsedBody();
$handle = $body["new_member_handle"];
$email = $body["new_member_email"];
$pass = $body["new_member_pass"];
$title = $body["new_member_title"];
$now = new \Moment\Moment();
//setup folks config
$hash = password_hash($pass, PASSWORD_DEFAULT);
$newFolks[0]["id"] = 0;
$newFolks[0]["handle"] = $handle;
$newFolks[0]["email"] = $email;
$newFolks[0]["password"] = $hash;
$newFolks[0]["key"] = password_hash($email, PASSWORD_DEFAULT);
$newFolks[0]["secret"] = StringTools::randomString(12);
$newFolks[0]["role"] = "hnic";
$newFolks[0]["created"] = $now->format("Y-m-d\TH:i:sP");
$newFolks[0]["updated"] = $now->format("Y-m-d\TH:i:sP");
//set up settings config
$newSettings["global"]["title"] = $title;
//create index file
//$rightNow = $now->format("Y-m-d\TH:i:sP");
//var_dump($now->format("Y-m-d\TH:i:sP"));
$index = [
"id" => 1,
"uuid" => StringTools::createUUID(),
"title" => "FIRST!",
"feature" => "/assets/images/global/default-bg.jpg",
"path" => "content/pages/start",
"layout" => "index",
"tags" => "start, welcome",
"author" => $handle,
"created" => $now->format("Y-m-d\TH:i:sP"),
"updated" => $now->format("Y-m-d\TH:i:sP"),
"deleted" => "false",
"slug" => "first",
"menu" => "false",
"featured" => "false",
"published" => "true",
"content" =>
"# F**k Yes \n\nIf you're seeing this, you're up and running. NICE WORK!\n\nFrom here, feel free to start dropping pages to your heart's content.\n\nFor some tips about using Fipamo, check out the ![docs](https://code.playvicio.us/Are0h/Fipamo/wiki/02-Usage)\n\nAll good? Feel free to edit this page to whatever you want!\n\nYOU'RE THE CAPTAIN NOW.",
];
$freshIndex = DocTools::objectToMD($index);
//once all files created, write down
DocTools::writeSettings("../config/settings.json", $newSettings);
DocTools::writeSettings("../config/folks.json", $newFolks);
DocTools::writeSettings("../config/tags.json", []);
DocTools::writePages(
"create",
"start",
"../content/pages/start/index.md",
$freshIndex
);
//if there is an older session file, get rid of it
if (is_file("../content/.session")) {
unlink("../content/.session");
}
$result = ["type" => "blogInitGood", "message" => "Site Created"];
return $result;
}
public static function restore($request)
{
$result = [
"type" => "requestLame",
"message" => "Still working on it.",
];
$body = $request->getParsedBody();
$backup = $request->getUploadedFiles();
$file = $backup["backup-upload"];
$size = $file->getSize();
$name = $file->getClientFileName();
//park it so it can be read
$file->moveTo("../content" . "/" . $name);
//open it and get files to verify user
$zip = new ZipArchive();
if ($zip->open("../content" . "/" . $name) === true) {
$folks = json_decode($zip->getFromName("settings/folks.json"), true);
$found = find($folks, ["handle" => $body["restore_member_handle"]]);
//if member is found in back up, check pass
if ($found) {
if (password_verify($body["restore_member_pass"], $found["password"])) {
//backup verified, restore site
//set new secret key for older folks configs
$newFolks = [];
if (!isset($found["secret"])) {
$found["secret"] = StringTools::randomString(12);
}
array_push($newFolks, $found);
//dump files in folder
$zip->extractTo("../content");
//move to appropriate spots
/*
rename(
"../content/settings/settings.json",
"../config/settings.json"
);
*/
//load up old config file
$newConfig = json_decode(
file_get_contents("../content/settings/settings.json"),
true
);
//check for key, add if not there
if (!isset($newConfig["global"]["externalAPI"])) {
$newConfig["global"]["externalAPI"] = "false";
}
//write new config file
DocTools::writeSettings("../config/settings.json", $newConfig);
//rename("../content/settings/folks.json", "../config/folks.json");
DocTools::writeSettings("../config/folks.json", $newFolks);
rename("../content/settings/tags.json", "../config/tags.json");
//images path for blog and user
$blogImagePath = "../public/assets/images/blog";
$userImagePath = "../public/assets/images/user";
//check to see if image dirs are empty, if not chill
if ($globs = glob($blogImagePath . "/*")) {
//directory not empty, relax
} else {
rename("../content/public/assets/images/blog", $blogImagePath);
}
if ($globs = glob($userImagePath . "/*")) {
//directory not empty, relax
} else {
rename("../content/public/assets/images/user", $userImagePath);
}
rename("../content/content/pages/", "../content/pages");
//legacy check for old file structure
if (is_file("../content/pages/index.md")) {
if (!is_dir("../content/pages/start")) {
//Directory does not exist, so lets create it.
mkdir("../content/pages/start", 0755, true);
//move start page to appropriate spot
rename(
"../content/pages/index.md",
"../content/pages/start/index.md"
);
}
} else {
//chill
}
//clean up
DocTools::deleteFolder("../content/settings");
DocTools::deleteFolder("../content/public");
DocTools::deleteFolder("../content/content");
$result = [
"type" => "requestGood",
"message" => "Site Restored! Redirecting",
];
} else {
$result = [
"type" => "requestLame",
"message" => "Check that password, champ.",
];
}
} else {
$result = [
"type" => "requestLame",
"message" => "No member found by that name, hoss",
];
}
$zip->close();
$zipPath = "../content/" . $name;
//trash zip when done
unlink($zipPath);
} else {
$result = [
"type" => "requestLame",
"message" => "Could not open backup. RATS!",
];
}
return $result;
}
}

229
brain/utility/Setup.php Normal file
View file

@ -0,0 +1,229 @@
<?php
namespace brain\utility;
use function _\find;
class SetUp
{
public static function status()
{
if (file_exists("../config/settings.json")) {
return true;
} else {
return false;
}
}
public static function init($body)
{
//grab template files
$newFolks = json_decode(
file_get_contents("../config/init/folks-template.json"),
true
);
$newSettings = json_decode(
file_get_contents("../config/init/settings-template.json"),
true
);
//get form values
//$body = $request->getParsedBody();
$handle = $body["new_member_handle"];
$email = $body["new_member_email"];
$pass = $body["new_member_pass"];
$title = $body["new_member_title"];
$now = new \Moment\Moment();
//setup folks config
$hash = password_hash($pass, PASSWORD_DEFAULT);
$newFolks[0]["id"] = 0;
$newFolks[0]["handle"] = $handle;
$newFolks[0]["email"] = $email;
$newFolks[0]["password"] = $hash;
$newFolks[0]["key"] = password_hash($email, PASSWORD_DEFAULT);
$newFolks[0]["secret"] = StringTools::randomString(12);
$newFolks[0]["role"] = "hnic";
$newFolks[0]["created"] = $now->format("Y-m-d\TH:i:sP");
$newFolks[0]["updated"] = $now->format("Y-m-d\TH:i:sP");
//set up settings config
$newSettings["global"]["title"] = $title;
//create index file
//$rightNow = $now->format("Y-m-d\TH:i:sP");
//var_dump($now->format("Y-m-d\TH:i:sP"));
$index = [
"id" => 1,
"uuid" => StringTools::createUUID(),
"title" => "FIRST!",
"feature" => "/assets/images/global/default-bg.jpg",
"files" => "",
"path" => "content/pages/start",
"layout" => "index",
"tags" => "start, welcome",
"author" => $handle,
"created" => $now->format("Y-m-d\TH:i:sP"),
"updated" => $now->format("Y-m-d\TH:i:sP"),
"deleted" => "false",
"slug" => "first",
"menu" => "false",
"featured" => "false",
"published" => "true",
"content" =>
"# F**k Yes \n\nIf you're seeing this, you're up and running. NICE WORK!\n\nFrom here, feel free to start dropping pages to your heart's content.\n\nFor some tips about using Fipamo, check out the ![docs](https://code.playvicio.us/Are0h/Fipamo/wiki/02-Usage)\n\nAll good? Feel free to edit this page to whatever you want!\n\nYOU'RE THE CAPTAIN NOW.",
];
$freshIndex = DocTools::objectToMD($index);
//once all files created, write down
DocTools::writeSettings("../config/settings.json", $newSettings);
DocTools::writeSettings("../config/folks.json", $newFolks);
DocTools::writeSettings("../config/tags.json", []);
DocTools::writePages(
"create",
"start",
"../content/pages/start/index.md",
$freshIndex
);
//if there is an older session file, get rid of it
if (is_file("../content/.session")) {
unlink("../content/.session");
}
$result = ["type" => "blogInitGood", "message" => "Site Created"];
return $result;
}
public static function restore($request)
{
$result = [
"type" => "requestLame",
"message" => "Still working on it.",
];
$body = $request->getParsedBody();
$backup = $request->getUploadedFiles();
$file = $backup["backup-upload"];
//NOTE: If this fails check 'post_max_size' in php.ini
$size = $file->getSize();
$name = $file->getClientFileName();
//park it so it can be read
$file->moveTo("../content" . "/" . $name);
//open it and get files to verify user
$zip = new \ZipArchive();
if ($zip->open("../content" . "/" . $name) === true) {
$folks = json_decode($zip->getFromName("settings/folks.json"), true);
$found = find($folks, ["handle" => $body["restore_member_handle"]]);
//if member is found in back up, check pass
if ($found) {
if (password_verify($body["restore_member_pass"], $found["password"])) {
//backup verified, restore site
//set new secret key for older folks configs
$newFolks = [];
if (!isset($found["secret"])) {
$found["secret"] = StringTools::randomString(12);
}
array_push($newFolks, $found);
//dump files in folder
$zip->extractTo("../content");
//move to appropriate spots
/*
rename(
"../content/settings/settings.json",
"../config/settings.json"
);
*/
//load up old config file
$newConfig = json_decode(
file_get_contents("../content/settings/settings.json"),
true
);
//check for key, add if not there
if (!isset($newConfig["global"]["externalAPI"])) {
$newConfig["global"]["externalAPI"] = "false";
}
//write new config file
DocTools::writeSettings("../config/settings.json", $newConfig);
//rename("../content/settings/folks.json", "../config/folks.json");
DocTools::writeSettings("../config/folks.json", $newFolks);
rename("../content/settings/tags.json", "../config/tags.json");
//images path for blog and user
$blogImagePath = "../public/assets/images/blog";
$userImagePath = "../public/assets/images/user";
//check to see if image dirs are empty, if not chill
if ($globs = glob($blogImagePath . "/*")) {
//directory not empty, relax
} else {
rename("../content/public/assets/images/blog", $blogImagePath);
}
if ($globs = glob($userImagePath . "/*")) {
//directory not empty, relax
} else {
rename("../content/public/assets/images/user", $userImagePath);
}
rename("../content/content/pages/", "../content/pages");
//legacy check for old file structure
if (is_file("../content/pages/index.md")) {
if (!is_dir("../content/pages/start")) {
//Directory does not exist, so lets create it.
mkdir("../content/pages/start", 0755, true);
//move start page to appropriate spot
rename(
"../content/pages/index.md",
"../content/pages/start/index.md"
);
}
} else {
//chill
}
//clean up
DocTools::deleteFolder("../content/settings");
DocTools::deleteFolder("../content/public");
DocTools::deleteFolder("../content/content");
$result = [
"type" => "requestGood",
"message" => "Site Restored! Redirecting",
];
} else {
$result = [
"type" => "requestLame",
"message" => "Check that password, champ.",
];
}
} else {
$result = [
"type" => "requestLame",
"message" => "No member found by that name, hoss",
];
}
$zip->close();
$zipPath = "../content/" . $name;
//trash zip when done
unlink($zipPath);
} else {
$result = [
"type" => "requestLame",
"message" => "Could not open backup. RATS!",
];
}
return $result;
}
}

View file

@ -1,238 +0,0 @@
<?php
use Mni\FrontYAML\Parser;
use function _\find;
use function _\filter;
class Sorting
{
private static $_tags = [];
private static $_archive = [];
public function __construct()
{
}
public static function tags()
{
$pages = (new Book("../content/pages"))->getContents();
foreach ($pages as $page) {
$temp = [];
$temp = explode(",", $page["tags"]);
foreach ($temp as $tag) {
$label = trim($tag);
if (!find(self::$_tags, ["tag_name" => $label])) {
array_push(self::$_tags, [
"tag_name" => $label,
"slug" => StringTools::safeString($label),
"pages" => self::tagPages($label, $pages),
]);
}
}
}
return self::$_tags;
}
private static function tagPages($tag, $pages)
{
$tagged = [];
foreach ($pages as $page) {
if (strpos($page["tags"], $tag) !== false) {
array_push($tagged, [
"title" => $page["title"],
"slug" => $page["slug"],
"path" => $page["path"],
"feature" => $page["feature"],
]);
}
}
return $tagged;
}
public static function archive()
{
$pages = (new Book("../content/pages"))->getContents();
$years = [];
$archive = [];
foreach ($pages as $page) {
//$year = date("Y", date($page["rawCreated"]));
$date = explode("/", $page["path"]);
//echo $page["title"] . " : " . $year . "\n";
if (!find($years, ["year" => trim($date[0])])) {
$findPages = filter($pages, ["createdYear" => trim($date[0])]);
//var_dump($findPages);
array_push($years, [
"year" => trim($date[0]),
"count" => count($findPages),
]);
}
}
foreach ($years as $year) {
$sorted = [];
$filtered = filter($pages, ["createdYear" => $year["year"]]);
foreach ($filtered as $obj) {
$month = date("m", date($obj["rawCreated"]));
if (!find($sorted, ["month" => $month])) {
$perMonth = filter($pages, [
"path" => $year["year"] . "/" . $month,
"deleted" => false,
"published" => true,
"layout" => "page",
]);
array_push($sorted, [
"month" => $month,
"full_month" => date("F", date($obj["rawCreated"])),
"count" => count($perMonth),
"pages" => $perMonth,
]);
}
}
array_push(self::$_archive, [
"year" => $year["year"],
"year_data" => $sorted,
]);
}
return self::$_archive;
}
public static function page($page)
{
$config = new Settings();
$settings = $config->getSettings();
$pageOption = [];
$pageInfo = [
"keywords" => isset($settings["global"]["keywords"])
? $settings["global"]["keywords"]
: "fipamo, blog, jamstack, php, markdown, js",
"description" => $settings["global"]["descriptions"],
"image" =>
$settings["global"]["base_url"] . $settings["global"]["background"],
"baseURL" => $settings["global"]["base_url"],
];
$taglist = explode(",", $page["tags"]);
$tags = [];
foreach ($taglist as $tag) {
$label = trim($tag);
array_push($tags, [
"label" => $label . " ",
"slug" => StringTools::safeString($label),
]);
}
$meta = [
"who" => $page["author"],
"when" => $page["created"],
"tags" => $tags,
];
//render markdown content and clean it
$parser = new Parser();
$rendered = $parser->parse($page["content"]);
$sanitizer = HtmlSanitizer\Sanitizer::create([
"extensions" => ["basic", "image", "list", "code"],
"tags" => [
"img" => [
"allowed_attributes" => ["src", "alt", "title", "class"],
"allowed_hosts" => null,
],
],
]);
$preclean = $sanitizer->sanitize($rendered->getContent());
//just clean renderd string for now, Sanitize doesn't like relative img urls
//so another option is needed
$cleaned = strip_tags($rendered->getContent(), [
"a",
"br",
"p",
"strong",
"br",
"img",
"iframe",
"ul",
"li",
"i",
"em",
"h1",
"h2",
"h3",
"pre",
"code",
]);
//$cleaned = preg_replace('/(?:\r\n|[\r\n]){2,}/', "\n\n", $cleaned);
//$cleaned = html_entity_decode($cleaned, ENT_QUOTES, "UTF-8");
//if page feature isn't empty, replace page info meta image
if ($page["feature"] != "" || $page["feature"] != null) {
$pageInfo["image"] = $pageInfo["baseURL"] . $page["feature"];
}
if ($page["layout"] == "index") {
//$template = $this->theme . "/index.twig";
//$location = "../public/index.html";
//$dir = null;
$recent = [];
$featured = [];
$limit = 4;
$pages = (new Book())->getContents();
foreach ($pages as $item) {
if (
!$item["deleted"] &&
$item["published"] &&
$item["menu"] != "true"
) {
if (count($recent) < $limit) {
array_push($recent, [
"path" => $item["path"],
"slug" => $item["slug"],
"title" => $item["title"],
"feature" => $item["feature"],
]);
}
if ($item["featured"] == true) {
if (count($featured) < $limit) {
array_push($featured, [
"path" => $item["path"],
"slug" => $item["slug"],
"title" => $item["title"],
"feature" => $item["feature"],
]);
}
}
}
}
$pageOptions = [
"title" => $page["title"],
"background" => $page["feature"],
"content" => $page["html"], //$cleaned,
"meta" => $meta,
"recent" => $recent,
"featured" => $featured,
"info" => $pageInfo,
"menu" => $settings["menu"],
"dynamicRender" => $settings["global"]["dynamicRender"],
];
} else {
//$template = $this->theme . "/page.twig";
//$location = "../public/" . $page["path"] . "/" . $page["slug"] . ".html";
//$dir = "../public/" . $page["path"];
$pageOptions = [
"title" => $page["title"],
"background" => $page["feature"],
"content" => $page["html"], //$cleaned,
"meta" => $meta,
"info" => $pageInfo,
"menu" => $settings["menu"],
"dynamicRender" => $settings["global"]["dynamicRender"],
];
}
return $pageOptions;
}
}

248
brain/utility/Sorting.php Normal file
View file

@ -0,0 +1,248 @@
<?php
namespace brain\utility;
use Mni\FrontYAML\Parser;
use brain\data\Book;
use brain\data\Settings;
use function _\find;
use function _\filter;
class Sorting
{
private static $_tags = [];
private static $_archive = [];
public function __construct()
{
}
public static function tags()
{
$pages = (new Book("../content/pages"))->getContents();
foreach ($pages as $page) {
$temp = [];
$temp = explode(",", $page["tags"]);
foreach ($temp as $tag) {
$label = trim($tag);
if (!find(self::$_tags, ["tag_name" => $label])) {
array_push(self::$_tags, [
"tag_name" => $label,
"slug" => StringTools::safeString($label),
"pages" => self::tagPages($label, $pages),
]);
}
}
}
return self::$_tags;
}
private static function tagPages($tag, $pages)
{
$tagged = [];
foreach ($pages as $page) {
if (strpos($page["tags"], $tag) !== false) {
array_push($tagged, [
"title" => $page["title"],
"slug" => $page["slug"],
"path" => $page["path"],
"feature" => $page["feature"],
]);
}
}
return $tagged;
}
public static function archive()
{
$pages = (new Book("../content/pages"))->getContents();
$years = [];
$archive = [];
foreach ($pages as $page) {
//$year = date("Y", date($page["rawCreated"]));
$date = explode("/", $page["path"]);
//echo $page["title"] . " : " . $year . "\n";
if (!find($years, ["year" => trim($date[0])])) {
$findPages = filter($pages, ["createdYear" => trim($date[0])]);
//var_dump($findPages);
array_push($years, [
"year" => trim($date[0]),
"count" => count($findPages),
]);
}
}
foreach ($years as $year) {
$sorted = [];
$filtered = filter($pages, ["createdYear" => $year["year"]]);
foreach ($filtered as $obj) {
$month = date("m", date($obj["rawCreated"]));
if (!find($sorted, ["month" => $month])) {
$perMonth = filter($pages, [
"path" => $year["year"] . "/" . $month,
"deleted" => false,
"published" => true,
"layout" => "page",
]);
array_push($sorted, [
"month" => $month,
"full_month" => date("F", date($obj["rawCreated"])),
"count" => count($perMonth),
"pages" => $perMonth,
]);
}
}
array_push(self::$_archive, [
"year" => $year["year"],
"year_data" => $sorted,
]);
}
return self::$_archive;
}
public static function page($page)
{
$config = new Settings();
$settings = $config->getSettings();
$pageOption = [];
$pageInfo = [
"keywords" => isset($settings["global"]["keywords"])
? $settings["global"]["keywords"]
: "fipamo, blog, jamstack, php, markdown, js",
"description" => $settings["global"]["descriptions"],
"image" =>
$settings["global"]["base_url"] . $settings["global"]["background"],
"baseURL" => $settings["global"]["base_url"],
];
$taglist = explode(",", $page["tags"]);
$tags = [];
foreach ($taglist as $tag) {
$label = trim($tag);
array_push($tags, [
"label" => $label . " ",
"slug" => StringTools::safeString($label),
]);
}
$meta = [
"who" => $page["author"],
"when" => $page["created"],
"tags" => $tags,
];
//render markdown content and clean it
$parser = new Parser();
$rendered = $parser->parse($page["content"]);
$sanitizer = \HtmlSanitizer\Sanitizer::create([
"extensions" => ["basic", "image", "list", "code"],
"tags" => [
"img" => [
"allowed_attributes" => ["src", "alt", "title", "class"],
"allowed_hosts" => null,
],
],
]);
$preclean = $sanitizer->sanitize($rendered->getContent());
//just clean renderd string for now, Sanitize doesn't like relative img urls
//so another option is needed
$cleaned = strip_tags($rendered->getContent(), [
"a",
"br",
"p",
"strong",
"br",
"img",
"iframe",
"ul",
"li",
"i",
"em",
"h1",
"h2",
"h3",
"pre",
"code",
]);
//$cleaned = preg_replace('/(?:\r\n|[\r\n]){2,}/', "\n\n", $cleaned);
//$cleaned = html_entity_decode($cleaned, ENT_QUOTES, "UTF-8");
//if page feature isn't empty, replace page info meta image
if ($page["feature"] != "" || $page["feature"] != null) {
$pageInfo["image"] = $pageInfo["baseURL"] . $page["feature"];
}
if ($page["layout"] == "index") {
//$template = $this->theme . "/index.twig";
//$location = "../public/index.html";
//$dir = null;
$recent = [];
$featured = [];
$limit = 4;
$pages = (new Book())->getContents();
foreach ($pages as $item) {
if (
!$item["deleted"] &&
$item["published"] &&
$item["menu"] != "true"
) {
if (count($recent) < $limit) {
array_push($recent, [
"path" => $item["path"],
"slug" => $item["slug"],
"title" => $item["title"],
"feature" => $item["feature"],
]);
}
if ($item["featured"] == true) {
if (count($featured) < $limit) {
array_push($featured, [
"path" => $item["path"],
"slug" => $item["slug"],
"title" => $item["title"],
"feature" => $item["feature"],
]);
}
}
}
}
$pageOptions = [
"title" => $page["title"],
"background" => $page["feature"],
"content" => $page["html"], //$cleaned,
"meta" => $meta,
"recent" => $recent,
"featured" => $featured,
"info" => $pageInfo,
"menu" => $settings["menu"],
"dynamicRender" => $settings["global"]["dynamicRender"],
"media" => $page["media"],
"files" => $page["docs"],
];
} else {
//$template = $this->theme . "/page.twig";
//$location = "../public/" . $page["path"] . "/" . $page["slug"] . ".html";
//$dir = "../public/" . $page["path"];
$pageOptions = [
"title" => $page["title"],
"background" => $page["feature"],
"content" => $page["html"], //$cleaned,
"meta" => $meta,
"info" => $pageInfo,
"menu" => $settings["menu"],
"dynamicRender" => $settings["global"]["dynamicRender"],
"media" => $page["media"],
"files" => $page["docs"],
];
}
return $pageOptions;
}
}

View file

@ -1,130 +0,0 @@
<?php
use ReallySimpleJWT\Token;
use ReallySimpleJWT\Exception\BuildException;
use Mni\FrontYAML\Parser;
//include "brain/data/Auth.inc.php";
class StringTools
{
public static function createUUID()
{
if (function_exists("com_create_guid") === true) {
return trim(com_create_guid(), "{}");
}
return sprintf(
"%04X%04X-%04X-%04X-%04X-%04X%04X%04X",
mt_rand(0, 65535),
mt_rand(0, 65535),
mt_rand(0, 65535),
mt_rand(16384, 20479),
mt_rand(32768, 49151),
mt_rand(0, 65535),
mt_rand(0, 65535),
mt_rand(0, 65535)
);
}
public static function sanitizeContent($entry)
{
$parser = new Parser();
$rendered = $parser->parse($entry);
$sanitizer = HtmlSanitizer\Sanitizer::create([
"extensions" => ["basic", "image", "list", "code"],
"tags" => [
"img" => [
"allowed_attributes" => ["src", "alt", "title", "class"],
"allowed_hosts" => null,
],
],
]);
$preclean = $sanitizer->sanitize($rendered->getContent());
$cleaned = strip_tags($rendered->getContent(), [
"a",
"br",
"p",
"strong",
"br",
"img",
"iframe",
"ul",
"li",
"i",
"h1",
"h2",
"h3",
"pre",
"code",
]);
return $cleaned;
}
public static function safeString($string)
{
return strtolower(
trim(
preg_replace(
"~[^0-9a-z]+~i",
"_",
html_entity_decode(
preg_replace(
"~&([a-z]{1,2})(?:acute|cedil|circ|grave|lig|orn|ring|slash|th|tilde|uml);~i",
'$1',
htmlentities($string, ENT_QUOTES, "UTF-8")
),
ENT_QUOTES,
"UTF-8"
)
),
"-"
)
);
}
public static function randomString(int $length)
{
$alphanum =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
$special = '*&!@%^#$';
$alphabet = $alphanum . $special;
$random = openssl_random_pseudo_bytes($length);
$alphabet_length = strlen($alphabet);
$string = "";
for ($i = 0; $i < $length; ++$i) {
$string .= $alphabet[ord($random[$i]) % $alphabet_length];
}
//secret needs to be a valid token
if ($length == 12) {
try {
$secret = Token::create(12, $string, time() + 3600, "localhost");
return $string;
} catch (BuildException $e) {
//bad secret, so try agiain
//echo "BAD STRING";
return self::randomString(12);
}
if (Token::validate($key, $string)) {
return $string;
} else {
return self::randomString(12);
}
}
}
private static function checkSpecial($string)
{
$specials = ["*", "&", "!", "@", "%", "^", "#", "$"];
$valid = false;
foreach ($specials as $item) {
if (strpos($string, $item)) {
return $valid = true;
}
}
return $valid;
}
}

View file

@ -0,0 +1,132 @@
<?php
namespace brain\utility;
use ReallySimpleJWT\Token;
use ReallySimpleJWT\Exception\BuildException;
use Mni\FrontYAML\Parser;
class StringTools
{
public static function createUUID()
{
if (function_exists("com_create_guid") === true) {
return trim(com_create_guid(), "{}");
}
return sprintf(
"%04X%04X-%04X-%04X-%04X-%04X%04X%04X",
mt_rand(0, 65535),
mt_rand(0, 65535),
mt_rand(0, 65535),
mt_rand(16384, 20479),
mt_rand(32768, 49151),
mt_rand(0, 65535),
mt_rand(0, 65535),
mt_rand(0, 65535)
);
}
public static function sanitizeContent($entry)
{
$parser = new Parser();
$rendered = $parser->parse($entry);
$sanitizer = HtmlSanitizer\Sanitizer::create([
"extensions" => ["basic", "image", "list", "code"],
"tags" => [
"img" => [
"allowed_attributes" => ["src", "alt", "title", "class"],
"allowed_hosts" => null,
],
],
]);
$preclean = $sanitizer->sanitize($rendered->getContent());
$cleaned = strip_tags($rendered->getContent(), [
"a",
"br",
"p",
"strong",
"br",
"img",
"iframe",
"ul",
"li",
"i",
"h1",
"h2",
"h3",
"pre",
"code",
]);
return $cleaned;
}
public static function safeString($string)
{
return strtolower(
trim(
preg_replace(
"~[^0-9a-z]+~i",
"_",
html_entity_decode(
preg_replace(
"~&([a-z]{1,2})(?:acute|cedil|circ|grave|lig|orn|ring|slash|th|tilde|uml);~i",
'$1',
htmlentities($string, ENT_QUOTES, "UTF-8")
),
ENT_QUOTES,
"UTF-8"
)
),
"-"
)
);
}
public static function randomString(int $length)
{
$alphanum =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
$special = '*&!@%^#$';
$alphabet = $alphanum . $special;
$random = openssl_random_pseudo_bytes($length);
$alphabet_length = strlen($alphabet);
$string = "";
for ($i = 0; $i < $length; ++$i) {
$string .= $alphabet[ord($random[$i]) % $alphabet_length];
}
//secret needs to be a valid token
if ($length == 12) {
try {
$secret = Token::create(12, $string, time() + 3600, "localhost");
return $string;
} catch (BuildException $e) {
//bad secret, so try agiain
//echo "BAD STRING";
return self::randomString(12);
}
if (Token::validate($key, $string)) {
return $string;
} else {
return self::randomString(12);
}
}
}
private static function checkSpecial($string)
{
$specials = ["*", "&", "!", "@", "%", "^", "#", "$"];
$valid = false;
foreach ($specials as $item) {
if (strpos($string, $item)) {
return $valid = true;
}
}
return $valid;
}
}

View file

@ -5,7 +5,7 @@
{% endblock %}
{% block stylesheets %}
<link rel="stylesheet" type="text/css" href="/assets/css/dash.css?=adfdfa">
<link rel="stylesheet" type="text/css" href="/assets/css/dash.css?=dfvgy">
{% endblock %}
{% block mainContent %}
@ -45,58 +45,36 @@
</div>
<div id="posts-list">
{% for page in pages %}
<a class="page-link" href="/dashboard/page/edit/{{ page.uuid }}">
<div class="page-bg" style="background: url({{ page.feature }}) no-repeat center center / cover">
{% if page.media[0].type == 'mp4' %}
<a href="/dashboard/page/edit/{{ page.uuid }}" id="{{ page.uuid }}" class="page-link">
<div class="page-video">
<video class="post-video" loop muted autoplay>
<source src="{{ page.media[0].file }}" type="video/mp4">
Sorry, your browser doesn't support embedded videos.
</video>
<label>
{{ page.title }}
</label>
<div id="meta">
<div id="options">
{% if page.menu == 'true' %}
{% set menu = "true" %}
{% else %}
{% set menu = "false" %}
{% endif %}
{% if page.published == 'true' %}
{% set published = "true" %}
{% else %}
{% set published = "false" %}
{% endif %}
{% if page.featured == 'true' %}
{% set featured = "true" %}
{% else %}
{% set featured = "false" %}
{% endif %}
<div id="option-left">
<button data-active="{{ menu }}">
<svg>
<use xlink:href="/assets/images/global/sprite.svg#entypo-add-to-list"/>
</svg>
</button>
<button data-active="{{ published }}">
<svg>
<use xlink:href="/assets/images/global/sprite.svg#entypo-globe"/>
</svg>
</button>
<button data-active="{{ featured }}">
<svg>
<use xlink:href="/assets/images/global/sprite.svg#entypo-star"/>
</svg>
</button>
</div>
<div id="option-right">
<span>
{{ page.updated }}
</span>
{{ include("dash/partials/recent-options.twig") }}
</div>
</div>
</a>
{% else %}
<a class="page-link" href="/dashboard/page/edit/{{ page.uuid }}">
<div class="page-bg" style="background: url({{ page.media[0].file }}) no-repeat center center / cover">
<label>
{{ page.title }}
</label>
<div id="meta">
{{ include("dash/partials/recent-options.twig") }}
</div>
</div>
</a>
{% endif %}
{% endfor %}
{% if numOfPages > 1 %}
<div class="paginate">

View file

@ -1,7 +1,7 @@
<div id="dash-login">
<div id="dash-form" class="dash-form">
<img id="the-logo" src="/assets/images/global/fipamo-logo.svg"/>
<form id="login" class='login' name="login" action="/dashboard/login" method="POST">
<form id="login" class='login' name="login" method="POST">
<input type="text" name="handle" class="form-control" placeholder="Handle" required ">
<input type="password" name="password" class="form-control" placeholder="Password" required">
<button id="login-btn" class='login-btn' type='submit'>

View file

@ -12,7 +12,7 @@
<div id="dash-index">
<div id="dash-index-wrapper">
<div id="dash-init" class="dash-init">
<form id="init-form">
<form id="init-form" method="POST">
<img id="the-logo" src="/assets/images/global/fipamo-logo.svg"/>
<input type="text" name="new_member_handle" id="new_member_handle" placeholder="handle"/>
<input type="text" name="new_member_email" id="new_member_email" placeholder="email"/>
@ -26,7 +26,7 @@
</div>
<div id="dash-restore" class="dash-restore">
<form id="init-restore">
<form id="init-restore" method="POST">
<img id="the-logo" src="/assets/images/global/fipamo-logo.svg"/>
<input type="text" name="restore_member_handle" id="restore_member_handle" placeholder="handle"/><input type="password" name="restore_member_pass" id="restore_member_pass" placeholder="password"/>
<div>
@ -44,5 +44,5 @@
{% endblock %}
{% block javascripts %}
<script src="/assets/scripts/Start.js" type="text/javascript"></script>
<script src="/assets/scripts/Start.js?=sdfsdf" type="text/javascript"></script>
{% endblock %}

View file

@ -39,5 +39,5 @@
{% endblock %}
{% block javascripts %}
<script src="/assets/scripts/Start.js" type="text/javascript"></script>
<script src="/assets/scripts/Start.js?=cvfggt" type="text/javascript"></script>
{% endblock %}

View file

@ -14,6 +14,8 @@
{% set content = page['content'] %}
{% set date = page['created'] %}
{% set updated = page['updated'] %}
{% set media = page['media'] %}
{% set files = page['docs'] %}
{% else %}
{% set id = '' %}
{% set uuid = '' %}
@ -25,6 +27,8 @@
{% set content = '' %}
{% set date = '' %}
{% set updated = '' %}
{% set media = '' %}
{% set files = '' %}
{% endif %}
{% block title %}
@ -32,7 +36,7 @@
{% endblock %}
{% block stylesheets %}
<link rel="stylesheet" type="text/css" href="/assets/css/dash.css?=qwert">
<link rel="stylesheet" type="text/css" href="/assets/css/dash.css?=vbhj">
{% endblock %}
{% block mainContent %}
@ -40,19 +44,73 @@
<div id="post-edit-index-wrapper">
<div id="post-feature">
{% if page['feature'] == null %}
<div id="featured-image-drop">
DRAG AND DROP IMAGE OR <label for="featured-image-upload">CLICK TO CHOSE</label>
<div id="page-file-manager">
<div id="page-file-wrapper">
<div id="page-file-drop">
<label for="page-files-upload">DRAG AND DROP FILES OR CLICK TO SELECT</label>
</div>
{% else %}
<div id="featured-new-image-btn">
<button id="new-feature-upload">
<svg id="new-feature-upload" viewbox="0 0 20 20" class="icons"><use xlink:href="/assets/images/global/sprite.svg#entypo-image-inverted"/></svg>
</button>
</div>
<div id="featured-image-drop">
<img id="featured-image" src="{{ feature }}"/>
IMAGES AND VIDEO
<div id="page-images-list"></div>
FILES
<div id="page-files-list"></div>
</div>
</div>
{% else %}
<div id="page-file-manager">
<div id="page-file-wrapper">
<div id="page-file-drop">
<label for="page-files-upload">DRAG AND DROP FILES OR CLICK TO SELECT</label>
</div>
IMAGES AND VIDEO
<div id="page-images-list">
{% if media|length > 1 %}
{% for item in media %}
{% if item.type == "mp4"%}
<div id="{{loop.index0}}" class="video-item" data-source="{{ item.file }}"></div>
{% else %}
<div id="{{loop.index0}}" class="img-item" style="background: url({{ item.file }}) no-repeat center center / cover"></div>
{% endif %}
{% endfor %}
{% else %}
{% if media[0] != '' %}
{% if media[0].type == "mp4"%}
<div id="0" class="video-item" data-source="{{ media[0].file }}"></div>
{% else %}
<div id="0" class="img-item" style="background: url({{ media[0].file }}) no-repeat center center / cover"></div>
{% endif %}
{% else %}
{% endif %}
{% endif %}
</div>
FILES
<div id="page-files-list">
{% if files|length > 1 %}
{% for item in files %}
{% if item.type == "mp3"%}
<div id="{{loop.index0}}" class="audio-item" data-source="{{ item.file }}"></div>
{% else %}
<div id="{{loop.index0}}" class="file-item" data-source="{{ item.file }}"></div>
{% endif %}
{% endfor %}
{% else %}
{% if files[0] != '' %}
{% if files[0].type == "mp3"%}
<div id="0" class="audio-item" data-source="{{ files[0].file }}"></div>
{% else %}
<div id="0" class="file-item" data-source="{{ files[0].file }}"></div>
{% endif %}
{% else %}
{% endif %}
{% endif %}
</div>
</div>
</div>
{% endif %}
</div>
@ -95,7 +153,7 @@
<span id="post-date" type="text">
{{ updated }}
</span>
<input id="featured-image-upload" type="file" name="featured-image-upload"/>
<input id="page-files-upload" type="file" name="page-files-upload" multiple/>
<input id="post-image-upload" type="file" name="post-image-upload"/>
<input id="form_token" name="token" type="hidden" value="{{ token }}">
</div>
@ -119,5 +177,5 @@
{% endblock %}
{% block javascripts %}
<script src="/assets/scripts/Start.js" type="text/javascript"></script>
<script src="/assets/scripts/Start.js?=erty" type="text/javascript"></script>
{% endblock %}

View file

@ -25,53 +25,30 @@
<br/>
{% if data["entryCount"] != 0 %}
{% for page in data['pages'] %}
<a href="/dashboard/page/edit/{{ page.uuid }}" id="{{ page.uuid }}" class="post-link" style="background: url({{ page.feature }}) no-repeat center center / cover">
{% if page.media[0].type == 'mp4' %}
<a href="/dashboard/page/edit/{{ page.uuid }}" id="{{ page.uuid }}" class="post-video-link">
<video class="post-video" loop muted autoplay>
<source src="{{ page.media[0].file }}" type="video/mp4">
Sorry, your browser doesn't support embedded videos.
</video>
<label>
{{ page.title }}
</label>
<div id="options">
{% if page.menu == 'true' %}
{% set menu = "true" %}
{% else %}
{% set menu = "false" %}
{% endif %}
{% if page.published == 'true' %}
{% set published = "true" %}
{% else %}
{% set published = "false" %}
{% endif %}
{% if page.featured == 'true' %}
{% set featured = "true" %}
{% else %}
{% set featured = "false" %}
{% endif %}
<div id="option-left">
<button data-active="{{ menu }}">
<svg>
<use xlink:href="/assets/images/global/sprite.svg#entypo-add-to-list"/>
</svg>
</button>
<button data-active="{{ published }}">
<svg>
<use xlink:href="/assets/images/global/sprite.svg#entypo-globe"/>
</svg>
</button>
<button data-active="{{ featured }}">
<svg>
<use xlink:href="/assets/images/global/sprite.svg#entypo-star"/>
</svg>
</button>
</div>
<div id="option-right">
<span>
{{ page.updated }}
</span>
</div>
</div>
{{ include("dash/partials/recent-options.twig") }}
</a>
{% else %}
<a href="/dashboard/page/edit/{{ page.uuid }}" id="{{ page.uuid }}" class="post-link" style="background: url({{ page.media[0].file }}) no-repeat center center / cover">
<label>
{{ page.title }}
</label>
{{ include("dash/partials/recent-options.twig") }}
</a>
{% endif %}
{% endfor %}
{% else %}
There are no pages

View file

@ -0,0 +1,42 @@
<div id="options">
{% if page.menu == 'true' %}
{% set menu = "true" %}
{% else %}
{% set menu = "false" %}
{% endif %}
{% if page.published == 'true' %}
{% set published = "true" %}
{% else %}
{% set published = "false" %}
{% endif %}
{% if page.featured == 'true' %}
{% set featured = "true" %}
{% else %}
{% set featured = "false" %}
{% endif %}
<div id="option-left">
<button data-active="{{ menu }}">
<svg>
<use xlink:href="/assets/images/global/sprite.svg#entypo-add-to-list"/>
</svg>
</button>
<button data-active="{{ published }}">
<svg>
<use xlink:href="/assets/images/global/sprite.svg#entypo-globe"/>
</svg>
</button>
<button data-active="{{ featured }}">
<svg>
<use xlink:href="/assets/images/global/sprite.svg#entypo-star"/>
</svg>
</button>
</div>
<div id="option-right">
<span>
{{ page.updated }}
</span>
</div>
</div>

View file

@ -5,7 +5,7 @@
{% endblock %}
{% block stylesheets %}
<link rel="stylesheet" type="text/css" href="/assets/css/dash.css?=adfd">
<link rel="stylesheet" type="text/css" href="/assets/css/dash.css?=adfdff">
{% endblock %}
{% block mainContent %}
@ -23,5 +23,5 @@
{% endblock %}
{% block javascripts %}
<script src="/assets/scripts/Start.js" type="text/javascript"></script>
<script src="/assets/scripts/Start.js?=ghji" type="text/javascript"></script>
{% endblock %}

View file

@ -9,6 +9,11 @@
"homepage": "https://roiskinda.cool"
}
],
"autoload": {
"psr-4": {
"brain\\":"brain"
}
},
"support": {
"source": "https://code.playvicio.us/Are0h/Fipamo",
"wiki": "https://code.playvicio.us/Are0h/Fipamo/wiki/_pages",

View file

@ -1,4 +1,4 @@
{% extends "fipamo-default/frame.twig" %}
{% extends "frame.twig" %}
{% block title %}
{{ title }}

View file

@ -1,31 +1,32 @@
/**
-------------------------------
-- Typography
-------------------------------
**/
/**
-------------------------------
-- Colors
-------------------------------
**/
/**
-------------------------------
-- Mixins
-------------------------------
**/
/**
-------------------------------
-- Normalize
-------------------------------
**/
h1, h2, h3 {
color: #ebe5d4;
}
h1 {
font-size: 2em;
font-weight: 400;
}
h2 {
font-size: 1.75em;
font-weight: 400;
}
h3 {
font-size: 1.5em;
font-weight: 300;
}
html {
line-height: 1.15;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
body {
margin: 0;
}
article,
aside,
footer,
@ -34,62 +35,75 @@ nav,
section {
display: block;
}
h1 {
font-size: 2em;
margin: 0.67em 0;
line-height: 1em;
}
figcaption,
figure,
main {
display: block;
}
figure {
margin: 1em 40px;
}
hr {
box-sizing: content-box;
height: 0;
overflow: visible;
}
pre {
font-family: monospace, monospace;
font-size: 1em;
}
a {
background-color: transparent;
-webkit-text-decoration-skip: objects;
}
a:active,
a:hover {
outline-width: 0;
}
abbr[title] {
border-bottom: none;
text-decoration: underline;
text-decoration: underline dotted;
}
b,
strong {
font-weight: inherit;
font-weight: bolder;
}
code,
kbd,
samp {
font-family: monospace, monospace;
font-size: 1em;
}
dfn {
font-style: italic;
}
mark {
background-color: #ff0;
color: #000;
}
small {
font-size: 80%;
}
sub,
sup {
font-size: 60%;
@ -97,31 +111,38 @@ sup {
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.55em;
background: #bdcbdb;
background: #151d26;
color: #151d26;
border-radius: 2px;
padding: 0 2px 0 2px;
margin: 0 2px 0 0;
}
audio,
video {
display: inline-block;
}
audio:not([controls]) {
display: none;
height: 0;
}
img {
border-style: none;
}
svg:not(:root) {
overflow: hidden;
}
button,
input,
optgroup,
@ -132,38 +153,44 @@ textarea {
line-height: 1.15;
margin: 0;
}
button,
input {
overflow: visible;
}
button,
select {
text-transform: none;
}
button,
html [type="button"],
[type="reset"],
[type="submit"] {
button, html [type=button],
[type=reset],
[type=submit] {
-webkit-appearance: button;
}
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner,
[type=button]::-moz-focus-inner,
[type=reset]::-moz-focus-inner,
[type=submit]::-moz-focus-inner,
button::-moz-focus-inner {
border-style: none;
padding: 0;
}
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring,
[type=button]:-moz-focusring,
[type=reset]:-moz-focusring,
[type=submit]:-moz-focusring,
button:-moz-focusring {
outline: 1px dotted ButtonText;
}
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
legend {
box-sizing: border-box;
color: inherit;
@ -172,55 +199,143 @@ legend {
padding: 0;
white-space: normal;
}
progress {
display: inline-block;
vertical-align: baseline;
}
textarea {
overflow: auto;
}
[type="checkbox"],
[type="radio"] {
[type=checkbox],
[type=radio] {
box-sizing: border-box;
padding: 0;
}
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
[type=number]::-webkit-inner-spin-button,
[type=number]::-webkit-outer-spin-button {
height: auto;
}
[type="search"] {
[type=search] {
-webkit-appearance: textfield;
outline-offset: -2px;
}
[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration {
[type=search]::-webkit-search-cancel-button,
[type=search]::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-file-upload-button {
-webkit-appearance: button;
font: inherit;
}
details,
menu {
display: block;
}
summary {
display: list-item;
}
canvas {
display: inline-block;
}
template {
display: none;
}
[hidden] {
display: none;
}
/**
-------------------------------
-- Main Structure
-------------------------------
**/
form {
display: inline-block;
}
form a {
color: #151d26;
}
form p {
background: #e8c33e;
color: #151d26;
padding: 5px;
display: block;
border-radius: 5px;
text-align: left;
}
input[type=email], input[type=password], input[type=text] {
border: 0;
border-radius: 5px;
padding: 5px;
margin: 10px 5px 0 0;
font: 18px Helvetica, Arial, sans-serif;
display: inline-block;
background: #151d26;
color: #e8c33e;
}
textarea {
border: 0;
border-radius: 3px;
color: #ebe5d4;
font: 15px Helvetica, Arial, sans-serif;
background: #151d26;
}
button, input[type=submit] {
background: #7ED07E;
color: #151d26;
font: 20px Helvetica, Arial, sans-serif;
border-radius: 5px;
position: relative;
cursor: pointer;
border: 0;
padding: 10px 0 5px 0;
-moz-transition: all 0.3s linear;
-webkit-transition: all 0.3s linear;
-o-transition: all 0.3s linear;
transition: all 0.3s linear;
}
select {
font: 14px Helvetica, Arial, sans-serif;
border: 1px solid #FC6399;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
color: #151d26;
}
::-webkit-input-placeholder {
font: 25px Helvetica, Arial, sans-serif;
color: #ebe5d4;
}
:-moz-placeholder {
/* Firefox 18- */
font: 25px Helvetica, Arial, sans-serif;
color: #ebe5d4;
}
::-moz-placeholder {
/* Firefox 19+ */
font: 15px Helvetica, Arial, sans-serif;
color: #ebe5d4;
}
:-ms-input-placeholder {
font: 25px Helvetica, Arial, sans-serif;
color: #ebe5d4;
}
html {
margin: 0;
padding: 0;
@ -229,6 +344,7 @@ html {
overflow: hidden;
font: 400 1.2em/1.4em Helvetica, Arial, sans-serif;
}
body {
background: #ebe5d4;
margin: 0;
@ -240,51 +356,79 @@ body {
overflow-y: scroll;
overflow-x: hidden;
}
a {
color: #151d26;
text-decoration: none;
border-bottom: 1px solid #7ed07e;
-moz-transition: all 0.2s linear;
-webkit-transition: all 0.2s linear;
-o-transition: all 0.2s linear;
transition: all 0.2s linear;
border-bottom: 1px solid #7ED07E;
}
a:hover {
border-bottom: 1px solid #fc6399;
border-bottom: 1px solid #FC6399;
}
code {
background: #32302f;
color: #7ed07e;
color: #7ED07E;
border-radius: 3px;
padding: 3px;
}
pre {
background: #32302f;
color: #7ed07e;
color: #7ED07E;
border-radius: 3px;
padding: 3px;
}
pre code {
color: #fc6399;
code {
color: #FC6399;
background: none;
}
svg.icons {
width: 25px;
fill: #ebe5d4;
}
header {
background: #151d26;
height: 90%;
width: 100%;
border-top: #ebe5d4 3px solid;
}
header #media {
width: 100%;
height: 90%;
position: absolute;
}
header #media .slide {
-moz-transition: all 0.7s linear;
-webkit-transition: all 0.7s linear;
-o-transition: all 0.7s linear;
transition: all 0.7s linear;
width: 100%;
height: 100%;
position: absolute;
}
header #media .hide {
opacity: 0;
}
header #media .show {
opacity: 1;
}
header #media video {
width: 100%;
height: 100%;
object-fit: cover;
}
header nav {
width: 97%;
margin: 10px auto;
z-index: 1000;
position: relative;
color: #151d26;
}
header nav .left,
header nav .right {
header nav .left, header nav .right {
width: 50%;
display: inline-block;
vertical-align: top;
@ -302,7 +446,7 @@ header nav .right {
text-align: right;
}
header nav .right a.menu-link {
background: #fc6399;
background: #FC6399;
margin-bottom: 4px;
padding: 3px;
border-radius: 2px;
@ -311,8 +455,9 @@ header nav .right a.menu-link {
border-bottom: none;
}
header nav .right a.menu-link:hover {
background: #feb1cc;
background: #FC6399;
}
.container {
z-index: 2;
background: #ebe5d4;
@ -331,57 +476,47 @@ header nav .right a.menu-link:hover {
color: #32302f;
margin: 0 auto;
}
.container article .index,
.container article .page {
.container article .index, .container article .page {
padding: 0 0 15px 0;
}
.container article .index img,
.container article .page img {
.container article .index img, .container article .page img {
display: block;
width: 100%;
}
.container article .index h1,
.container article .page h1 {
.container article .index h1, .container article .page h1 {
color: #151d26;
}
.container article .index p,
.container article .page p {
.container article .index p, .container article .page p {
font: 300 1.25em/1.6em Helvetica, Arial, sans-serif;
}
.container article .index .meta,
.container article .page .meta {
.container article .index .meta, .container article .page .meta {
font: 500 0.8em/1.3em Helvetica, Arial, sans-serif;
padding: 5px 0 0 0;
border-top: 1px solid #151d26;
background: #ede8d8;
background: #ebe5d4;
}
.container article .index .meta a,
.container article .page .meta a {
.container article .index .meta a, .container article .page .meta a {
font-size: 0.8em;
font-weight: 400;
}
.container article .index .archive-item,
.container article .page .archive-item {
.container article .index .archive-item, .container article .page .archive-item {
padding: 15px 0 20px 0;
}
.container article .index .archive-item span.year,
.container article .page .archive-item span.year {
.container article .index .archive-item span.year, .container article .page .archive-item span.year {
font-size: 1.5em;
font-weight: 500;
padding: 5px;
display: block;
color: #151d26;
}
.container article .index .archive-item .archive-month,
.container article .page .archive-item .archive-month {
.container article .index .archive-item .archive-month, .container article .page .archive-item .archive-month {
display: inline-block;
vertical-align: top;
width: 30%;
padding: 5px;
}
.container article .index .archive-item .archive-month span.month,
.container article .page .archive-item .archive-month span.month {
color: #fc6399;
.container article .index .archive-item .archive-month span.month, .container article .page .archive-item .archive-month span.month {
color: #FC6399;
font-size: 1.5em;
font-weight: 300;
padding: 5px;
@ -394,35 +529,31 @@ header nav .right a.menu-link:hover {
.container section a {
color: #ebe5d4;
}
.container section .index-lists,
.container section .page-title {
.container section .index-lists, .container section .page-title {
max-width: 840px;
width: 80%;
margin: 0 auto;
padding: 20px 0 0 0;
}
.container section .index-lists span,
.container section .page-title span {
font: 600 2em/1.5 Helvetica, Arial, sans-serif;
color: #ebe5d4;
.container section .index-lists span, .container section .page-title span {
font-size: 2em;
color: #FC6399;
font-weight: 400;
}
.container section .index-lists .recent,
.container section .page-title .recent,
.container section .index-lists .featured,
.container section .page-title .featured {
.container section .index-lists .recent, .container section .index-lists .featured, .container section .page-title .recent, .container section .page-title .featured {
display: inline-block;
width: 50%;
vertical-align: top;
}
.container section .index-lists label,
.container section .page-title label {
.container section .index-lists label, .container section .page-title label {
background: #32302f;
color: #ebe5d4;
font-size: 1.5em;
line-height: 1.3;
}
footer {
background: #e4dcc5;
background: #ebe5d4;
padding: 10px;
color: #151d26;
font-size: 0.8em;
@ -435,121 +566,44 @@ footer .inner {
max-width: 840px;
}
footer .inner a {
color: #fc6399;
color: #FC6399;
}
@media only screen and (max-width: 640px) {
header nav {
header nav {
width: 98%;
}
header span {
}
header span {
font-size: 2.5em;
}
.container article .index .archive-item .archive-month,
.container article .page .archive-item .archive-month {
}
header .container article .index .archive-item .archive-month, header .container article .page .archive-item .archive-month {
width: 45%;
}
}
@media only screen and (max-width: 480px) {
header nav {
header nav {
width: 96%;
}
.container article .index,
.container article .page {
}
header .container article .index, header .container article .page {
margin: 0;
}
.container article .index p,
.container article .page p {
}
header .container article .index p, header .container article .page p {
font: 300 1em/1.6em Helvetica, Arial, sans-serif;
}
.container section .index-lists .recent,
.container section .index-lists .featured {
}
header .container section .index-lists .recent, header .container section .index-lists .featured {
width: 100% !important;
}
}
@media only screen and (max-width: 375px) {
header nav {
header nav {
width: 95%;
}
.container article .index,
.container article .page {
}
.container article .index, .container article .page {
margin: 0;
}
.container article .index p,
.container article .page p {
}
.container article .index p, .container article .page p {
font: 300 0.9em/1.7em Helvetica, Arial, sans-serif;
}
.container article .index .archive-item .archive-month,
.container article .page .archive-item .archive-month {
}
.container article .index .archive-item .archive-month, .container article .page .archive-item .archive-month {
width: 95%;
}
}
/**
-------------------------------
-- Forms
-------------------------------
**/
form {
display: inline-block;
}
input[type=email],
input[type=password],
input[type=text] {
border: 0;
border-radius: 5px;
padding: 5px;
margin: 10px 5px 0 0;
font: 15px 'RobotoMono';
display: inline-block;
}
textarea {
border: 0;
border-radius: 3px;
color: $type02;
font: 15px 'RobotoMono';
}
button,
input[type=submit] {
background: #fc6399;
color: #ebe5d4;
font: 14px Helvetica, Arial, sans-serif;
border-radius: 5px;
position: relative;
cursor: pointer;
border: 0;
padding: 5px 5px 0 5px;
-moz-transition: all 0.3s linear;
-webkit-transition: all 0.3s linear;
-o-transition: all 0.3s linear;
transition: all 0.3s linear;
}
button:hover,
input[type=submit]:hover {
background: #fc7ca9;
}
select {
font: 14px 'RobotoMono';
border: 1px solid #fc6399;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
color: #151d26;
}
::-webkit-input-placeholder {
font: 14px 'RobotoMono';
color: #837e7c;
}
:-moz-placeholder {
/* Firefox 18- */
font: 14px 'RobotoMono';
color: #837e7c;
}
::-moz-placeholder {
/* Firefox 19+ */
font: 14px 'RobotoMono';
color: #837e7c;
}
:-ms-input-placeholder {
font: 14px 'RobotoMono';
color: #837e7c;
}
/*# sourceMappingURL=base.css.map */

File diff suppressed because one or more lines are too long

View file

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View file

@ -0,0 +1,2 @@
(()=>{class t{constructor(){this.start()}start(){console.log("Connected like F.E.")}}document.addEventListener("DOMContentLoaded",(function(){new t}),!1)})();
//# sourceMappingURL=Start.js.map

View file

@ -0,0 +1 @@
{"mappings":"4BAKIA,KAAKC,QAEPA,QACEC,QAAQC,IAAI,wBCNhBC,SAASC,iBACP,oBACA,WACa,IAAIC,KAEjB","sources":["src/themes/theme-fipamo-default/com/Base.js","src/themes/theme-fipamo-default/com/Start.js"],"sourcesContent":["export default class Base {\n //--------------------------\n // constructor\n //--------------------------\n constructor() {\n this.start();\n }\n start() {\n console.log(\"Connected like F.E.\");\n }\n //--------------------------\n // methods\n //--------------------------\n\n //--------------------------\n // event handlers\n //--------------------------\n}\n","import Base from \"./Base.js\";\n\ndocument.addEventListener(\n \"DOMContentLoaded\",\n function () {\n var base = new Base();\n },\n false\n);\n"],"names":["this","start","console","log","document","addEventListener","$b8d4b81eabebe07b$export$2e2bcd8739ae039"],"version":3,"file":"Start.js.map"}

View file

@ -0,0 +1,583 @@
// modules are defined as an array
// [ module function, map of requires ]
//
// map of requires is short require name -> numeric require
//
// anything defined in a previous bundle is accessed via the
// orig method which is the require for previous bundles
(function (modules, entry, mainEntry, parcelRequireName, globalName) {
/* eslint-disable no-undef */
var globalObject =
typeof globalThis !== 'undefined'
? globalThis
: typeof self !== 'undefined'
? self
: typeof window !== 'undefined'
? window
: typeof global !== 'undefined'
? global
: {};
/* eslint-enable no-undef */
// Save the require from previous bundle to this closure if any
var previousRequire =
typeof globalObject[parcelRequireName] === 'function' &&
globalObject[parcelRequireName];
var cache = previousRequire.cache || {};
// Do not use `require` to prevent Webpack from trying to bundle this call
var nodeRequire =
typeof module !== 'undefined' &&
typeof module.require === 'function' &&
module.require.bind(module);
function newRequire(name, jumped) {
if (!cache[name]) {
if (!modules[name]) {
// if we cannot find the module within our internal map or
// cache jump to the current global require ie. the last bundle
// that was added to the page.
var currentRequire =
typeof globalObject[parcelRequireName] === 'function' &&
globalObject[parcelRequireName];
if (!jumped && currentRequire) {
return currentRequire(name, true);
}
// If there are other bundles on this page the require from the
// previous one is saved to 'previousRequire'. Repeat this as
// many times as there are bundles until the module is found or
// we exhaust the require chain.
if (previousRequire) {
return previousRequire(name, true);
}
// Try the node require function if it exists.
if (nodeRequire && typeof name === 'string') {
return nodeRequire(name);
}
var err = new Error("Cannot find module '" + name + "'");
err.code = 'MODULE_NOT_FOUND';
throw err;
}
localRequire.resolve = resolve;
localRequire.cache = {};
var module = (cache[name] = new newRequire.Module(name));
modules[name][0].call(
module.exports,
localRequire,
module,
module.exports,
this
);
}
return cache[name].exports;
function localRequire(x) {
var res = localRequire.resolve(x);
return res === false ? {} : newRequire(res);
}
function resolve(x) {
var id = modules[name][1][x];
return id != null ? id : x;
}
}
function Module(moduleName) {
this.id = moduleName;
this.bundle = newRequire;
this.exports = {};
}
newRequire.isParcelRequire = true;
newRequire.Module = Module;
newRequire.modules = modules;
newRequire.cache = cache;
newRequire.parent = previousRequire;
newRequire.register = function (id, exports) {
modules[id] = [
function (require, module) {
module.exports = exports;
},
{},
];
};
Object.defineProperty(newRequire, 'root', {
get: function () {
return globalObject[parcelRequireName];
},
});
globalObject[parcelRequireName] = newRequire;
for (var i = 0; i < entry.length; i++) {
newRequire(entry[i]);
}
if (mainEntry) {
// Expose entry point to Node, AMD or browser globals
// Based on https://github.com/ForbesLindesay/umd/blob/master/template.js
var mainExports = newRequire(mainEntry);
// CommonJS
if (typeof exports === 'object' && typeof module !== 'undefined') {
module.exports = mainExports;
// RequireJS
} else if (typeof define === 'function' && define.amd) {
define(function () {
return mainExports;
});
// <script>
} else if (globalName) {
this[globalName] = mainExports;
}
}
})({"5ZIt9":[function(require,module,exports) {
"use strict";
var HMR_HOST = null;
var HMR_PORT = 1234;
var HMR_SECURE = false;
var HMR_ENV_HASH = "d6ea1d42532a7575";
module.bundle.HMR_BUNDLE_ID = "423b0fbd795fbd6e";
function _toConsumableArray(arr) {
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _iterableToArray(iter) {
if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) return _arrayLikeToArray(arr);
}
function _createForOfIteratorHelper(o, allowArrayLike) {
var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
if (!it) {
if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
if (it) o = it;
var i = 0;
var F = function F() {
};
return {
s: F,
n: function n() {
if (i >= o.length) return {
done: true
};
return {
done: false,
value: o[i++]
};
},
e: function e(_e) {
throw _e;
},
f: F
};
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
var normalCompletion = true, didErr = false, err;
return {
s: function s() {
it = it.call(o);
},
n: function n() {
var step = it.next();
normalCompletion = step.done;
return step;
},
e: function e(_e2) {
didErr = true;
err = _e2;
},
f: function f() {
try {
if (!normalCompletion && it.return != null) it.return();
} finally{
if (didErr) throw err;
}
}
};
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
return arr2;
}
/* global HMR_HOST, HMR_PORT, HMR_ENV_HASH, HMR_SECURE */ /*::
import type {
HMRAsset,
HMRMessage,
} from '@parcel/reporter-dev-server/src/HMRServer.js';
interface ParcelRequire {
(string): mixed;
cache: {|[string]: ParcelModule|};
hotData: mixed;
Module: any;
parent: ?ParcelRequire;
isParcelRequire: true;
modules: {|[string]: [Function, {|[string]: string|}]|};
HMR_BUNDLE_ID: string;
root: ParcelRequire;
}
interface ParcelModule {
hot: {|
data: mixed,
accept(cb: (Function) => void): void,
dispose(cb: (mixed) => void): void,
// accept(deps: Array<string> | string, cb: (Function) => void): void,
// decline(): void,
_acceptCallbacks: Array<(Function) => void>,
_disposeCallbacks: Array<(mixed) => void>,
|};
}
declare var module: {bundle: ParcelRequire, ...};
declare var HMR_HOST: string;
declare var HMR_PORT: string;
declare var HMR_ENV_HASH: string;
declare var HMR_SECURE: boolean;
*/ var OVERLAY_ID = '__parcel__error__overlay__';
var OldModule = module.bundle.Module;
function Module(moduleName) {
OldModule.call(this, moduleName);
this.hot = {
data: module.bundle.hotData,
_acceptCallbacks: [],
_disposeCallbacks: [],
accept: function accept(fn) {
this._acceptCallbacks.push(fn || function() {
});
},
dispose: function dispose(fn) {
this._disposeCallbacks.push(fn);
}
};
module.bundle.hotData = undefined;
}
module.bundle.Module = Module;
var checkedAssets, acceptedAssets, assetsToAccept;
function getHostname() {
return HMR_HOST || (location.protocol.indexOf('http') === 0 ? location.hostname : 'localhost');
}
function getPort() {
return HMR_PORT || location.port;
} // eslint-disable-next-line no-redeclare
var parent = module.bundle.parent;
if ((!parent || !parent.isParcelRequire) && typeof WebSocket !== 'undefined') {
var hostname = getHostname();
var port = getPort();
var protocol = HMR_SECURE || location.protocol == 'https:' && !/localhost|127.0.0.1|0.0.0.0/.test(hostname) ? 'wss' : 'ws';
var ws = new WebSocket(protocol + '://' + hostname + (port ? ':' + port : '') + '/'); // $FlowFixMe
ws.onmessage = function(event) {
checkedAssets = {
};
acceptedAssets = {
};
assetsToAccept = [];
var data = JSON.parse(event.data);
if (data.type === 'update') {
// Remove error overlay if there is one
if (typeof document !== 'undefined') removeErrorOverlay();
var assets = data.assets.filter(function(asset) {
return asset.envHash === HMR_ENV_HASH;
}); // Handle HMR Update
var handled = assets.every(function(asset) {
return asset.type === 'css' || asset.type === 'js' && hmrAcceptCheck(module.bundle.root, asset.id, asset.depsByBundle);
});
if (handled) {
console.clear();
assets.forEach(function(asset) {
hmrApply(module.bundle.root, asset);
});
for(var i = 0; i < assetsToAccept.length; i++){
var id = assetsToAccept[i][1];
if (!acceptedAssets[id]) hmrAcceptRun(assetsToAccept[i][0], id);
}
} else window.location.reload();
}
if (data.type === 'error') {
// Log parcel errors to console
var _iterator = _createForOfIteratorHelper(data.diagnostics.ansi), _step;
try {
for(_iterator.s(); !(_step = _iterator.n()).done;){
var ansiDiagnostic = _step.value;
var stack = ansiDiagnostic.codeframe ? ansiDiagnostic.codeframe : ansiDiagnostic.stack;
console.error('🚨 [parcel]: ' + ansiDiagnostic.message + '\n' + stack + '\n\n' + ansiDiagnostic.hints.join('\n'));
}
} catch (err) {
_iterator.e(err);
} finally{
_iterator.f();
}
if (typeof document !== 'undefined') {
// Render the fancy html overlay
removeErrorOverlay();
var overlay = createErrorOverlay(data.diagnostics.html); // $FlowFixMe
document.body.appendChild(overlay);
}
}
};
ws.onerror = function(e) {
console.error(e.message);
};
ws.onclose = function() {
console.warn('[parcel] 🚨 Connection to the HMR server was lost');
};
}
function removeErrorOverlay() {
var overlay = document.getElementById(OVERLAY_ID);
if (overlay) {
overlay.remove();
console.log('[parcel] ✨ Error resolved');
}
}
function createErrorOverlay(diagnostics) {
var overlay = document.createElement('div');
overlay.id = OVERLAY_ID;
var errorHTML = '<div style="background: black; opacity: 0.85; font-size: 16px; color: white; position: fixed; height: 100%; width: 100%; top: 0px; left: 0px; padding: 30px; font-family: Menlo, Consolas, monospace; z-index: 9999;">';
var _iterator2 = _createForOfIteratorHelper(diagnostics), _step2;
try {
for(_iterator2.s(); !(_step2 = _iterator2.n()).done;){
var diagnostic = _step2.value;
var stack = diagnostic.codeframe ? diagnostic.codeframe : diagnostic.stack;
errorHTML += "\n <div>\n <div style=\"font-size: 18px; font-weight: bold; margin-top: 20px;\">\n \uD83D\uDEA8 ".concat(diagnostic.message, "\n </div>\n <pre>").concat(stack, "</pre>\n <div>\n ").concat(diagnostic.hints.map(function(hint) {
return '<div>💡 ' + hint + '</div>';
}).join(''), "\n </div>\n ").concat(diagnostic.documentation ? "<div>\uD83D\uDCDD <a style=\"color: violet\" href=\"".concat(diagnostic.documentation, "\" target=\"_blank\">Learn more</a></div>") : '', "\n </div>\n ");
}
} catch (err) {
_iterator2.e(err);
} finally{
_iterator2.f();
}
errorHTML += '</div>';
overlay.innerHTML = errorHTML;
return overlay;
}
function getParents(bundle, id) /*: Array<[ParcelRequire, string]> */ {
var modules = bundle.modules;
if (!modules) return [];
var parents = [];
var k, d, dep;
for(k in modules)for(d in modules[k][1]){
dep = modules[k][1][d];
if (dep === id || Array.isArray(dep) && dep[dep.length - 1] === id) parents.push([
bundle,
k
]);
}
if (bundle.parent) parents = parents.concat(getParents(bundle.parent, id));
return parents;
}
function updateLink(link) {
var newLink = link.cloneNode();
newLink.onload = function() {
if (link.parentNode !== null) // $FlowFixMe
link.parentNode.removeChild(link);
};
newLink.setAttribute('href', link.getAttribute('href').split('?')[0] + '?' + Date.now()); // $FlowFixMe
link.parentNode.insertBefore(newLink, link.nextSibling);
}
var cssTimeout = null;
function reloadCSS() {
if (cssTimeout) return;
cssTimeout = setTimeout(function() {
var links = document.querySelectorAll('link[rel="stylesheet"]');
for(var i = 0; i < links.length; i++){
// $FlowFixMe[incompatible-type]
var href = links[i].getAttribute('href');
var hostname = getHostname();
var servedFromHMRServer = hostname === 'localhost' ? new RegExp('^(https?:\\/\\/(0.0.0.0|127.0.0.1)|localhost):' + getPort()).test(href) : href.indexOf(hostname + ':' + getPort());
var absolute = /^https?:\/\//i.test(href) && href.indexOf(window.location.origin) !== 0 && !servedFromHMRServer;
if (!absolute) updateLink(links[i]);
}
cssTimeout = null;
}, 50);
}
function hmrApply(bundle, asset) {
var modules = bundle.modules;
if (!modules) return;
if (asset.type === 'css') reloadCSS();
else if (asset.type === 'js') {
var deps = asset.depsByBundle[bundle.HMR_BUNDLE_ID];
if (deps) {
if (modules[asset.id]) {
// Remove dependencies that are removed and will become orphaned.
// This is necessary so that if the asset is added back again, the cache is gone, and we prevent a full page reload.
var oldDeps = modules[asset.id][1];
for(var dep in oldDeps)if (!deps[dep] || deps[dep] !== oldDeps[dep]) {
var id = oldDeps[dep];
var parents = getParents(module.bundle.root, id);
if (parents.length === 1) hmrDelete(module.bundle.root, id);
}
}
var fn = new Function('require', 'module', 'exports', asset.output);
modules[asset.id] = [
fn,
deps
];
} else if (bundle.parent) hmrApply(bundle.parent, asset);
}
}
function hmrDelete(bundle, id1) {
var modules = bundle.modules;
if (!modules) return;
if (modules[id1]) {
// Collect dependencies that will become orphaned when this module is deleted.
var deps = modules[id1][1];
var orphans = [];
for(var dep in deps){
var parents = getParents(module.bundle.root, deps[dep]);
if (parents.length === 1) orphans.push(deps[dep]);
} // Delete the module. This must be done before deleting dependencies in case of circular dependencies.
delete modules[id1];
delete bundle.cache[id1]; // Now delete the orphans.
orphans.forEach(function(id) {
hmrDelete(module.bundle.root, id);
});
} else if (bundle.parent) hmrDelete(bundle.parent, id1);
}
function hmrAcceptCheck(bundle, id, depsByBundle) {
if (hmrAcceptCheckOne(bundle, id, depsByBundle)) return true;
// Traverse parents breadth first. All possible ancestries must accept the HMR update, or we'll reload.
var parents = getParents(module.bundle.root, id);
var accepted = false;
while(parents.length > 0){
var v = parents.shift();
var a = hmrAcceptCheckOne(v[0], v[1], null);
if (a) // If this parent accepts, stop traversing upward, but still consider siblings.
accepted = true;
else {
// Otherwise, queue the parents in the next level upward.
var p = getParents(module.bundle.root, v[1]);
if (p.length === 0) {
// If there are no parents, then we've reached an entry without accepting. Reload.
accepted = false;
break;
}
parents.push.apply(parents, _toConsumableArray(p));
}
}
return accepted;
}
function hmrAcceptCheckOne(bundle, id, depsByBundle) {
var modules = bundle.modules;
if (!modules) return;
if (depsByBundle && !depsByBundle[bundle.HMR_BUNDLE_ID]) {
// If we reached the root bundle without finding where the asset should go,
// there's nothing to do. Mark as "accepted" so we don't reload the page.
if (!bundle.parent) return true;
return hmrAcceptCheck(bundle.parent, id, depsByBundle);
}
if (checkedAssets[id]) return true;
checkedAssets[id] = true;
var cached = bundle.cache[id];
assetsToAccept.push([
bundle,
id
]);
if (!cached || cached.hot && cached.hot._acceptCallbacks.length) return true;
}
function hmrAcceptRun(bundle, id) {
var cached = bundle.cache[id];
bundle.hotData = {
};
if (cached && cached.hot) cached.hot.data = bundle.hotData;
if (cached && cached.hot && cached.hot._disposeCallbacks.length) cached.hot._disposeCallbacks.forEach(function(cb) {
cb(bundle.hotData);
});
delete bundle.cache[id];
bundle(id);
cached = bundle.cache[id];
if (cached && cached.hot && cached.hot._acceptCallbacks.length) cached.hot._acceptCallbacks.forEach(function(cb) {
var assetsToAlsoAccept = cb(function() {
return getParents(module.bundle.root, id);
});
if (assetsToAlsoAccept && assetsToAccept.length) // $FlowFixMe[method-unbinding]
assetsToAccept.push.apply(assetsToAccept, assetsToAlsoAccept);
});
acceptedAssets[id] = true;
}
},{}],"3OjfR":[function(require,module,exports) {
var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js");
var _baseJs = require("./Base.js");
var _baseJsDefault = parcelHelpers.interopDefault(_baseJs);
document.addEventListener("DOMContentLoaded", function() {
var base = new _baseJsDefault.default();
}, false);
},{"./Base.js":"jWciR","@parcel/transformer-js/src/esmodule-helpers.js":"gkKU3"}],"jWciR":[function(require,module,exports) {
var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js");
parcelHelpers.defineInteropFlag(exports);
class Base {
//--------------------------
// constructor
//--------------------------
constructor(){
this.currentSlide = 0;
this.slides = document.querySelectorAll("#media .slide");
this.start();
}
start() {
if (this.slides.length > 1) this.slideInterval = setInterval(()=>{
this.slides[this.currentSlide].className = "slide hide";
this.currentSlide = (this.currentSlide + 1) % this.slides.length;
this.slides[this.currentSlide].className = "slide show";
}, 3000);
}
}
exports.default = Base;
},{"@parcel/transformer-js/src/esmodule-helpers.js":"gkKU3"}],"gkKU3":[function(require,module,exports) {
exports.interopDefault = function(a) {
return a && a.__esModule ? a : {
default: a
};
};
exports.defineInteropFlag = function(a) {
Object.defineProperty(a, '__esModule', {
value: true
});
};
exports.exportAll = function(source, dest) {
Object.keys(source).forEach(function(key) {
if (key === 'default' || key === '__esModule' || dest.hasOwnProperty(key)) return;
Object.defineProperty(dest, key, {
enumerable: true,
get: function() {
return source[key];
}
});
});
return dest;
};
exports.export = function(dest, destName, get) {
Object.defineProperty(dest, destName, {
enumerable: true,
get: get
});
};
},{}]},["5ZIt9","3OjfR"], "3OjfR", "parcelRequire0e20")
//# sourceMappingURL=ThemeStart.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,7 +1,7 @@
<!DOCTYPE html>
{% if debug is defined %}
{% set assetPath = '/src/themes/theme-fipamo-default/fipamo-default/assets/' %}
{% set assetPath = '/src/themes/theme-'~theme~'/'~theme~'/assets/' %}
{% else %}
{% set assetPath = '/assets/' %}
{% endif %}
@ -15,15 +15,52 @@
</title>
<meta charset="UTF-8" />
<meta name='viewport' content='width=device-width, initial-scale=1.0' />
<meta name="keywords" content="{{ info['keywords'] }}"/>
<meta name="keywords" content="{{ info['keywords'] }}" />
<meta name="description" content="{{info['description']}} " />
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta property="og:image" content="{{info["image"]}}" />
<meta name="twitter:image" content="{{info["image"]}}" />
<link rel="stylesheet" type="text/css" href="{{ assetPath~"css/base.css?=adfafd" }}">
<link rel="stylesheet" type="text/css" href="{{ assetPath~"css/base.css?=dfvbghh" }}">
</head>
<body>
<!--
<header style="background: url({{ background }}) no-repeat center center; background-size: cover">
-->
<header>
<div id="media">
{% if media|length > 1 %}
{% for item in media %}
{% if item.type == "mp4"%}
<div id="{{loop.index0}}" class="slide">
<video controls autoplay muted>
<source src="{{item.file}}" type="video/mp4">
Please get a better browser. They're free.
</video>
</div>
{% else %}
<div id="{{loop.index0}}" class="slide hide" style="background: url({{ item.file }}) no-repeat center center / cover"></div>
{% endif %}
{% endfor %}
{% else %}
{% if media[0] != '' %}
{% if media[0].type == "mp4"%}
<div id="0" class="slide">
<video controls autoplay muted>
<source src="{{media[0].file}}" type="video/mp4">
Please get a better browser. They're free.
</video>
</div>
{% else %}
<div id="0" class="slide" style="background: url({{ media[0].file }}) no-repeat center center / cover"></div>
{% endif %}
{% else %}
{% endif %}
{% endif %}
</div>
<nav>
{% apply spaceless %}
<div class="left">
@ -43,7 +80,6 @@
{% else %}
<a href="{{"/"~link.slug~".html"}}" class="menu-link">{{link.title}}</a><br />
{% endif %}
{% endfor %}
{% endif %}
</div>
@ -68,10 +104,9 @@
{% else %}
<a href="/archives.html">Archives</a><br />
{% endif %}
© 2020 By Fipamo
</div>
</footer>
<script src="{{ assetPath~"scripts/start.min.js" }}" type="text/javascript"></script>
<script src="{{ assetPath~"scripts/ThemeStart.js" }}" type="text/javascript"></script>
</body>
</html>

View file

@ -1,4 +1,4 @@
{% extends "fipamo-default/frame.twig" %}
{% extends "frame.twig" %}
{% block title %}
{{ title }}
@ -39,6 +39,7 @@
{% else %}
<a href="{{ "/"~item.path~"/"~item.slug~".html" }}"> {{item.title}} </a><br />
{% endif %}
{% else %}
<a href="{{ "/"~item.path~"/"~item.slug~".html" }}"> {{item.title}} </a><br />
{% endif %}

View file

@ -1,4 +1,4 @@
{% extends "fipamo-default/frame.twig" %}
{% extends "frame.twig" %}
{% block title %}
{{ title }}
@ -12,7 +12,7 @@
</section>
<article>
<div class="page">
THIS IS A CUSTOM TEMPLATE <br />
[CUSTOM PAGE BRUH]
<p>{{content | raw}}</p>
<div>
@ -20,7 +20,7 @@
<strong>tags: </strong>
{% for tag in meta['tags'] %}
{% if dynamicRender is defined %}
{% if dynamicRender == 'true' %}
{% if dynamicRender == 'false' %}
<a href="{{ "/tags/"~tag.slug }}">{{ tag.label }}</a>
{% else %}
<a href="{{ "/tags/"~tag.slug~".html" }}">{{ tag.label }}</a>
@ -28,7 +28,6 @@
{% else %}
<a href="{{ "/tags/"~tag.slug~".html" }}">{{ tag.label }}</a>
{% endif %}
{% endfor %}
</div>
</div>

View file

@ -1,4 +1,4 @@
{% extends "fipamo-default/frame.twig" %}
{% extends "frame.twig" %}
{% block title %}
{{ title }}
@ -19,7 +19,7 @@
<strong>tags: </strong>
{% for tag in meta['tags'] %}
{% if dynamicRender is defined %}
{% if dynamicRender == 'false' %}
{% if dynamicRender == 'true' %}
<a href="{{ "/tags/"~tag.slug }}">{{ tag.label }}</a>
{% else %}
<a href="{{ "/tags/"~tag.slug~".html" }}">{{ tag.label }}</a>
@ -27,7 +27,6 @@
{% else %}
<a href="{{ "/tags/"~tag.slug~".html" }}">{{ tag.label }}</a>
{% endif %}
{% endfor %}
</div>
</div>

View file

@ -1,4 +1,4 @@
{% extends "fipamo-default/frame.twig" %}
{% extends "frame.twig" %}
{% block title %}
{{ title }}
@ -23,7 +23,6 @@
{% else %}
<a href="{{"/"~tag.path~"/"~tag.slug~".html"}}">{{tag.title}}</a><br />
{% endif %}
{% endfor %}
</div>

257
package-lock.json generated
View file

@ -25,9 +25,10 @@
"devDependencies": {
"@babel/preset-env": "^7.16.5",
"babel-cli": "^6.26.0",
"eslint": "^8.5.0",
"eslint": "^8.11.0",
"eslint-plugin-babel": "^5.3.1",
"parcel": "^2.0.1"
"parcel": "^2.0.1",
"prettier": "^2.6.0"
}
},
"node_modules/@babel/code-frame": {
@ -1819,15 +1820,15 @@
}
},
"node_modules/@eslint/eslintrc": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz",
"integrity": "sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.1.tgz",
"integrity": "sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ==",
"dependencies": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
"espree": "^9.2.0",
"espree": "^9.3.1",
"globals": "^13.9.0",
"ignore": "^4.0.6",
"ignore": "^5.2.0",
"import-fresh": "^3.2.1",
"js-yaml": "^4.1.0",
"minimatch": "^3.0.4",
@ -1838,9 +1839,9 @@
}
},
"node_modules/@eslint/eslintrc/node_modules/globals": {
"version": "13.12.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz",
"integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==",
"version": "13.13.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz",
"integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==",
"dependencies": {
"type-fest": "^0.20.2"
},
@ -1851,14 +1852,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@eslint/eslintrc/node_modules/ignore": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
"integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
"engines": {
"node": ">= 4"
}
},
"node_modules/@eslint/eslintrc/node_modules/type-fest": {
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
@ -3908,14 +3901,6 @@
"resolved": "https://registry.npmjs.org/animejs/-/animejs-3.2.1.tgz",
"integrity": "sha512-sWno3ugFryK5nhiDm/2BKeFCpZv7vzerWUcUPyAZLDhMek3+S/p418ldZJbJXo5ZUOpfm2kP2XRO4NJcULMy9A=="
},
"node_modules/ansi-colors": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
"integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
"engines": {
"node": ">=6"
}
},
"node_modules/ansi-escapes": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
@ -6618,17 +6603,6 @@
"node": ">= 0.8"
}
},
"node_modules/enquirer": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
"integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
"dependencies": {
"ansi-colors": "^4.1.1"
},
"engines": {
"node": ">=8.6"
}
},
"node_modules/entities": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz",
@ -6755,23 +6729,22 @@
}
},
"node_modules/eslint": {
"version": "8.5.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.5.0.tgz",
"integrity": "sha512-tVGSkgNbOfiHyVte8bCM8OmX+xG9PzVG/B4UCF60zx7j61WIVY/AqJECDgpLD4DbbESD0e174gOg3ZlrX15GDg==",
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.11.0.tgz",
"integrity": "sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA==",
"dependencies": {
"@eslint/eslintrc": "^1.0.5",
"@eslint/eslintrc": "^1.2.1",
"@humanwhocodes/config-array": "^0.9.2",
"ajv": "^6.10.0",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
"debug": "^4.3.2",
"doctrine": "^3.0.0",
"enquirer": "^2.3.5",
"escape-string-regexp": "^4.0.0",
"eslint-scope": "^7.1.0",
"eslint-scope": "^7.1.1",
"eslint-utils": "^3.0.0",
"eslint-visitor-keys": "^3.1.0",
"espree": "^9.2.0",
"eslint-visitor-keys": "^3.3.0",
"espree": "^9.3.1",
"esquery": "^1.4.0",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
@ -6779,7 +6752,7 @@
"functional-red-black-tree": "^1.0.1",
"glob-parent": "^6.0.1",
"globals": "^13.6.0",
"ignore": "^4.0.6",
"ignore": "^5.2.0",
"import-fresh": "^3.0.0",
"imurmurhash": "^0.1.4",
"is-glob": "^4.0.0",
@ -6790,9 +6763,7 @@
"minimatch": "^3.0.4",
"natural-compare": "^1.4.0",
"optionator": "^0.9.1",
"progress": "^2.0.0",
"regexpp": "^3.2.0",
"semver": "^7.2.1",
"strip-ansi": "^6.0.1",
"strip-json-comments": "^3.1.0",
"text-table": "^0.2.0",
@ -6947,9 +6918,9 @@
}
},
"node_modules/eslint/node_modules/eslint-scope": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.0.tgz",
"integrity": "sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg==",
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
"integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
"dependencies": {
"esrecurse": "^4.3.0",
"estraverse": "^5.2.0"
@ -6959,9 +6930,9 @@
}
},
"node_modules/eslint/node_modules/eslint-visitor-keys": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz",
"integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==",
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
"integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
@ -7007,14 +6978,6 @@
"node": ">=8"
}
},
"node_modules/eslint/node_modules/ignore": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
"integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
"engines": {
"node": ">= 4"
}
},
"node_modules/eslint/node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@ -7078,20 +7041,6 @@
"node": ">= 0.8.0"
}
},
"node_modules/eslint/node_modules/semver": {
"version": "7.3.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
"dependencies": {
"lru-cache": "^6.0.0"
},
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/eslint/node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@ -7170,13 +7119,13 @@
}
},
"node_modules/espree": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.2.0.tgz",
"integrity": "sha512-oP3utRkynpZWF/F2x/HZJ+AGtnIclaR7z1pYPxy7NYM2fSO6LgK/Rkny8anRSPK/VwEA1eqm2squui0T7ZMOBg==",
"version": "9.3.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz",
"integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==",
"dependencies": {
"acorn": "^8.6.0",
"acorn": "^8.7.0",
"acorn-jsx": "^5.3.1",
"eslint-visitor-keys": "^3.1.0"
"eslint-visitor-keys": "^3.3.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@ -7194,9 +7143,9 @@
}
},
"node_modules/espree/node_modules/eslint-visitor-keys": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz",
"integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==",
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
"integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
@ -8505,7 +8454,6 @@
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
"integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
"dev": true,
"engines": {
"node": ">= 4"
}
@ -9627,6 +9575,7 @@
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"dependencies": {
"yallist": "^4.0.0"
},
@ -11558,6 +11507,21 @@
"node": ">=0.10.0"
}
},
"node_modules/prettier": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.0.tgz",
"integrity": "sha512-m2FgJibYrBGGgQXNzfd0PuDGShJgRavjUoRCw1mZERIWVSXF0iLzLm+aOqTAbLnC3n6JzUhAA8uZnFVghHJ86A==",
"dev": true,
"bin": {
"prettier": "bin-prettier.js"
},
"engines": {
"node": ">=10.13.0"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/prismjs": {
"version": "1.25.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.25.0.tgz",
@ -11586,14 +11550,6 @@
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
"dev": true
},
"node_modules/progress": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/psl": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
@ -14376,7 +14332,8 @@
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true
},
"node_modules/yaml": {
"version": "1.10.2",
@ -15645,15 +15602,15 @@
}
},
"@eslint/eslintrc": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz",
"integrity": "sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.1.tgz",
"integrity": "sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ==",
"requires": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
"espree": "^9.2.0",
"espree": "^9.3.1",
"globals": "^13.9.0",
"ignore": "^4.0.6",
"ignore": "^5.2.0",
"import-fresh": "^3.2.1",
"js-yaml": "^4.1.0",
"minimatch": "^3.0.4",
@ -15661,18 +15618,13 @@
},
"dependencies": {
"globals": {
"version": "13.12.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz",
"integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==",
"version": "13.13.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz",
"integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==",
"requires": {
"type-fest": "^0.20.2"
}
},
"ignore": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
"integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg=="
},
"type-fest": {
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
@ -17091,11 +17043,6 @@
"resolved": "https://registry.npmjs.org/animejs/-/animejs-3.2.1.tgz",
"integrity": "sha512-sWno3ugFryK5nhiDm/2BKeFCpZv7vzerWUcUPyAZLDhMek3+S/p418ldZJbJXo5ZUOpfm2kP2XRO4NJcULMy9A=="
},
"ansi-colors": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
"integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA=="
},
"ansi-escapes": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
@ -19391,14 +19338,6 @@
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
"dev": true
},
"enquirer": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
"integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
"requires": {
"ansi-colors": "^4.1.1"
}
},
"entities": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz",
@ -19497,23 +19436,22 @@
}
},
"eslint": {
"version": "8.5.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.5.0.tgz",
"integrity": "sha512-tVGSkgNbOfiHyVte8bCM8OmX+xG9PzVG/B4UCF60zx7j61WIVY/AqJECDgpLD4DbbESD0e174gOg3ZlrX15GDg==",
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.11.0.tgz",
"integrity": "sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA==",
"requires": {
"@eslint/eslintrc": "^1.0.5",
"@eslint/eslintrc": "^1.2.1",
"@humanwhocodes/config-array": "^0.9.2",
"ajv": "^6.10.0",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
"debug": "^4.3.2",
"doctrine": "^3.0.0",
"enquirer": "^2.3.5",
"escape-string-regexp": "^4.0.0",
"eslint-scope": "^7.1.0",
"eslint-scope": "^7.1.1",
"eslint-utils": "^3.0.0",
"eslint-visitor-keys": "^3.1.0",
"espree": "^9.2.0",
"eslint-visitor-keys": "^3.3.0",
"espree": "^9.3.1",
"esquery": "^1.4.0",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
@ -19521,7 +19459,7 @@
"functional-red-black-tree": "^1.0.1",
"glob-parent": "^6.0.1",
"globals": "^13.6.0",
"ignore": "^4.0.6",
"ignore": "^5.2.0",
"import-fresh": "^3.0.0",
"imurmurhash": "^0.1.4",
"is-glob": "^4.0.0",
@ -19532,9 +19470,7 @@
"minimatch": "^3.0.4",
"natural-compare": "^1.4.0",
"optionator": "^0.9.1",
"progress": "^2.0.0",
"regexpp": "^3.2.0",
"semver": "^7.2.1",
"strip-ansi": "^6.0.1",
"strip-json-comments": "^3.1.0",
"text-table": "^0.2.0",
@ -19592,18 +19528,18 @@
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
},
"eslint-scope": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.0.tgz",
"integrity": "sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg==",
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
"integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
"requires": {
"esrecurse": "^4.3.0",
"estraverse": "^5.2.0"
}
},
"eslint-visitor-keys": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz",
"integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA=="
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
"integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA=="
},
"estraverse": {
"version": "5.3.0",
@ -19631,11 +19567,6 @@
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
},
"ignore": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
"integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg=="
},
"is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@ -19681,14 +19612,6 @@
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="
},
"semver": {
"version": "7.3.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
"requires": {
"lru-cache": "^6.0.0"
}
},
"shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@ -19779,13 +19702,13 @@
"integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw=="
},
"espree": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.2.0.tgz",
"integrity": "sha512-oP3utRkynpZWF/F2x/HZJ+AGtnIclaR7z1pYPxy7NYM2fSO6LgK/Rkny8anRSPK/VwEA1eqm2squui0T7ZMOBg==",
"version": "9.3.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz",
"integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==",
"requires": {
"acorn": "^8.6.0",
"acorn": "^8.7.0",
"acorn-jsx": "^5.3.1",
"eslint-visitor-keys": "^3.1.0"
"eslint-visitor-keys": "^3.3.0"
},
"dependencies": {
"acorn": {
@ -19794,9 +19717,9 @@
"integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ=="
},
"eslint-visitor-keys": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz",
"integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA=="
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
"integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA=="
}
}
},
@ -20802,8 +20725,7 @@
"ignore": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
"integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
"dev": true
"integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ=="
},
"immutable": {
"version": "4.0.0",
@ -21658,6 +21580,7 @@
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"requires": {
"yallist": "^4.0.0"
}
@ -23110,6 +23033,12 @@
"dev": true,
"optional": true
},
"prettier": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.0.tgz",
"integrity": "sha512-m2FgJibYrBGGgQXNzfd0PuDGShJgRavjUoRCw1mZERIWVSXF0iLzLm+aOqTAbLnC3n6JzUhAA8uZnFVghHJ86A==",
"dev": true
},
"prismjs": {
"version": "1.25.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.25.0.tgz",
@ -23132,11 +23061,6 @@
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
"dev": true
},
"progress": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="
},
"psl": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
@ -25353,7 +25277,8 @@
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true
},
"yaml": {
"version": "1.10.2",

View file

@ -10,9 +10,10 @@
"devDependencies": {
"@babel/preset-env": "^7.16.5",
"babel-cli": "^6.26.0",
"eslint": "^8.5.0",
"eslint": "^8.11.0",
"eslint-plugin-babel": "^5.3.1",
"parcel": "^2.0.1"
"parcel": "^2.0.1",
"prettier": "^2.6.0"
},
"dependencies": {
"@babel/core": "^7.16.5",

View file

@ -1912,6 +1912,7 @@ a {
font: 300 1em Helvetica, Arial, sans-serif;
color: #b2cce5;
text-decoration: underline;
transition: all 0.2s linear;
}
svg.icons {
@ -1953,21 +1954,8 @@ svg.icons {
-moz-animation: spin 2s linear infinite;
animation: spin 2s linear infinite;
}
@-moz-keyframes spin {
100% {
-moz-transform: rotate(360deg);
}
}
@-webkit-keyframes spin {
100% {
-webkit-transform: rotate(360deg);
}
}
@keyframes spin {
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
#notifications #notifyMessage .notify-icon {
background: #32302f;
@ -2057,10 +2045,7 @@ svg.icons {
border-radius: 50px;
}
.main-container section header #wrapper #right #dash-menu a button svg {
-moz-transition: all 0.1s linear;
-webkit-transition: all 0.1s linear;
-o-transition: all 0.1s linear;
transition: all 0.1s linear;
transition: all 0.2s linear;
width: 40px;
height: 20px;
fill: #EFEBE3;
@ -2270,15 +2255,12 @@ svg.icons {
margin-left: 10px;
}
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list .recent-header .index-header-right a button svg {
-moz-transition: all 0.1s linear;
-webkit-transition: all 0.1s linear;
-o-transition: all 0.1s linear;
transition: all 0.1s linear;
transition: all 0.2s linear;
width: 40px;
height: 20px;
fill: #EFEBE3;
}
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link {
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link, #dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-video-link {
font-size: 1.5em;
font-weight: 300;
display: inline-block;
@ -2286,8 +2268,15 @@ svg.icons {
vertical-align: top;
text-decoration: none;
position: relative;
overflow: hidden;
}
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link label {
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link .post-video, #dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-video-link .post-video {
width: 100%;
height: 100%;
object-fit: cover;
position: absolute;
}
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link label, #dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-video-link label {
font-size: 1.4em;
font-weight: 700;
color: #EFEBE3;
@ -2301,53 +2290,53 @@ svg.icons {
top: 35%;
text-shadow: 2px 2px 0 #32302f;
}
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link div#options {
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link div#options, #dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-video-link div#options {
width: 100%;
position: absolute;
bottom: 0;
border-radius: 0 0 3px 3px;
background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.65) 100%);
}
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link div#options #option-left {
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link div#options #option-left, #dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-video-link div#options #option-left {
display: inline-block;
vertical-align: top;
width: 50%;
position: relative;
background: none;
}
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link div#options #option-left button {
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link div#options #option-left button, #dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-video-link div#options #option-left button {
border-radius: 3px;
background: #1D3040;
margin: 0 0 10px 10px;
}
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link div#options #option-left button svg {
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link div#options #option-left button svg, #dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-video-link div#options #option-left button svg {
width: 40px;
height: 20px;
fill: #b2cce5;
}
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link div#options #option-left .item-options {
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link div#options #option-left .item-options, #dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-video-link div#options #option-left .item-options {
border-radius: 3px;
margin: 5px;
display: inline-block;
}
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link div#options #option-left button[data-active=false] {
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link div#options #option-left button[data-active=false], #dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-video-link div#options #option-left button[data-active=false] {
background: #1D3040;
}
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link div#options #option-left button[data-active=false] svg {
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link div#options #option-left button[data-active=false] svg, #dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-video-link div#options #option-left button[data-active=false] svg {
fill: #b2cce5;
}
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link div#options #option-left button[data-active=true] {
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link div#options #option-left button[data-active=true], #dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-video-link div#options #option-left button[data-active=true] {
background: #f5ab35;
}
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link div#options #option-left button[data-active=true] svg {
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link div#options #option-left button[data-active=true] svg, #dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-video-link div#options #option-left button[data-active=true] svg {
fill: #1D3040;
}
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link div#options #option-right {
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link div#options #option-right, #dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-video-link div#options #option-right {
display: inline-block;
width: 50%;
text-align: right;
}
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link div#options #option-right span {
#dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-link div#options #option-right span, #dash-index-content #dash-index #dash-index-wrapper #dash-recent #recent-list a.post-video-link div#options #option-right span {
font-weight: bold;
display: block;
background: #EFEBE3;
@ -2845,9 +2834,6 @@ button, input[type=submit] {
cursor: pointer;
border: 0;
padding: 10px 0 5px 0;
-moz-transition: all 0.3s linear;
-webkit-transition: all 0.3s linear;
-o-transition: all 0.3s linear;
transition: all 0.3s linear;
}
@ -2911,7 +2897,8 @@ select {
margin-left: 10px;
width: 55px;
}
#post-index #post-index-wrapper #post-index-header #post-index-header-right a button svg {
#post-index #post-index-wrapper #post-index-header #post-index-header-right a svg {
transition: all 0.1s linear;
width: 20px;
height: 17px;
fill: #EFEBE3;
@ -2942,13 +2929,17 @@ select {
vertical-align: top;
width: 100%;
}
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg {
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg, #post-index #post-index-wrapper #posts-list a.page-link div.page-video {
width: 100%;
height: 350px;
background-color: #fc6399;
position: relative;
}
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg label {
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg video, #post-index #post-index-wrapper #posts-list a.page-link div.page-video video {
width: 100%;
position: absolute;
}
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg label, #post-index #post-index-wrapper #posts-list a.page-link div.page-video label {
font-size: 2em;
font-weight: 700;
color: #EFEBE3;
@ -2961,9 +2952,8 @@ select {
position: relative;
top: 35%;
text-shadow: 2px 2px 0 #32302f;
text-shadow: 2px 2px 0 #32302f;
}
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg #meta {
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg #meta, #post-index #post-index-wrapper #posts-list a.page-link div.page-video #meta {
width: 100%;
background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.65) 100%);
border-radius: 3px;
@ -2972,51 +2962,52 @@ select {
position: absolute;
padding: 0 0 20px 0;
}
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg #meta #options {
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg #meta #options, #post-index #post-index-wrapper #posts-list a.page-link div.page-video #meta #options {
width: 100%;
bottom: 0;
position: absolute;
}
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg #meta #options #option-left {
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg #meta #options #option-left, #post-index #post-index-wrapper #posts-list a.page-link div.page-video #meta #options #option-left {
display: inline-block;
vertical-align: top;
width: 50%;
position: relative;
background: none;
}
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg #meta #options #option-left button {
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg #meta #options #option-left button, #post-index #post-index-wrapper #posts-list a.page-link div.page-video #meta #options #option-left button {
border-radius: 3px;
background: #1D3040;
margin: 0 0 10px 10px;
}
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg #meta #options #option-left button svg {
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg #meta #options #option-left svg, #post-index #post-index-wrapper #posts-list a.page-link div.page-video #meta #options #option-left svg {
transition: all 0.2s linear;
width: 40px;
height: 20px;
fill: #b2cce5;
}
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg #meta #options #option-left .item-options {
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg #meta #options #option-left .item-options, #post-index #post-index-wrapper #posts-list a.page-link div.page-video #meta #options #option-left .item-options {
border-radius: 3px;
margin: 5px;
display: inline-block;
}
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg #meta #options #option-left button[data-active=false] {
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg #meta #options #option-left button[data-active=false], #post-index #post-index-wrapper #posts-list a.page-link div.page-video #meta #options #option-left button[data-active=false] {
background: #1D3040;
}
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg #meta #options #option-left button[data-active=false] svg {
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg #meta #options #option-left button[data-active=false] svg, #post-index #post-index-wrapper #posts-list a.page-link div.page-video #meta #options #option-left button[data-active=false] svg {
fill: #b2cce5;
}
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg #meta #options #option-left button[data-active=true] {
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg #meta #options #option-left button[data-active=true], #post-index #post-index-wrapper #posts-list a.page-link div.page-video #meta #options #option-left button[data-active=true] {
background: #f5ab35;
}
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg #meta #options #option-left button[data-active=true] svg {
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg #meta #options #option-left button[data-active=true] svg, #post-index #post-index-wrapper #posts-list a.page-link div.page-video #meta #options #option-left button[data-active=true] svg {
fill: #1D3040;
}
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg #meta #options #option-right {
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg #meta #options #option-right, #post-index #post-index-wrapper #posts-list a.page-link div.page-video #meta #options #option-right {
display: inline-block;
width: 50%;
text-align: right;
}
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg #meta #options #option-right span {
#post-index #post-index-wrapper #posts-list a.page-link div.page-bg #meta #options #option-right span, #post-index #post-index-wrapper #posts-list a.page-link div.page-video #meta #options #option-right span {
font-weight: bold;
display: block;
background: #EFEBE3;
@ -3138,13 +3129,6 @@ select {
#post-edit-index #post-edit-index-wrapper #post-header #post-header-wrapper #post-meta #post-options button {
width: 25%;
height: 45px;
-moz-transition: all 0.3s linear;
-webkit-transition: all 0.3s linear;
-o-transition: all 0.3s linear;
transition: all 0.3s linear;
-moz-transition: all 0.3s linear;
-webkit-transition: all 0.3s linear;
-o-transition: all 0.3s linear;
transition: all 0.3s linear;
margin: 0;
border-radius: 0;
@ -3164,41 +3148,88 @@ select {
#post-edit-index #post-edit-index-wrapper #post-header #post-header-wrapper #post-meta #post-options button[data-active=true] svg {
fill: #1D3040;
}
#post-edit-index #post-edit-index-wrapper #post-header #post-header-wrapper #post-meta #featured-image-upload, #post-edit-index #post-edit-index-wrapper #post-header #post-header-wrapper #post-meta #post-image-upload {
#post-edit-index #post-edit-index-wrapper #post-header #post-header-wrapper #post-meta #page-files-upload, #post-edit-index #post-edit-index-wrapper #post-header #post-header-wrapper #post-meta #post-image-upload {
display: none;
}
#post-edit-index #post-edit-index-wrapper #post-feature {
width: 100%;
}
#post-edit-index #post-edit-index-wrapper #post-feature #featured-image-drop {
#post-edit-index #post-edit-index-wrapper #post-feature #page-file-manager {
background: #f5ab35;
width: 100%;
min-height: 300px;
}
#post-edit-index #post-edit-index-wrapper #post-feature #page-file-manager #page-file-wrapper {
width: 100%;
max-width: 900px;
padding: 10px;
margin: 0 auto;
font-weight: bold;
font-color: #1D3040;
font-size: 1em;
}
#post-edit-index #post-edit-index-wrapper #post-feature #page-file-manager #page-file-wrapper #page-file-drop {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
min-height: 200px;
background: black;
min-height: 100px;
background: #EFEBE3;
color: #1D3040;
vertical-align: middle;
font-family: "Lucida Console", Monaco, monospace;
border-radius: 5px;
margin: 0 0 10px 0;
}
#post-edit-index #post-edit-index-wrapper #post-feature #featured-image-drop label {
#post-edit-index #post-edit-index-wrapper #post-feature #page-file-manager #page-file-wrapper #page-file-drop label {
cursor: pointer;
font-weight: 600px;
text-transform: capitalize;
}
#post-edit-index #post-edit-index-wrapper #post-feature #featured-image-drop img {
#post-edit-index #post-edit-index-wrapper #post-feature #page-file-manager #page-file-wrapper #page-file-drop img {
width: 100%;
margin: 0;
padding: 0;
}
#post-edit-index #post-edit-index-wrapper #post-feature #featured-new-image-btn {
position: absolute;
margin: 20px;
#post-edit-index #post-edit-index-wrapper #post-feature #page-file-manager #page-file-wrapper #page-images-list, #post-edit-index #post-edit-index-wrapper #post-feature #page-file-manager #page-file-wrapper #page-files-list {
padding: 10px 0 0 0;
}
#post-edit-index #post-edit-index-wrapper #post-feature #featured-new-image-btn #new-feature-upload {
padding-top: 4px;
background: #EFEBE3;
#post-edit-index #post-edit-index-wrapper #post-feature #page-file-manager #page-file-wrapper #page-images-list .img-item, #post-edit-index #post-edit-index-wrapper #post-feature #page-file-manager #page-file-wrapper #page-files-list .img-item {
height: 150px;
width: 23.8%;
border-radius: 3px;
margin: 0 10px 10px 0;
display: inline-block;
cursor: pointer;
}
#post-edit-index #post-edit-index-wrapper #post-feature #featured-new-image-btn #new-feature-upload svg {
fill: #fc6399;
#post-edit-index #post-edit-index-wrapper #post-feature #page-file-manager #page-file-wrapper #page-images-list .audio-item, #post-edit-index #post-edit-index-wrapper #post-feature #page-file-manager #page-file-wrapper #page-files-list .audio-item {
height: 150px;
width: 23.8%;
border-radius: 3px;
margin: 0 10px 10px 0;
display: inline-block;
cursor: pointer;
background: #1D3040;
background: url("/assets/images/global/upload-audio.png") no-repeat center center/cover;
}
#post-edit-index #post-edit-index-wrapper #post-feature #page-file-manager #page-file-wrapper #page-images-list .video-item, #post-edit-index #post-edit-index-wrapper #post-feature #page-file-manager #page-file-wrapper #page-files-list .video-item {
height: 150px;
width: 23.8%;
border-radius: 3px;
margin: 0 10px 10px 0;
display: inline-block;
cursor: pointer;
background: #1D3040;
background: url("/assets/images/global/upload-video.png") no-repeat center center/cover;
}
#post-edit-index #post-edit-index-wrapper #post-feature #page-file-manager #page-file-wrapper #page-images-list .file-item, #post-edit-index #post-edit-index-wrapper #post-feature #page-file-manager #page-file-wrapper #page-files-list .file-item {
height: 150px;
width: 23.8%;
border-radius: 3px;
margin: 0 10px 10px 0;
display: inline-block;
cursor: pointer;
background: #1D3040;
background: url("/assets/images/global/upload-doc.png") no-repeat center center/cover;
}
#post-edit-index #post-edit-index-wrapper #edit-post {
width: 100%;
@ -3216,7 +3247,6 @@ select {
border-color: #fc6399;
}
#post-edit-index #post-edit-index-wrapper #edit-post #edit-post-wrapper #edit, #post-edit-index #post-edit-index-wrapper #edit-post #edit-post-wrapper #highlight {
/* Both elements need the same text and space styling so they are directly on top of each other */
border: 0;
width: 100%;
min-height: 300px;
@ -3248,6 +3278,28 @@ select {
#post-edit-index #post-edit-index-wrapper #edit-post #edit-post-wrapper #highlight {
z-index: 0;
}
#post-edit-index #post-edit-index-wrapper #edit-post #edit-post-wrapper #highlight pre {
margin: 0;
}
#post-edit-index #post-edit-index-wrapper #edit-post #edit-post-wrapper #highlight pre code {
font-family: "Lucida Console", Monaco, monospace;
padding: 5px;
border-radius: 5px;
line-height: 1.6em;
font-size: 1.25em;
color: #fde3a7;
word-wrap: normal;
white-space: pre-wrap;
line-break: normal;
-webkit-line-break: normal;
-o-line-break: normal;
-moz-line-break: normal;
display: inline-block;
width: 100%;
max-width: 900px;
min-height: 200px;
caret-color: #fc6399;
}
@media only screen and (max-width: 800px) {
#post-edit-index #post-edit-index-wrapper #post-header #post-title #post-date {
@ -3630,9 +3682,6 @@ select {
background: #b2cce5;
width: 10%;
height: 39px;
-moz-transition: all 0.3s linear;
-webkit-transition: all 0.3s linear;
-o-transition: all 0.3s linear;
transition: all 0.3s linear;
margin: 0;
border-radius: 0;

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 486 678" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g id="Logo" transform="matrix(1.36867,0,0,1.36867,-351.696,-71.9183)">
<g transform="matrix(2.31599,0,0,2.31599,218.53,-99.4797)">
<path d="M93.67,140.92L93.67,140.921C105.569,140.921 115.216,150.567 115.216,162.467L115.216,172.724L115.216,172.724L115.216,182.262C115.216,194.161 105.569,203.808 93.669,203.808C81.976,203.217 74.12,195.969 72.237,184.474L72.282,182.737L72.282,162.467L72.205,160.847C72.775,149.587 82.728,141.121 93.67,140.92Z" style="fill:rgb(252,99,153);fill-rule:nonzero;"/>
</g>
<g transform="matrix(2.31599,0,0,2.31599,218.53,-437.697)">
<path d="M93.67,211.678L93.67,211.678C105.569,211.678 115.216,221.324 115.216,233.224L115.216,243.481L115.216,243.481L115.216,253.019C115.216,264.919 105.569,274.565 93.669,274.565C81.976,273.975 74.12,266.726 72.237,255.232L72.282,253.495L72.282,233.224L72.205,231.604C72.775,220.344 82.728,211.878 93.67,211.678Z" style="fill:rgb(252,99,153);fill-rule:nonzero;"/>
</g>
<g transform="matrix(2.31599,0,0,2.31599,218.53,241.338)">
<path d="M93.67,69.288L93.67,69.288C105.569,69.288 115.216,78.934 115.216,90.834L115.216,101.091L115.216,101.091L115.216,110.629C115.216,122.528 105.569,132.175 93.669,132.175C81.976,131.584 74.12,124.336 72.237,112.842L72.282,111.105L72.282,90.834L72.205,89.214C72.775,77.954 82.728,69.488 93.67,69.288Z" style="fill:rgb(171,183,183);fill-rule:nonzero;"/>
</g>
<g transform="matrix(2.31599,0,0,2.31599,218.53,-104.112)">
<path d="M38.059,142.92L38.059,142.921C49.958,142.921 59.605,152.567 59.605,164.467L59.605,174.724L59.605,174.724L59.605,184.262C59.605,196.161 49.958,205.808 38.058,205.808C26.365,205.217 18.509,197.969 16.626,186.474L16.671,184.737L16.671,164.467L16.594,162.847C17.164,151.587 27.117,143.121 38.059,142.92Z" style="fill:rgb(252,99,153);fill-rule:nonzero;"/>
</g>
<g transform="matrix(2.31599,0,0,2.31599,218.53,-104.112)">
<path d="M148.331,142.92L148.331,142.921C160.23,142.921 169.877,152.567 169.877,164.467L169.877,174.724L169.877,174.724L169.877,184.262C169.877,196.161 160.23,205.808 148.331,205.808C136.637,205.217 128.782,197.969 126.898,186.474L126.943,184.737L126.943,164.467L126.867,162.847C127.436,151.587 137.389,143.121 148.331,142.92Z" style="fill:rgb(171,183,183);fill-rule:nonzero;"/>
</g>
<g transform="matrix(2.31599,0,0,2.31599,218.53,-437.697)">
<path d="M38.059,211.678L38.059,211.678C49.958,211.678 59.605,221.324 59.605,233.224L59.605,243.481L59.605,243.481L59.605,253.019C59.605,264.919 49.958,274.565 38.058,274.565C26.365,273.975 18.509,266.726 16.626,255.232L16.671,253.495L16.671,233.224L16.594,231.604C17.164,220.344 27.117,211.878 38.059,211.678Z" style="fill:rgb(252,99,153);fill-rule:nonzero;"/>
</g>
<g transform="matrix(2.31599,0,0,2.31599,218.53,-437.697)">
<path d="M148.331,211.678L148.331,211.678C160.23,211.678 169.877,221.324 169.877,233.224L169.877,243.481L169.877,243.481L169.877,253.019C169.877,264.919 160.23,274.565 148.331,274.565C136.637,273.975 128.782,266.726 126.898,255.232L126.943,253.495L126.943,233.224L126.867,231.604C127.436,220.344 137.389,211.878 148.331,211.678Z" style="fill:rgb(252,99,153);fill-rule:nonzero;"/>
</g>
<g transform="matrix(2.31599,0,0,2.31599,218.53,241.338)">
<path d="M38.059,69.288L38.059,69.288C49.958,69.288 59.605,78.934 59.605,90.834L59.605,101.091L59.605,101.091L59.605,110.629C59.605,122.528 49.958,132.175 38.058,132.175C26.365,131.584 18.509,124.336 16.626,112.842L16.671,111.105L16.671,90.834L16.594,89.214C17.164,77.954 27.117,69.488 38.059,69.288Z" style="fill:rgb(252,99,153);fill-rule:nonzero;"/>
</g>
<g transform="matrix(2.31599,0,0,2.31599,218.53,241.338)">
<path d="M148.331,69.288L148.331,69.288C160.23,69.288 169.877,78.934 169.877,90.834L169.877,101.091L169.877,101.091L169.877,110.629C169.877,122.528 160.23,132.175 148.331,132.175C136.637,131.584 128.782,124.336 126.898,112.842L126.943,111.105L126.943,90.834L126.867,89.214C127.436,77.954 137.389,69.488 148.331,69.288Z" style="fill:rgb(171,183,183);fill-rule:nonzero;"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,5 +1,7 @@
<?php
require "../vendor/autoload.php";
include "../brain/App.inc.php";
use brain\init\App as App;
new App();

204
src/com/ui/FileManager.js Normal file
View file

@ -0,0 +1,204 @@
import Sortable from 'sortablejs';
import DataUtils from '../utils/DataUtils';
import Notfications from './Notifications.js';
const notify = new Notfications();
export default class FileManager {
//--------------------------
// constructor
//--------------------------
constructor(upload, input, imageList, fileList) {
this.upload = upload;
this.input = input;
this.imageList = imageList;
this.fileList = fileList;
this.accetableFiles = [
'image/jpeg',
'image/gif',
'image/png',
'image/svg',
'audio/mpeg',
'video/mp4',
'application/pdf',
'text/plain',
'text/rtf'
];
this.files = [];
this.sortedFiles = [];
this.storage = [];
this.start();
}
//--------------------------
// methods
//--------------------------
start() {
this.upload.addEventListener('dragover', e => this.handleFileActions(e), false);
this.upload.addEventListener('drop', e => this.handleFileActions(e), false);
this.input.addEventListener('change', e => this.handleFileActions(e), false);
Sortable.create(this.imageList, {
onUpdate: e => {
notify.alert('REINDEXING FILES', null);
let currentFiles = []; //store current list
let items = e.target.children;
for (let index = 0; index < items.length; index++) {
var item = items[index];
let url = '';
if (item.className == 'img-item') {
url = item.style.backgroundImage.slice(4, -1).replace(/"/g, '');
} else {
url = item.getAttribute('data-source');
}
currentFiles.push({
earl: url
});
}
this.reindexFiles(currentFiles, 0);
}
});
Sortable.create(this.fileList, {
onUpdate: e => {
notify.alert('REINDEXING FILES', null);
let currentFiles = [];
let items = e.target.children;
for (let index = 0; index < items.length; index++) {
var item = items[index];
let url = item.getAttribute('data-source');
currentFiles.push({
earl: url
});
}
this.reindexFiles(currentFiles, 0);
}
});
}
getFiles() {
return this.files;
}
reindexFiles(sortOrder, step) {
let count = sortOrder.length;
if (step == 0) this.files = [];
var utils = new DataUtils();
var path = sortOrder[step].earl.split('/');
utils.imgLoad(sortOrder[step].earl).then(blob => {
var fresh = new File([blob], path[6], { type: blob.type });
this.files.push(fresh);
if (this.files.length <= count - 1) {
this.reindexFiles(sortOrder, ++step);
} else {
notify.alert('FILES READY TO UPLOAD', true);
}
});
}
sortFiles(files) {
var self = this;
this.files = []; //clear files array
this.imageList.innerHTML = '';
this.fileList.innerHTML = '';
for (var i = 0, file; (file = files[i]); i++) {
var reader = new FileReader();
// Closure to capture the file information
reader.onload = (theFile => {
return function (f) {
// sort files
switch (theFile.type) {
case 'image/jpg':
case 'image/jpeg':
case 'image/gif':
case 'image/svg':
case 'image/png':
//create element and add to list
var image = document.createElement('img');
image.src = f.target.result;
image.title = escape(theFile.name);
var span = document.createElement('div');
span.style.background =
'url(' +
f.target.result +
') no-repeat center center / cover';
span.className = 'img-item';
image.setAttribute('id', i);
self.storage.push([
{
id: 'page_image' + i,
data: f.target.result,
type: theFile.type,
name: escape(theFile.name)
}
]);
self.imageList.appendChild(span);
//add to files list
self.files.push(theFile);
break;
case 'video/mp4':
var video = document.createElement('div');
video.className = 'video-item';
video.setAttribute('data-source', f.target.result);
self.imageList.appendChild(video);
self.files.push(theFile);
break;
case 'audio/mpeg':
var sound = document.createElement('div');
sound.className = 'audio-item';
sound.setAttribute('data-source', f.target.result);
self.fileList.appendChild(sound);
self.files.push(theFile);
break;
case 'application/pdf':
case 'text/plain':
case 'text/rtf':
var file = document.createElement('div');
file.className = 'file-item';
file.setAttribute('data-source', f.target.result);
self.fileList.appendChild(file);
self.files.push(theFile);
break;
}
};
})(file);
// Read in the image file as a data URL.
reader.readAsDataURL(file);
}
}
//--------------------------
// event handlers
//--------------------------
handleFileActions(e) {
e.stopPropagation();
e.preventDefault();
let self = this;
let rawList = [];
let sortedList = [];
let notOnTheList = [];
switch (e.type) {
case 'dragover':
e.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
break;
case 'change':
case 'drop':
e.type == 'drop'
? (rawList = e.dataTransfer.files)
: (rawList = e.target.files);
for (var i = 0, f; (f = rawList[i]); i++) {
// check witch files are cool to upload
if (this.accetableFiles.includes(f.type)) {
sortedList.push(f);
} else {
notOnTheList.push(f);
}
}
//send for sorting
self.sortFiles(sortedList);
break;
}
}
}