🎉 initial commit

This commit is contained in:
2024-10-07 22:58:27 +02:00
commit d3eccf99f0
824 changed files with 16401 additions and 0 deletions

114
.buildpath Normal file
View File

@@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8"?>
<buildpath>
<buildpathentry kind="con" path="org.eclipse.php.core.LANGUAGE"/>
<buildpathentry kind="src" path="classes/external/bramus/router/src">
<attributes>
<attribute name="composer" value="vendor"/>
</attributes>
</buildpathentry>
<buildpathentry kind="src" path="classes/external/composer">
<attributes>
<attribute name="composer" value="vendor"/>
</attributes>
</buildpathentry>
<buildpathentry kind="src" path="classes/external/fakerphp/faker/src/Faker">
<attributes>
<attribute name="composer" value="vendor"/>
</attributes>
</buildpathentry>
<buildpathentry kind="src" path="classes/external/guzzlehttp/promises/src">
<attributes>
<attribute name="composer" value="vendor"/>
</attributes>
</buildpathentry>
<buildpathentry kind="src" path="classes/external/guzzlehttp/psr7/src">
<attributes>
<attribute name="composer" value="vendor"/>
</attributes>
</buildpathentry>
<buildpathentry kind="src" path="classes/external/psr/container/src">
<attributes>
<attribute name="composer" value="vendor"/>
</attributes>
</buildpathentry>
<buildpathentry kind="src" path="classes/external/psr/http-client/src">
<attributes>
<attribute name="composer" value="vendor"/>
</attributes>
</buildpathentry>
<buildpathentry kind="src" path="classes/external/psr/http-factory/src">
<attributes>
<attribute name="composer" value="vendor"/>
</attributes>
</buildpathentry>
<buildpathentry kind="src" path="classes/external/psr/http-message/src">
<attributes>
<attribute name="composer" value="vendor"/>
</attributes>
</buildpathentry>
<buildpathentry kind="src" path="classes/external/scssphp/scssphp/src">
<attributes>
<attribute name="composer" value="vendor"/>
</attributes>
</buildpathentry>
<buildpathentry kind="src" path="classes/external/scssphp/server/src">
<attributes>
<attribute name="composer" value="vendor"/>
</attributes>
</buildpathentry>
<buildpathentry kind="src" path="classes/external/twig/twig/src">
<attributes>
<attribute name="composer" value="vendor"/>
</attributes>
</buildpathentry>
<buildpathentry kind="src" path="classes/external/guzzlehttp/guzzle/src">
<attributes>
<attribute name="composer" value="vendor"/>
</attributes>
</buildpathentry>
<buildpathentry kind="src" path="classes/external/ralouphie/getallheaders/src">
<attributes>
<attribute name="composer" value="vendor"/>
</attributes>
</buildpathentry>
<buildpathentry kind="src" path="classes/external/symfony/deprecation-contracts">
<attributes>
<attribute name="composer" value="vendor"/>
</attributes>
</buildpathentry>
<buildpathentry kind="src" path="classes/external/symfony/polyfill-ctype">
<attributes>
<attribute name="composer" value="vendor"/>
</attributes>
</buildpathentry>
<buildpathentry kind="src" path="classes/external/symfony/polyfill-mbstring">
<attributes>
<attribute name="composer" value="vendor"/>
</attributes>
</buildpathentry>
<buildpathentry excluding="Resources/stubs/" kind="src" path="classes/external/symfony/polyfill-php80">
<attributes>
<attribute name="composer" value="vendor"/>
</attributes>
</buildpathentry>
<buildpathentry kind="src" path="classes/external/symfony/polyfill-php80/Resources/stubs">
<attributes>
<attribute name="composer" value="vendor"/>
</attributes>
</buildpathentry>
<buildpathentry excluding="external/bramus/router/src/|external/composer/|external/fakerphp/faker/src/Faker/|external/guzzlehttp/guzzle/src/|external/guzzlehttp/promises/src/|external/guzzlehttp/psr7/src/|external/psr/container/src/|external/psr/http-client/src/|external/psr/http-factory/src/|external/psr/http-message/src/|external/scssphp/scssphp/src/|external/scssphp/server/src/|external/symfony/polyfill-ctype/|external/symfony/polyfill-mbstring/|external/symfony/polyfill-php80/|external/twig/twig/src/|external/ralouphie/getallheaders/src/|external/symfony/deprecation-contracts/|external/tracy/tracy/src/" kind="src" path="classes">
<attributes>
<attribute name="composer" value="source"/>
</attributes>
</buildpathentry>
<buildpathentry excluding="Tracy/" kind="src" path="classes/external/tracy/tracy/src">
<attributes>
<attribute name="composer" value="vendor"/>
</attributes>
</buildpathentry>
<buildpathentry kind="src" path="classes/external/tracy/tracy/src/Tracy">
<attributes>
<attribute name="composer" value="vendor"/>
</attributes>
</buildpathentry>
</buildpath>

21
.editorconfig Normal file
View File

@@ -0,0 +1,21 @@
[*.{css,scss,less,js,json,ts,sass,html,hbs,mustache,phtml,html.twig,md,yml}]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
indent_size = 4
trim_trailing_whitespace = false
[site/templates/**.php]
indent_size = 2
[site/snippets/**.php]
indent_size = 2
[package.json,.{babelrc,editorconfig,eslintrc,lintstagedrc,stylelintrc}]
indent_style = space
indent_size = 2

2
.env.example Normal file
View File

@@ -0,0 +1,2 @@
COCKPIT_API_PATH=
COCKPIT_API_KEY=

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
classes/external/*
cache/*
.env

8
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

14
.idea/deployment.xml generated Normal file
View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PublishConfigData" remoteFilesAllowedToDisappearOnAutoupload="false">
<serverData>
<paths name="localhost">
<serverdata>
<mappings>
<mapping local="$PROJECT_DIR$" web="/" />
</mappings>
</serverdata>
</paths>
</serverData>
</component>
</project>

View File

@@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>

13
.idea/material_theme_project_new.xml generated Normal file
View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MaterialThemeProjectNewConfig">
<option name="metadata">
<MTProjectMetadataState>
<option name="migrated" value="true" />
<option name="pristineConfig" value="false" />
<option name="userId" value="eb0ded3:168bec48898:-8000" />
<option name="version" value="8.13.2" />
</MTProjectMetadataState>
</option>
</component>
</project>

6
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="NodePackageJsonFileManager">
<packageJsonPaths />
</component>
</project>

8
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/newspage.iml" filepath="$PROJECT_DIR$/.idea/newspage.iml" />
</modules>
</component>
</project>

70
.idea/newspage.iml generated Normal file
View File

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/classes" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/bramus/router/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/bramus/router/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/fakerphp/faker/src/Faker" isTestSource="false" packagePrefix="Faker\" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/fakerphp/faker/test/Faker" isTestSource="true" packagePrefix="Faker\Test\" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/fakerphp/faker/test/Fixture" isTestSource="true" packagePrefix="Faker\Test\Fixture\" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/fakerphp/faker/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/guzzlehttp/guzzle/src" isTestSource="false" packagePrefix="GuzzleHttp\" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/guzzlehttp/guzzle/tests" isTestSource="true" packagePrefix="GuzzleHttp\Tests\" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/guzzlehttp/guzzle/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/guzzlehttp/promises/src" isTestSource="false" packagePrefix="GuzzleHttp\Promise\" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/guzzlehttp/promises/tests" isTestSource="true" packagePrefix="GuzzleHttp\Promise\Tests\" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/guzzlehttp/promises/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/guzzlehttp/psr7/src" isTestSource="false" packagePrefix="GuzzleHttp\Psr7\" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/guzzlehttp/psr7/tests" isTestSource="true" packagePrefix="GuzzleHttp\Tests\Psr7\" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/guzzlehttp/psr7/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/psr/container/src" isTestSource="false" packagePrefix="Psr\Container\" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/psr/http-client/src" isTestSource="false" packagePrefix="Psr\Http\Client\" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/psr/http-factory/src" isTestSource="false" packagePrefix="Psr\Http\Message\" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/psr/http-message/src" isTestSource="false" packagePrefix="Psr\Http\Message\" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/ralouphie/getallheaders/tests" isTestSource="true" packagePrefix="getallheaders\Tests\" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/ralouphie/getallheaders/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/scssphp/scssphp/src" isTestSource="false" packagePrefix="ScssPhp\ScssPhp\" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/scssphp/scssphp/tests" isTestSource="true" packagePrefix="ScssPhp\ScssPhp\Tests\" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/scssphp/scssphp/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/scssphp/server/src" isTestSource="false" packagePrefix="ScssPhp\Server\" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/scssphp/server/tests" isTestSource="true" packagePrefix="ScssPhp\Server\Tests\" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/scssphp/server/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/symfony/polyfill-ctype/" isTestSource="false" packagePrefix="Symfony\Polyfill\Ctype\" />
<sourceFolder url="file://$MODULE_DIR$/spec" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/symfony/polyfill-mbstring/" isTestSource="false" packagePrefix="Symfony\Polyfill\Mbstring\" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/symfony/polyfill-php80/" isTestSource="false" packagePrefix="Symfony\Polyfill\Php80\" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/twig/twig/src" isTestSource="false" packagePrefix="Twig\" />
<sourceFolder url="file://$MODULE_DIR$/classes/external/twig/twig/tests" isTestSource="true" packagePrefix="Twig\Tests\" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/bramus/router" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/composer" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/fakerphp/faker" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/guzzlehttp/guzzle" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/guzzlehttp/promises" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/guzzlehttp/psr7" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/psr/container" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/psr/http-client" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/psr/http-factory" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/psr/http-message" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/ralouphie/getallheaders" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/scssphp/scssphp" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/scssphp/server" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/symfony/deprecation-contracts" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/symfony/polyfill-ctype" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/symfony/polyfill-mbstring" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/symfony/polyfill-php80" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/tracy/tracy" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/twig/twig" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/doctrine/instantiator" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/doctrine/lexer" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/graham-campbell/result-type" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/jms/metadata" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/jms/serializer" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/phpoption/phpoption" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/phpstan/phpdoc-parser" />
<excludeFolder url="file://$MODULE_DIR$/classes/external/vlucas/phpdotenv" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

56
.idea/php.xml generated Normal file
View File

@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MessDetectorOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCSFixerOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCodeSnifferOptionsConfiguration">
<option name="highlightLevel" value="WARNING" />
<option name="transferred" value="true" />
</component>
<component name="PhpIncludePathManager">
<include_path>
<path value="$PROJECT_DIR$/classes/external/guzzlehttp/guzzle" />
<path value="$PROJECT_DIR$/classes/external/guzzlehttp/promises" />
<path value="$PROJECT_DIR$/classes/external/guzzlehttp/psr7" />
<path value="$PROJECT_DIR$/classes/external/graham-campbell/result-type" />
<path value="$PROJECT_DIR$/classes/external/symfony/deprecation-contracts" />
<path value="$PROJECT_DIR$/classes/external/symfony/polyfill-ctype" />
<path value="$PROJECT_DIR$/classes/external/symfony/polyfill-mbstring" />
<path value="$PROJECT_DIR$/classes/external/symfony/polyfill-php80" />
<path value="$PROJECT_DIR$/classes/external/ralouphie/getallheaders" />
<path value="$PROJECT_DIR$/classes/external/scssphp/scssphp" />
<path value="$PROJECT_DIR$/classes/external/scssphp/server" />
<path value="$PROJECT_DIR$/classes/external/tracy/tracy" />
<path value="$PROJECT_DIR$/classes/external/psr/container" />
<path value="$PROJECT_DIR$/classes/external/psr/http-client" />
<path value="$PROJECT_DIR$/classes/external/psr/http-factory" />
<path value="$PROJECT_DIR$/classes/external/psr/http-message" />
<path value="$PROJECT_DIR$/classes/external/jms/metadata" />
<path value="$PROJECT_DIR$/classes/external/jms/serializer" />
<path value="$PROJECT_DIR$/classes/external/vlucas/phpdotenv" />
<path value="$PROJECT_DIR$/classes/external/fakerphp/faker" />
<path value="$PROJECT_DIR$/classes/external/phpstan/phpdoc-parser" />
<path value="$PROJECT_DIR$/classes/external/bramus/router" />
<path value="$PROJECT_DIR$/classes/external/twig/twig" />
<path value="$PROJECT_DIR$/classes/external/composer" />
<path value="$PROJECT_DIR$/classes/external/doctrine/instantiator" />
<path value="$PROJECT_DIR$/classes/external/doctrine/lexer" />
<path value="$PROJECT_DIR$/classes/external/phpoption/phpoption" />
</include_path>
</component>
<component name="PhpProjectSharedConfiguration" php_language_level="8.1" />
<component name="PhpStanOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PhpUnit">
<phpunit_settings>
<PhpUnitSettings custom_loader_path="$PROJECT_DIR$/classes/external/autoload.php" />
</phpunit_settings>
</component>
<component name="PsalmOptionsConfiguration">
<option name="transferred" value="true" />
</component>
</project>

10
.idea/phpspec.xml generated Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PHPSpec">
<suites>
<PhpSpecSuiteConfiguration>
<option name="myPath" value="$PROJECT_DIR$" />
</PhpSpecSuiteConfiguration>
</suites>
</component>
</project>

17
.idea/phpunit.xml generated Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PHPUnit">
<option name="directories">
<list>
<option value="$PROJECT_DIR$/classes/external/scssphp/scssphp/tests" />
<option value="$PROJECT_DIR$/classes/external/ralouphie/getallheaders/tests" />
<option value="$PROJECT_DIR$/classes/external/guzzlehttp/guzzle/tests" />
<option value="$PROJECT_DIR$/classes/external/fakerphp/faker/tests" />
<option value="$PROJECT_DIR$/classes/external/guzzlehttp/promises/tests" />
<option value="$PROJECT_DIR$/classes/external/guzzlehttp/psr7/tests" />
<option value="$PROJECT_DIR$/classes/external/bramus/router/tests" />
<option value="$PROJECT_DIR$/classes/external/scssphp/server/tests" />
</list>
</option>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

4
.idea/watcherTasks.xml generated Normal file
View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectTasksOptions" suppressed-tasks="SCSS" />
</project>

33
.project Normal file
View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>dnd-rules</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.php.composer.core.builder.buildPathManagementBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.wst.common.project.facet.core.builder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.wst.validation.validationbuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.dltk.core.scriptbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.php.core.PHPNature</nature>
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,77 @@
<?php
namespace Application;
use Application\Helper\ArrayPath;
use Dotenv\Dotenv;
use Exception;
class AppEnvironment
{
private static ?AppEnvironment $instance = null;
private array $environment = [];
/**
* The Singleton's constructor should always be private to prevent direct
* construction calls with the `new` operator.
*/
protected function __construct()
{
$this->loadEnvironment();
}
/**
* Singletons should not be cloneable.
*/
protected function __clone() {}
/**
* Singletons should not be restorable from strings.
*
* @throws Exception
*/
public function __wakeup()
{
throw new Exception("Cannot unserialize a singleton.");
}
/**
* This is the static method that controls the access to the singleton
* instance. On the first run, it creates a singleton object and places it
* into the static field. On subsequent runs, it returns the client existing
* object stored in the static field.
*
* This implementation lets you subclass the Singleton class while keeping
* just one instance of each subclass around.
*/
public static function getInstance(): AppEnvironment
{
if (!isset(self::$instance)) {
self::$instance = new static();
}
return self::$instance;
}
/**
* Finally, any singleton should define some business logic, which can be
* executed on its instance.
*/
private function loadEnvironment(): void
{
if (!empty($this->environment)) {
return;
}
$this->environment = Dotenv::createImmutable($_SERVER['DOCUMENT_ROOT'] . '/../')->load();
}
/**
* @throws Exception
*/
public function getVariable(string|array $key)
{
return ArrayPath::GetDataFromArray($this->environment, $key);
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace Application\Breadcrumbs;
class Breadcrumb {
/**
* @param string $name
* @param string $url
* @param bool $active
* @param bool $current
*/
public function __construct(
private string $name,
private string $url,
private bool $active = true,
private bool $current = true
) {}
public function setAsNotCurrent() {
$this->current = false;
}
public function getTemplateData() {
return array(
'name' => $this->name,
'url' => $this->url,
'active' => $this->active,
'current' => $this->current,
);
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace Application\Breadcrumbs;
class Breadcrumbs {
/**
* @var Breadcrumb[]
*/
private array $breadcrumbs;
public function __construct() {
$this->breadcrumbs[] = new Breadcrumb('Start', '/');
}
public function addBreadcrumb(string $name, string $url, bool $active = true, $current = true) {
if ($current) {
$this->setAllNonCurrent();
}
if (empty($url)) {
$active = false;
}
$this->breadcrumbs[] = new Breadcrumb($name, $url, $active, $current);
}
private function setAllNonCurrent(): void {
foreach ($this->breadcrumbs as $breadcrumb) {
$breadcrumb->setAsNotCurrent();
}
}
public function getTemplateData() {
$return = array();
foreach ($this->breadcrumbs as $breadcrumb) {
$return[] = $breadcrumb->getTemplateData();
}
return $return;
}
}

View File

@@ -0,0 +1,139 @@
<?php
namespace Application\Content;
use Application\AppEnvironment;
use Application\Models\Article;
use Application\Models\Site;
use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use JMS\Serializer\SerializerBuilder;
class CockpitApi
{
private ?Client $client = null;
public function __construct()
{
$this->client = new Client();
}
/**
* @param string $type
* @param array $variables
*
* @return string
* @throws Exception
*/
private function getApiPath(string $type = 'item', array $variables = []): string
{
$path = match ($type) {
'itemByModel' => '/content/item/{model}',
'itemsByModel' => '/content/items/{model}',
'itemByModelAndId' => '/content/item/{model}/{id}',
'items' => '/content/items',
'aggregateByModel' => '/content/aggregate/{model}',
'treeByModel' => '/content/tree/{model}',
'healthcheck' => '/system/healthcheck',
default => throw new Exception("Type '$type' does not exist."),
};
foreach ($variables as $search => $replace) {
$path = str_replace('{' . $search . '}', $replace, $path);
}
if (str_contains($path, '{')) {
throw new Exception("Non replaced variable in path '$path'.");
}
return AppEnvironment::getInstance()->getVariable('COCKPIT_API_PATH') . $path;
}
/**
* @throws GuzzleException
* @throws Exception
*/
public function getGlobalData(): Site
{
$res = $this->client->request('GET', $this->getApiPath('itemByModel', ['model' => 'site']), [
'headers' => [
'api-key' => AppEnvironment::getInstance()->getVariable('COCKPIT_API_KEY'),
],
]);
return $this->deserialize($res->getBody()->getContents(), Site::class);
}
/**
* @throws GuzzleException
* @throws Exception
*/
public function getArticles(): Article|array
{
$res = $this->client->request('GET', $this->getApiPath('itemsByModel', ['model' => 'article']), [
'headers' => [
'api-key' => AppEnvironment::getInstance()->getVariable('COCKPIT_API_KEY'),
],
'query' => [
'filter' => null, # '{fieldA:"test"}'
'fields' => null,
'sort' => null,
'limit' => 10,
'skip' => 0,
'populate' => 1,
],
]);
return $this->deserialize($res->getBody()->getContents(), Article::class);
}
/**
* @throws GuzzleException
* @throws Exception
*/
public function getArticle(string $id): Article
{
$res = $this->client->request('GET', $this->getApiPath('itemByModelAndId', ['model' => 'article', 'id' => $id]), [
'headers' => [
'api-key' => AppEnvironment::getInstance()->getVariable('COCKPIT_API_KEY'),
],
'query' => [
'filter' => null, # "{_id:$id}",
'fields' => null,
'sort' => null,
'limit' => 1,
'skip' => 0,
'populate' => 1,
],
]);
return $this->deserialize($res->getBody()->getContents(), Article::class);
}
/**
* Deserialize JSON data into objects.
*
* @param string $json
* @param string $type
*
* @return mixed
*/
private function deserialize(string $json, string $type): mixed
{
$array = json_decode($json, true);
if (!isset($array['data'])) {
return SerializerBuilder::create()->build()->deserialize($json, $type, 'json');
}
$return = [];
foreach ($array['data'] as $data) {
$json = json_encode($data);
dump($json);
$return[] = SerializerBuilder::create()->build()->deserialize($json, $type, 'json');
}
return $return;
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Application\Controller;
use Application\Content\CockpitApi;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
class ArticleController extends MainController
{
/**
* @throws Exception
* @throws GuzzleException
*/
protected function action(): void
{
$article = (new CockpitApi())->getArticle($this->getRouteParams('id'));
$this->pushToStash('article', [
'subtitle' => $this->faker->sentence(2),
'title' => $article->getTitle(),
'lead' => $this->faker->paragraph(),
'text' => $article->getText(),
'image' => [
'src' => 'https://picsum.photos/seed/' . $this->faker->randomDigit() . '/1920/1080',
'width' => 1920,
'height' => 1080,
'alt' => 'lorem ipsum',
],
]);
}
protected function getTemplate(): string
{
return '04_templates/t-article/t-article.twig';
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace Application\Controller;
use Application\Generator\Article;
use Application\Helper\NumberHash;
use Exception;
class HomeController extends MainController
{
/**
* @throws Exception
*/
protected function action(): void
{
$this->pushToStash('articles', $this->generateArticles());
}
private function generateArticles(): array
{
$return = [];
for ($i = 0; $i < 10; $i++) {
$return[] = (new Article(NumberHash::numHash("home_$i")))->getTeaserData();
}
return $return;
}
protected function getTemplate(): string
{
return '04_templates/t-home/t-home.twig';
}
}

View File

@@ -0,0 +1,210 @@
<?php
namespace Application\Controller;
use Application\Breadcrumbs\Breadcrumbs;
use Application\Helper\ArrayPath;
use Exception;
use Twig\Environment;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Error\SyntaxError;
use Twig\Loader\FilesystemLoader;
use Faker\Factory;
use Faker\Generator;
abstract class MainController
{
/**
* Path to twig template folder.
*/
public const DIR_TEMPLATES = __DIR__ . '/../../../templates';
/**
* Path to cache folder.
*/
public const DIR_CACHE = __DIR__ . '/../../../cache';
/**
* Array key for global stash scope.
*/
private const STASH_GLOBAL = 'global';
/**
* Array key for local stash scope.
*/
private const STASH_LOCAL = 'local';
/**
* Stash. This array will be sent to twig for rendering.
*
* @var array
*/
private array $stash = array();
/**
* URL parameters obtained by routing.
*
* @var array
*/
private array $route_parameters = array();
/**
* Fake data generator.
*
* @var Generator
*/
protected Generator $faker;
/**
* Breadcrumbs.
*
* @var Breadcrumbs
*/
private Breadcrumbs $breadcrumbs;
/**
* @throws RuntimeError
* @throws SyntaxError
* @throws LoaderError
* @throws Exception
*/
public function __invoke(array $parameters = array()): void
{
$this->route_parameters = $parameters;
$this->faker = Factory::create();
$this->faker->seed(1234567);
$this->preAction();
$this->action();
$this->postAction();
$this->render();
}
/**
* @throws Exception
*/
protected function getRouteParams(string|array $params)
{
return ArrayPath::GetDataFromArray($this->route_parameters, $params);
}
protected abstract function action(): void;
protected abstract function getTemplate(): string;
/**
* @throws Exception
*/
private function preAction(): void
{
$this->headerData();
$this->menuData();
$this->breadcrumbs = new Breadcrumbs();
$this->pushToStash('foo', 'bar', self::STASH_GLOBAL);
}
/**
* @return void
* @throws Exception
*/
private function postAction(): void
{
$this->BreadcrumbsToStash();
}
/**
* @return void
* @throws Exception
*/
private function menuData(): void
{
$this->pushToStash(
'menu',
[
[
'name' => 'Home',
'url' => '/',
],
[
'name' => 'News',
'url' => '/news',
],
[
'name' => 'Artikel',
'url' => '/article',
],
],
self::STASH_GLOBAL
);
}
/**
* Create header and meta-data.
*
* @return void
* @throws Exception
*/
private function headerData(): void
{
$this->pushToStash(
'meta',
[
'title' => $this->faker->domainName(),
],
self::STASH_GLOBAL
);
}
/**
* @throws Exception
*/
protected function pushToStash(string $name, mixed $data, string $context = self::STASH_LOCAL): void
{
if (array_key_exists($context, $this->stash) and array_key_exists($name, $this->stash[$context])) {
throw new Exception("The stash variable '$name' is already set!");
}
$this->stash[$context][$name] = $data;
}
protected function getBreadcrumbs()
{
return $this->breadcrumbs;
}
/**
* @throws SyntaxError
* @throws RuntimeError
* @throws LoaderError
*/
private function render(): void
{
$twig = new Environment(
new FilesystemLoader(self::DIR_TEMPLATES),
array(
'cache' => self::DIR_CACHE . '/twig',
'auto_reload' => true,
)
);
echo $twig->render(
$this->getTemplate(),
$this->getStash()
);
}
private function getStash(): array
{
return $this->stash;
}
/**
* @throws Exception
*/
private function BreadcrumbsToStash(): void
{
$this->pushToStash('breadcrumbs', $this->getBreadcrumbs()->getTemplateData(), self::STASH_GLOBAL);
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace Application\Generator;
class Article extends WebsiteObjectGenerator
{
public function __construct(protected readonly string $seed)
{
parent::__construct($seed);
}
private function getHeadline(): string
{
return $this->getGenerator()->sentence(8);
}
private function getKicker(): string
{
return $this->getGenerator()->word();
}
private function getTeaserImage(): array
{
return (new Image($this->getSeed()))->getImage(640, 480);
}
private function getHeroImage(): array
{
return (new Image($this->getSeed()))->getImage(1920, 1080);
}
private function getExcerpt(): string
{
return implode(' ', $this->getGenerator()->sentences(5));
}
private function getUrl(): string
{
return '/article/test-' . $this->getSeed();
}
public function getTeaserData(): array
{
return [
'headline' => $this->getHeadline(),
'kicker' => $this->getKicker(),
'excerpt' => $this->getExcerpt(),
'teaserImage' => $this->getTeaserImage(),
'url' => $this->getUrl(),
];
}
public function getFullData(): array
{
return [
'headline' => $this->getHeadline(),
'kicker' => $this->getKicker(),
'excerpt' => $this->getExcerpt(),
'heroImage' => $this->getHeroImage(),
'url' => $this->getUrl(),
];
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Application\Generator;
use Application\Generator\WebsiteObjectGenerator;
class Image extends WebsiteObjectGenerator
{
public function __construct(protected readonly string $seed)
{
parent::__construct($seed);
}
public function getImage(int $width = 1280, int $height = 720): array
{
return [
'src' => 'https://picsum.photos/seed/' . $this->seed . "/$width/$height",
'width' => $width,
'height' => $height,
'alt' => $this->getGenerator()->sentence(),
];
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace Application\Generator;
use Faker\Factory;
use Faker\Generator;
class WebsiteObjectGenerator
{
/**
* @var Generator
*/
private Generator $generator;
public function __construct(private readonly string $seed)
{
$this->generator = Factory::create();
$this->getGenerator()->seed($this->seed);
}
protected function getGenerator(): Generator
{
return $this->generator;
}
protected function getSeed(): string
{
return $this->seed;
}
}

View File

@@ -0,0 +1,82 @@
<?php
namespace Application\Helper;
use Exception;
/**
* Return data from a nested array by providing a path. The parts of the path are seperated by commas.
*
* Examples: 'this.is.a.path' | 'root-node'
*/
class ArrayPath {
/**
* Return array data by given paths.
*
* Accepts no key (return all data) or a string (one specific data) or array (returns multiple data).
*
* @throws Exception|Exception
*/
public static function GetDataFromArray(array $array, mixed $key = null): mixed {
if (!$key) {
return $array;
}
if (is_string($key) and strpos($key, '.')) {
return self::getArrayDataByPath($array, $key);
}
if (is_string($key) and array_key_exists($key, $array)) {
return $array[$key];
}
if (is_array($key)) {
return self::GetMultipleData($array, $key);
}
return null;
}
/**
* Get data from a nested array by providing a path.
*
* @param string|array $data array to search the data on (haystack)
* @param string|array $path path(s) with dot-seperated parts (needle(s))
*
* @return mixed
*/
private static function getArrayDataByPath(mixed $data, string|array $path): mixed {
if (is_string($path)) {
$path = explode('.', $path);
}
if (count($path) === 0) {
return $data;
}
$key = array_shift($path);
return isset($data[$key]) ? self::getArrayDataByPath($data[$key], $path) : '';
}
/**
* Return multiple data by providing an array of desired keys and not just one as a string.
*
* @param array $data Haystack
* @param array $key Needles
*
* @return array
* @throws Exception
*/
private static function GetMultipleData(array $data, array $key): array {
$return = array();
foreach ($key as $key_value) {
$return[$key_value] = self::GetDataFromArray($data, $key_value);
}
return $return;
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace Application\Helper;
class NumberHash
{
/**
* Return a number only hash
*
* @see https://stackoverflow.com/a/23679870/175071
*
* @param string $string string to hash
* @param null|int $length optional specific length
*
* @return int
*/
public static function numHash(string $string, ?int $length = null): int
{
$stringHash = md5($string, true);
$numberHash = unpack('N2', $stringHash);
$hash = $numberHash[1] . $numberHash[2];
if ($length) {
$hash = substr($hash, 0, $length);
}
return (int)$hash;
}
}

View File

@@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
namespace Application\Models;
use JMS\Serializer\Annotation\SerializedName;
use JMS\Serializer\Annotation\Type;
class Article
{
use Meta;
#[SerializedName('authors')]
#[Type('array<' . Author::class . '>')]
protected array $authors;
#[SerializedName('headline')]
#[Type('string')]
protected string $headline;
#[SerializedName('excerpt')]
#[Type('string')]
protected string $excerpt;
#[SerializedName('image')]
#[Type(Image::class)]
protected Image $image;
#[SerializedName('text')]
#[Type('string')]
protected string $text;
/**
* Return the title / headline.
*
* @return string
*/
public function getTitle(): string {
return $this->headline;
}
/**
* Return the text / article body text.
*
* @return string
*/
public function getText(): string {
return $this->text;
}
}

View File

@@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace Application\Models;
use JMS\Serializer\Annotation\SerializedName;
use JMS\Serializer\Annotation\Type;
class Author
{
use Meta;
#[SerializedName('name')]
#[Type('string')]
private string $name;
}

View File

@@ -0,0 +1,65 @@
<?php
declare(strict_types=1);
namespace Application\Models;
use JMS\Serializer\Annotation\SerializedName;
use JMS\Serializer\Annotation\Type;
class Image
{
use Meta;
#[SerializedName('path')]
#[Type('string')]
private string $path;
#[SerializedName('title')]
#[Type('string')]
private string $title;
#[SerializedName('mime')]
#[Type('string')]
private string $mime;
#[SerializedName('type')]
#[Type('string')]
private string $type;
#[SerializedName('description')]
#[Type('string')]
private string $description;
#[SerializedName('tags')]
#[Type('array')]
private array $tags;
#[SerializedName('size')]
#[Type('string')]
private string $size;
#[SerializedName('colors')]
#[Type('array')]
private array $colors;
#[SerializedName('width')]
#[Type('string')]
private string $width;
#[SerializedName('height')]
#[Type('string')]
private string $height;
#[SerializedName('altText')]
#[Type('string')]
private string $altText;
#[SerializedName('thumbhash')]
#[Type('string')]
private string $thumbhash;
#[SerializedName('folder')]
#[Type('string')]
private string $folder;
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Application\Models;
use DateTime;
use JMS\Serializer\Annotation\SerializedName;
use JMS\Serializer\Annotation\Type;
trait Meta
{
#[SerializedName('_model')]
#[Type('string')]
private ?string $metaModel;
#[SerializedName('_state')]
#[Type('int')]
private ?int $metaState;
#[SerializedName('_modified')]
#[Type('DateTime<"U">')]
private ?DateTime $metaModified;
#[SerializedName('_mby')]
#[Type('string')]
private ?string $metaMby;
#[SerializedName('_created')]
#[Type('DateTime<"U">')]
private ?DateTime $metaCreated;
#[SerializedName('_cby')]
#[Type('string')]
private ?string $metaCby;
#[SerializedName('_id')]
#[Type('string')]
private ?string $metaId;
}

View File

@@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
namespace Application\Models;
use JMS\Serializer\Annotation\SerializedName;
use JMS\Serializer\Annotation\Type;
class Site
{
use Meta;
#[SerializedName('title')]
#[Type('string')]
private ?string $title;
public function getSiteTitle(): string
{
return $this->title;
}
}

View File

@@ -0,0 +1,75 @@
<?php
namespace Application;
use Application\Controller\HomeController;
use Application\Controller\ArticleController;
use Bramus\Router\Router as BramusRouter;
/**
* Simple router setup based on bramus/router.
*
* @link https://github.com/bramus/router
*/
class Router
{
private BramusRouter $router;
/**
* Constructor, setup router and routes
*/
public function __construct()
{
$this->setupRouter();
$this->setupRoutes();
}
/**
* Set up the router.
*
* @return void
*/
private function setupRouter(): void
{
$this->router = new BramusRouter();
$this->router->setNamespace('\Application\Controller');
}
/**
* Route-configuration will be done here.
*
* @return void
*/
private function setupRoutes(): void
{
$this->router->match('GET', '/', function () {
(new HomeController())();
});
$this->router->match('GET', '/messages', function () {
echo "<div>Lorem Ipsum Dolor</div>";
});
$this->router->match('GET', '/style.css', function () {
(new ScssCompiler())->compile();
});
$this->router->match('GET', '/debugbar/styles.css', function () {
#DebugBar::getInstance()->dumpCssAssets();
});
$this->router->match('GET', '/debugbar/javascript.js', function () {
#DebugBar::getInstance()->dumpJsAssets();
});
$this->router->match('GET', '/article/(\w+)-(\w+)', function ($name, $id) {
(new ArticleController())(['name' => $name, 'id' => $id]);
});
}
/**
* Run the routing and thus call the controllers.
*
* @return void
*/
public function serve(): void
{
$this->router->run();
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace Application;
use Application\Controller\MainController;
use ScssPhp\ScssPhp\Compiler;
use ScssPhp\ScssPhp\Exception\SassException;
use ScssPhp\ScssPhp\OutputStyle;
use ScssPhp\Server\Server;
use ScssPhp\Server\ServerException;
class ScssCompiler
{
/**
* @throws ServerException
* @throws SassException
*/
public function compile(): void
{
$scss = new Compiler();
$scss->setImportPaths(MainController::DIR_TEMPLATES);
$scss->setOutputStyle(OutputStyle::EXPANDED);
$scss->setSourceMap(Compiler::SOURCE_MAP_INLINE);
$_GET['p'] = 'main.scss';
$server = new Server(MainController::DIR_TEMPLATES, MainController::DIR_CACHE . '/scss', $scss);
$server->serve();
}
}

35
composer.json Normal file
View File

@@ -0,0 +1,35 @@
{
"name": "rauth/dnd-rules",
"description": "Dungeons and Dragons rules exporter",
"minimum-stability": "stable",
"license": "proprietary",
"authors": [
{
"name": "Adrian Rauth",
"email": "adrian@rauth.org"
}
],
"config": {
"vendor-dir": "classes/external/",
"allow-plugins": {
"pestphp/pest-plugin": true
}
},
"require": {
"php": "^8.1",
"guzzlehttp/guzzle": "^7",
"twig/twig": "^3.8",
"bramus/router": "^1.6",
"scssphp/scssphp": "^1.12",
"scssphp/server": "^1.10",
"tracy/tracy": "^2.10",
"fakerphp/faker": "^1.23",
"vlucas/phpdotenv": "^5.6",
"jms/serializer": "^3.30"
},
"autoload": {
"psr-0": {
"Application": "classes/"
}
}
}

1864
composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

15
docker-compose.yml Normal file
View File

@@ -0,0 +1,15 @@
version: "3"
services:
php:
image: webdevops/php-apache-dev:8.3
working_dir: /app
environment:
- WEB_DOCUMENT_ROOT=/app/public
ports:
- "80:80"
expose:
- "80"
volumes:
- ./:/app:rw,cached

7
public/.htaccess Normal file
View File

@@ -0,0 +1,7 @@
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-l
RewriteRule ^(.*)$ index.php/$1
</IfModule>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

13
public/index.php Normal file
View File

@@ -0,0 +1,13 @@
<?php
error_reporting(E_ALL);
ini_set("display_errors", 1);
require('../classes/external/autoload.php');
use Application\Router;
use Tracy\Debugger;
Debugger::enable(Debugger::Development);
(new Router())->serve();

1
public/js/htmx.min.js vendored Normal file

File diff suppressed because one or more lines are too long

0
readme.md Normal file
View File

View File

@@ -0,0 +1,13 @@
@import "misc/reset";
@import "misc/variables";
@import "fonts/badscript";
@import "fonts/opensans";
@import "fonts/source-sans";
@import "fonts/source-serif";
html, body {
background-color: $color4;
font-family: "Source Serif 4", sans-serif;
font-size: 1.2rem;
box-sizing: border-box;
}

View File

@@ -0,0 +1,8 @@
/* bad-script-regular - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Bad Script';
font-style: normal;
font-weight: 400;
src: url('/fonts/badscript/bad-script-v16-latin-regular.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}

View File

@@ -0,0 +1,107 @@
/* open-sans-300 - latin */
@font-face {
font-display: swap;
font-family: 'Open Sans';
font-style: normal;
font-weight: 300;
src: url('/fonts/opensans/open-sans-v40-latin-300.woff2') format('woff2');
}
/* open-sans-300italic - latin */
@font-face {
font-display: swap;
font-family: 'Open Sans';
font-style: italic;
font-weight: 300;
src: url('/fonts/opensans/open-sans-v40-latin-300italic.woff2') format('woff2');
}
/* open-sans-regular - latin */
@font-face {
font-display: swap;
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
src: url('/fonts/opensans/open-sans-v40-latin-regular.woff2') format('woff2');
}
/* open-sans-italic - latin */
@font-face {
font-display: swap;
font-family: 'Open Sans';
font-style: italic;
font-weight: 400;
src: url('/fonts/opensans/open-sans-v40-latin-italic.woff2') format('woff2');
}
/* open-sans-500 - latin */
@font-face {
font-display: swap;
font-family: 'Open Sans';
font-style: normal;
font-weight: 500;
src: url('/fonts/opensans/open-sans-v40-latin-500.woff2') format('woff2');
}
/* open-sans-500italic - latin */
@font-face {
font-display: swap;
font-family: 'Open Sans';
font-style: italic;
font-weight: 500;
src: url('/fonts/opensans/open-sans-v40-latin-500italic.woff2') format('woff2');
}
/* open-sans-600 - latin */
@font-face {
font-display: swap;
font-family: 'Open Sans';
font-style: normal;
font-weight: 600;
src: url('/fonts/opensans/open-sans-v40-latin-600.woff2') format('woff2');
}
/* open-sans-600italic - latin */
@font-face {
font-display: swap;
font-family: 'Open Sans';
font-style: italic;
font-weight: 600;
src: url('/fonts/opensans/open-sans-v40-latin-600italic.woff2') format('woff2');
}
/* open-sans-700 - latin */
@font-face {
font-display: swap;
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
src: url('/fonts/opensans/open-sans-v40-latin-700.woff2') format('woff2');
}
/* open-sans-700italic - latin */
@font-face {
font-display: swap;
font-family: 'Open Sans';
font-style: italic;
font-weight: 700;
src: url('/fonts/opensans/open-sans-v40-latin-700italic.woff2') format('woff2');
}
/* open-sans-800 - latin */
@font-face {
font-display: swap;
font-family: 'Open Sans';
font-style: normal;
font-weight: 800;
src: url('/fonts/opensans/open-sans-v40-latin-800.woff2') format('woff2');
}
/* open-sans-800italic - latin */
@font-face {
font-display: swap;
font-family: 'Open Sans';
font-style: italic;
font-weight: 800;
src: url('/fonts/opensans/open-sans-v40-latin-800italic.woff2') format('woff2');
}

View File

@@ -0,0 +1,143 @@
/* source-sans-3-200 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Sans 3';
font-style: normal;
font-weight: 200;
src: url('/fonts/source_sans/source-sans-3-v15-latin-200.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-sans-3-200italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Sans 3';
font-style: italic;
font-weight: 200;
src: url('/fonts/source_sans/source-sans-3-v15-latin-200italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-sans-3-300 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Sans 3';
font-style: normal;
font-weight: 300;
src: url('/fonts/source_sans/source-sans-3-v15-latin-300.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-sans-3-300italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Sans 3';
font-style: italic;
font-weight: 300;
src: url('/fonts/source_sans/source-sans-3-v15-latin-300italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-sans-3-regular - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Sans 3';
font-style: normal;
font-weight: 400;
src: url('/fonts/source_sans/source-sans-3-v15-latin-regular.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-sans-3-italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Sans 3';
font-style: italic;
font-weight: 400;
src: url('/fonts/source_sans/source-sans-3-v15-latin-italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-sans-3-500 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Sans 3';
font-style: normal;
font-weight: 500;
src: url('/fonts/source_sans/source-sans-3-v15-latin-500.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-sans-3-500italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Sans 3';
font-style: italic;
font-weight: 500;
src: url('/fonts/source_sans/source-sans-3-v15-latin-500italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-sans-3-600 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Sans 3';
font-style: normal;
font-weight: 600;
src: url('/fonts/source_sans/source-sans-3-v15-latin-600.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-sans-3-600italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Sans 3';
font-style: italic;
font-weight: 600;
src: url('/fonts/source_sans/source-sans-3-v15-latin-600italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-sans-3-700 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Sans 3';
font-style: normal;
font-weight: 700;
src: url('/fonts/source_sans/source-sans-3-v15-latin-700.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-sans-3-700italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Sans 3';
font-style: italic;
font-weight: 700;
src: url('/fonts/source_sans/source-sans-3-v15-latin-700italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-sans-3-800 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Sans 3';
font-style: normal;
font-weight: 800;
src: url('/fonts/source_sans/source-sans-3-v15-latin-800.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-sans-3-800italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Sans 3';
font-style: italic;
font-weight: 800;
src: url('/fonts/source_sans/source-sans-3-v15-latin-800italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-sans-3-900 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Sans 3';
font-style: normal;
font-weight: 900;
src: url('/fonts/source_sans/source-sans-3-v15-latin-900.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-sans-3-900italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Sans 3';
font-style: italic;
font-weight: 900;
src: url('/fonts/source_sans/source-sans-3-v15-latin-900italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}

View File

@@ -0,0 +1,143 @@
/* source-serif-4-200 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Serif 4';
font-style: normal;
font-weight: 200;
src: url('/fonts/source_serif/source-serif-4-v8-latin-200.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-serif-4-200italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Serif 4';
font-style: italic;
font-weight: 200;
src: url('/fonts/source_serif/source-serif-4-v8-latin-200italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-serif-4-300 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Serif 4';
font-style: normal;
font-weight: 300;
src: url('/fonts/source_serif/source-serif-4-v8-latin-300.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-serif-4-300italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Serif 4';
font-style: italic;
font-weight: 300;
src: url('/fonts/source_serif/source-serif-4-v8-latin-300italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-serif-4-regular - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Serif 4';
font-style: normal;
font-weight: 400;
src: url('/fonts/source_serif/source-serif-4-v8-latin-regular.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-serif-4-italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Serif 4';
font-style: italic;
font-weight: 400;
src: url('/fonts/source_serif/source-serif-4-v8-latin-italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-serif-4-500 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Serif 4';
font-style: normal;
font-weight: 500;
src: url('/fonts/source_serif/source-serif-4-v8-latin-500.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-serif-4-500italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Serif 4';
font-style: italic;
font-weight: 500;
src: url('/fonts/source_serif/source-serif-4-v8-latin-500italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-serif-4-600 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Serif 4';
font-style: normal;
font-weight: 600;
src: url('/fonts/source_serif/source-serif-4-v8-latin-600.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-serif-4-600italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Serif 4';
font-style: italic;
font-weight: 600;
src: url('/fonts/source_serif/source-serif-4-v8-latin-600italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-serif-4-700 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Serif 4';
font-style: normal;
font-weight: 700;
src: url('/fonts/source_serif/source-serif-4-v8-latin-700.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-serif-4-700italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Serif 4';
font-style: italic;
font-weight: 700;
src: url('/fonts/source_serif/source-serif-4-v8-latin-700italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-serif-4-800 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Serif 4';
font-style: normal;
font-weight: 800;
src: url('/fonts/source_serif/source-serif-4-v8-latin-800.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-serif-4-800italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Serif 4';
font-style: italic;
font-weight: 800;
src: url('/fonts/source_serif/source-serif-4-v8-latin-800italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-serif-4-900 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Serif 4';
font-style: normal;
font-weight: 900;
src: url('/fonts/source_serif/source-serif-4-v8-latin-900.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* source-serif-4-900italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Source Serif 4';
font-style: italic;
font-weight: 900;
src: url('/fonts/source_serif/source-serif-4-v8-latin-900italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}

View File

@@ -0,0 +1,15 @@
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M5 5H19V19H16L16 8H5V5Z" fill="currentColor" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M10 19C12.7614 19 15 16.7614 15 14C15 11.2386 12.7614 9 10 9C7.23858 9 5 11.2386 5 14C5 16.7614 7.23858 19 10 19ZM10 16C11.1046 16 12 15.1046 12 14C12 12.8954 11.1046 12 10 12C8.89543 12 8 12.8954 8 14C8 15.1046 8.89543 16 10 16Z"
fill="currentColor"
/>
</svg>

After

Width:  |  Height:  |  Size: 495 B

View File

@@ -0,0 +1,18 @@
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 6C12.5523 6 13 6.44772 13 7V11H17C17.5523 11 18 11.4477 18 12C18 12.5523 17.5523 13 17 13H13V17C13 17.5523 12.5523 18 12 18C11.4477 18 11 17.5523 11 17V13H7C6.44772 13 6 12.5523 6 12C6 11.4477 6.44772 11 7 11H11V7C11 6.44772 11.4477 6 12 6Z"
fill="currentColor"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M5 22C3.34315 22 2 20.6569 2 19V5C2 3.34315 3.34315 2 5 2H19C20.6569 2 22 3.34315 22 5V19C22 20.6569 20.6569 22 19 22H5ZM4 19C4 19.5523 4.44772 20 5 20H19C19.5523 20 20 19.5523 20 19V5C20 4.44772 19.5523 4 19 4H5C4.44772 4 4 4.44772 4 5V19Z"
fill="currentColor"
/>
</svg>

After

Width:  |  Height:  |  Size: 738 B

View File

@@ -0,0 +1,20 @@
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12ZM12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4Z"
fill="currentColor"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M13 7C13 6.44772 12.5523 6 12 6C11.4477 6 11 6.44772 11 7V11H7C6.44772 11 6 11.4477 6 12C6 12.5523 6.44772 13 7 13H11V17C11 17.5523 11.4477 18 12 18C12.5523 18 13 17.5523 13 17V13H17C17.5523 13 18 12.5523 18 12C18 11.4477 17.5523 11 17 11H13V7Z"
fill="currentColor"
/>
</svg>

After

Width:  |  Height:  |  Size: 770 B

View File

@@ -0,0 +1,20 @@
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1.3294 19L0.731323 17.9641L5.06145 15.4641L7.1029 19H1.3294Z"
fill="currentColor"
/>
<path
d="M15.1858 19H9.4123L5.7935 12.7321L10.1236 10.2321L15.1858 19Z"
fill="currentColor"
/>
<path
d="M23.2687 19H17.4952L10.8557 7.5L15.1858 5L23.2687 19Z"
fill="currentColor"
/>
</svg>

After

Width:  |  Height:  |  Size: 427 B

View File

@@ -0,0 +1,12 @@
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9.00967 5.12761H11.0097C12.1142 5.12761 13.468 5.89682 14.0335 6.8457L16.5089 11H21.0097C21.562 11 22.0097 11.4477 22.0097 12C22.0097 12.5523 21.562 13 21.0097 13H16.4138L13.9383 17.1543C13.3729 18.1032 12.0191 18.8724 10.9145 18.8724H8.91454L12.4138 13H5.42485L3.99036 15.4529H1.99036L4.00967 12L4.00967 11.967L2.00967 8.54712H4.00967L5.44417 11H12.5089L9.00967 5.12761Z"
fill="currentColor"
/>
</svg>

After

Width:  |  Height:  |  Size: 531 B

View File

@@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.45887 2L1 6.01478L2.33826 7.50107L6.79713 3.48629L5.45887 2Z" fill="currentColor"/>
<path d="M11 8H13V12H16V14H11V8Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12ZM5 12C5 8.13401 8.13401 5 12 5C15.866 5 19 8.13401 19 12C19 15.866 15.866 19 12 19C8.13401 19 5 15.866 5 12Z" fill="currentColor"/>
<path d="M18.5411 2L23 6.01478L21.6617 7.50107L17.2029 3.48629L18.5411 2Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 644 B

View File

@@ -0,0 +1,14 @@
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M2 19C2 20.6569 3.34315 22 5 22H19C20.6569 22 22 20.6569 22 19V5C22 3.34315 20.6569 2 19 2H5C3.34315 2 2 3.34315 2 5V19ZM20 19C20 19.5523 19.5523 20 19 20H5C4.44772 20 4 19.5523 4 19V5C4 4.44772 4.44772 4 5 4H10V12.0111L12.395 12.0112L14.0001 9.86419L15.6051 12.0112H18.0001L18 4H19C19.5523 4 20 4.44772 20 5V19ZM16 4H12V9.33585L14.0001 6.66046L16 9.33571V4Z"
fill="currentColor"
/>
</svg>

After

Width:  |  Height:  |  Size: 566 B

Some files were not shown because too many files have changed in this diff Show More