commit 46fffeb46e9bde54418efce5bd41bf1725a82103 Author: Dale Davies Date: Fri Feb 4 09:53:55 2022 +0000 Let there be code! diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..447b0d5 --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +*/vendor \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cef9de1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*/vendor +docker-compose.yaml \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ac86c97 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,28 @@ +# Start with the official composer image, copy application files and install +# dependencies. +FROM composer AS composer +COPY web/ /app +RUN composer install --no-dev \ + --optimize-autoloader \ + --no-interaction \ + --no-progress + +# Switch to trafex/php-nginx image and copy application files into it. +FROM trafex/php-nginx +COPY --chown=nginx --from=composer /app /var/www/html + +# The trafex/php-nginx image runs as "nobody" user so we need to switch to root +# so we can make changes inside the container. +USER root + +# We need the following PHP extensions. +RUN apk add php8-fileinfo + +# Create the cache directories. +RUN mkdir -p /var/www/cache/application \ + && chown nobody:nobody /var/www/cache/application \ + && mkdir -p /var/www/cache/icons \ + && chown nobody:nobody /var/www/cache/icons + +# Switch back to the nobody user so we're not running as root forever. +USER nobody \ No newline at end of file diff --git a/web/assets/backgrounds/animal-g3298dcb04_1920.jpg b/web/assets/backgrounds/animal-g3298dcb04_1920.jpg new file mode 100644 index 0000000..9219cd9 Binary files /dev/null and b/web/assets/backgrounds/animal-g3298dcb04_1920.jpg differ diff --git a/web/assets/backgrounds/budapest-g056b86516_1920.jpg b/web/assets/backgrounds/budapest-g056b86516_1920.jpg new file mode 100644 index 0000000..4d32e01 Binary files /dev/null and b/web/assets/backgrounds/budapest-g056b86516_1920.jpg differ diff --git a/web/assets/backgrounds/building-gad730b330_1920.jpg b/web/assets/backgrounds/building-gad730b330_1920.jpg new file mode 100644 index 0000000..75676e9 Binary files /dev/null and b/web/assets/backgrounds/building-gad730b330_1920.jpg differ diff --git a/web/assets/backgrounds/nature-gbde25f3ce_1920.jpg b/web/assets/backgrounds/nature-gbde25f3ce_1920.jpg new file mode 100644 index 0000000..04b37da Binary files /dev/null and b/web/assets/backgrounds/nature-gbde25f3ce_1920.jpg differ diff --git a/web/assets/backgrounds/san-francisco-g1a7f2aef8_1920.jpg b/web/assets/backgrounds/san-francisco-g1a7f2aef8_1920.jpg new file mode 100644 index 0000000..085dbd8 Binary files /dev/null and b/web/assets/backgrounds/san-francisco-g1a7f2aef8_1920.jpg differ diff --git a/web/assets/backgrounds/sea-ga4cb2ef0b_1920.jpg b/web/assets/backgrounds/sea-ga4cb2ef0b_1920.jpg new file mode 100644 index 0000000..e4bb7bb Binary files /dev/null and b/web/assets/backgrounds/sea-ga4cb2ef0b_1920.jpg differ diff --git a/web/assets/backgrounds/seagull-gc0701fe2f_1920.jpg b/web/assets/backgrounds/seagull-gc0701fe2f_1920.jpg new file mode 100644 index 0000000..7b8e90e Binary files /dev/null and b/web/assets/backgrounds/seagull-gc0701fe2f_1920.jpg differ diff --git a/web/assets/css/styles.css b/web/assets/css/styles.css new file mode 100644 index 0000000..122767f --- /dev/null +++ b/web/assets/css/styles.css @@ -0,0 +1,100 @@ +* { + box-sizing: border-box; +} + +body { + margin: 0; + padding: 0; + color: #fff; + font-family: -apple-system,system-ui,Ubuntu,Roboto,"Open Sans","Segoe UI","Helvetica Neue"; + font-size: 1em; + text-align: center; + background: #000; +} + +.fixed { + position: fixed; + top: 0; + right: 0; + left: 0; + bottom: 0; +} + +.background { + filter: brightness(0.55) blur(13px); + background-repeat: no-repeat; + background-size: cover; + background-position: center center; + transform: scale(1.07); + z-index: 1; +} + +body::after { + content: ''; + position:fixed; + top: 0; + left: 0; + right:0; + bottom:0; + background-image: url(../images/overlay.png); + opacity: 0.6; + z-index: 2; +} +.content { + z-index: 10; + display: flex; + flex-direction: column; + justify-content:center; +} + +.greeting { + font-size: 2.5em; + text-transform: capitalize; + text-shadow: 1px 2px 14px #000000; + margin-bottom: 30px; +} + +.sites, .sites li { + padding: 0; + margin: 0; + list-style-type: none; + font-weight: 300; + font-size: 14px; +} + .sites li { + display: inline-block; + margin-bottom:20px; + } + .sites li a { + color: inherit; + text-decoration: none; + } + + .sites .icon { + display: block; + background-color: #fff; + width: 75px; + height: 75px; + border-radius: 10px; + border: .2em solid #fff; + box-shadow: 0 1px 5px rgba(0,0,0,.3); + margin: 0 11px 7px 11px; + padding: 15px; + } + .sites .icon:hover { + border-color: #007aff; + transition: border-color .1s; + } + + .sites .icon img { + width:100%; + } + + .sites .name { + display: block; + width: 100%; + max-height: 3.3em; + overflow: hidden; + word-wrap: break-word; + text-shadow: 1px 1px 2px #000000 + } \ No newline at end of file diff --git a/web/assets/images/default-icon.png b/web/assets/images/default-icon.png new file mode 100644 index 0000000..ce3443a Binary files /dev/null and b/web/assets/images/default-icon.png differ diff --git a/web/assets/images/overlay.png b/web/assets/images/overlay.png new file mode 100644 index 0000000..4c0763c Binary files /dev/null and b/web/assets/images/overlay.png differ diff --git a/web/assets/js/index.js b/web/assets/js/index.js new file mode 100644 index 0000000..7bed246 --- /dev/null +++ b/web/assets/js/index.js @@ -0,0 +1 @@ +console.log('yay'); \ No newline at end of file diff --git a/web/background-css.php b/web/background-css.php new file mode 100644 index 0000000..76dd951 --- /dev/null +++ b/web/background-css.php @@ -0,0 +1,11 @@ +get_random_background_file(); +$backgroundgradient = 'linear-gradient(to bottom, #FC466B40, #425df530)'; + +header('Content-Type: text/css'); +echo '.background {background-image: '.$backgroundgradient.', url("'.$backgroundfile.'");}'; \ No newline at end of file diff --git a/web/classes/Background.php b/web/classes/Background.php new file mode 100644 index 0000000..8f3f41c --- /dev/null +++ b/web/classes/Background.php @@ -0,0 +1,26 @@ +config = $config; + $this->backgroundsdirectory = $config->get('backgroundsdir'); + $this->webaccessibledir = str_replace($config->get('wwwroot'), '', $config->get('backgroundsdir')); + $this->enumerate_files(); + } + + private function enumerate_files(): void { + $this->backgroundfiles = array_diff(scandir($this->backgroundsdirectory), array('..', '.')); + } + + public function get_random_background_file(bool $includepath = true): string { + return ($includepath ? $this->webaccessibledir : '') + . '/'. $this->backgroundfiles[array_rand($this->backgroundfiles)]; + } + +} diff --git a/web/classes/Cache.php b/web/classes/Cache.php new file mode 100644 index 0000000..d6641c5 --- /dev/null +++ b/web/classes/Cache.php @@ -0,0 +1,77 @@ +config = $config; + // Define the various caches used throughout the app. + $this->caches = [ + 'sites' => [ + 'cache' => null, + 'expirationtype' => Caching\Cache::FILES, + 'expirationparams' => $config->get('sitesfile') + ], + 'templates/sites' => [ + 'cache' => null, + 'expirationtype' => Caching\Cache::FILES, + 'expirationparams' => [ + __DIR__.'/../config.php', + $config->get('sitesfile'), + $config->get('templatedir').'/sites.mustache' + ] + ] + ]; + // Inititalise file storage for cache using cachedir path from config. + $this->storage = new Caching\Storages\FileStorage($this->config->get('cachedir').'/application'); + // Initialise a cache object for each cache name/type specified in caches array. + array_walk($this->caches, function(&$cachedef, $cachename) { + $cachedef['cache'] = new Caching\Cache($this->storage, $cachename); + }); + } + + /** + * Read the specified item from the cache or generate it, mostly a wrapper + * around Nette\Caching\Cache::load(). + * + * @param string $cachename The name of a cache type, must match a key in $caches definition. + * @param callable $callback The code from which the result should be stored in cache. + * @return mixed The result of callback function retreieved from cache. + */ + public function load(string $cachename, callable $callback): mixed { + // If cachebypass has been set in config.php then just execute the callback. + if ($this->config->parse_bool($this->config->get('cachebypass'))) { + return $callback(); + } + // We can only work with caches that have already been defined. + if (!array_key_exists($cachename, $this->caches)) { + throw new \Exception('Cache name not found ('.$cachename.')'); + } + // Retrieve the initialised cache object from $caches, defines the caches expiry + // and executes the callback. + return $this->caches[$cachename]['cache']->load($cachename, + function (&$dependencies) use ($callback, $cachename) { + $dependencies[$this->caches[$cachename]['expirationtype']] = $this->caches[$cachename]['expirationparams']; + return $callback(); + } + ); + } + +} diff --git a/web/classes/Config.php b/web/classes/Config.php new file mode 100644 index 0000000..2e77013 --- /dev/null +++ b/web/classes/Config.php @@ -0,0 +1,92 @@ + '/assets/backgrounds', + 'sitesfile' => '/sites/sites.json', + 'templatedir' => '/templates', + ]; + + /** + * Configurable params we do expect to find in config.php + */ + private const CONFIG_PARAMS = [ + 'sitename', + 'wwwroot', + 'cachebypass', + 'cachedir', + 'noindex', + ]; + + public function __construct() { + $this->config = new \PHLAK\Config\Config(__DIR__.'/../config.php'); + $this->add_wwwroot_to_base_paths(); + if ($this->config_params_missing()) { + throw new Exception('Config.php must always contain... '.implode(', ', self::CONFIG_PARAMS)); + } + } + + /** + * Prefixes the wwwroot string from config.php to the base application paths + * so they can be located in the file system correctly. + * + * @return void + */ + private function add_wwwroot_to_base_paths(): void { + $wwwroot = $this->config->get('wwwroot'); + foreach(self::BASE_APPLICATION_PATHS as $key => $value) { + $this->config->set($key, $wwwroot.$value); + } + } + + /** + * Determine if any configuration params are missing in the list loaded + * from the config.php. + * + * @return boolean + */ + private function config_params_missing(): bool { + return !!array_diff( + array_keys($this->config->toArray()), + array_merge( + array_keys(self::BASE_APPLICATION_PATHS), + self::CONFIG_PARAMS + )); + } + + /** + * Retrieves the config parameter provided in $key, first checks for its + * existence. + * + * @param string $key The config parameter required. + * @return mixed The selected value from the configuration array. + */ + public function get(string $key): mixed { + if (!$this->config->has($key)) { + throw new Exception('Config key does not exist... ('.$key.')'); + } + return $this->config->get($key); + } + + /** + * Attempt to converts a string to a boolean correctly, will return the parsed boolean + * or null on failure. + * + * @param mixed $input A string representing a boolean value... "true", "yes", "no", "false" etc. + * @return mixed Returns a proper boolean or null on failure. + */ + public function parse_bool(mixed $input): mixed { + return filter_var($input,FILTER_VALIDATE_BOOLEAN,FILTER_NULL_ON_FAILURE); + } + +} diff --git a/web/classes/Greeting.php b/web/classes/Greeting.php new file mode 100644 index 0000000..e4805f7 --- /dev/null +++ b/web/classes/Greeting.php @@ -0,0 +1,25 @@ +greetings = [ + 03 => 'morning', + 12 => 'afternoon', + 16 => 'evening', + 19 => 'night' + ]; + } + + public function get_greeting(): string { + krsort($this->greetings); + foreach ($this->greetings as $key => $value) { + if (date('H', time()) >= $key) { + return $value; + } + } + } +} \ No newline at end of file diff --git a/web/classes/Main.php b/web/classes/Main.php new file mode 100644 index 0000000..e46a45e --- /dev/null +++ b/web/classes/Main.php @@ -0,0 +1,66 @@ +config = new Config(); + $this->greeting = new Greeting(); + $this->mustache = new \Mustache_Engine([ + 'loader' => new \Mustache_Loader_FilesystemLoader($this->config->get('templatedir')) + ]); + $this->cache = new Cache($this->config); + $this->sites = new Sites($this->config, $this->cache); + } + + private function render_header(): string { + $template = $this->mustache->loadTemplate('header'); + return $template->render([ + 'noindex' => $this->config->parse_bool($this->config->get('noindex')), + 'sitename' => $this->config->get('sitename'), + ]); + } + + private function render_greeting(): string { + $template = $this->mustache->loadTemplate('greeting'); + return $template->render([ + 'greeting' => $this->greeting->get_greeting(), + ]); + } + + private function render_sites(): string { + return $this->cache->load('templates/sites', function() { + $template = $this->mustache->loadTemplate('sites'); + return $template->render([ + 'hassites' => !empty($this->sites->get_sites()), + 'sites' => $this->sites->get_sites() + ]); + }); + } + + private function render_footer(): string { + $template = $this->mustache->loadTemplate('footer'); + return $template->render(); + } + + public function build_index_page(): void { + $this->outputarray = [ + $this->render_header(), + $this->render_greeting(), + $this->render_sites(), + $this->render_footer(), + ]; + } + + public function get_output(): string { + return implode('', $this->outputarray); + } + +} diff --git a/web/classes/Site.php b/web/classes/Site.php new file mode 100644 index 0000000..63bc0b0 --- /dev/null +++ b/web/classes/Site.php @@ -0,0 +1,40 @@ +name = $sitearray['name']; + $this->url = $sitearray['url']; + $this->nofollow = isset($sitearray['nofollow']) ? $sitearray['nofollow'] : false; + $this->icon = isset($sitearray['icon']) ? $this->get_favicon_datauri($sitearray['icon']) : $this->get_favicon_datauri(); + } + + public function get_favicon_datauri(?string $icon = null): string { + if ($icon === null) { + $favicon = new \Favicon\Favicon(); + $favicon->cache([ + 'dir' => '/var/www/cache/icons/', + 'timeout' => 86400 + ]); + $rawimage = $favicon->get($this->url, \Favicon\FaviconDLType::RAW_IMAGE); + if (!$rawimage) { + $rawimage = file_get_contents(__DIR__ . '/../assets/images/default-icon.png'); + } + } else { + $rawimage = file_get_contents(__DIR__ . '/../sites/icons/'.$icon); + } + $mimetype = (new \finfo(FILEINFO_MIME_TYPE))->buffer($rawimage); + return 'data:'.$mimetype.';base64,'.base64_encode($rawimage); + } + +} \ No newline at end of file diff --git a/web/classes/Sites.php b/web/classes/Sites.php new file mode 100644 index 0000000..41f769f --- /dev/null +++ b/web/classes/Sites.php @@ -0,0 +1,82 @@ +config = $config; + $this->loadedsites = []; + $this->sitesfilelocation = $this->config->get('sitesfile'); + $this->cache = $cache; + $this->load_sites_from_json(); + } + + /** + * Try to load the list of sites from site.json. + * + * Throws an exception if the file cannot be loaded, is empty, or cannot + * be decoded to an array, + * + * @return void + * @throws Exception if sites.json cannot be found + */ + private function load_sites_from_json(): void { + $this->loadedsites = $this->cache->load('sites', function() { + $sites = []; + $rawjson = file_get_contents($this->sitesfilelocation); + if ($rawjson === false) { + throw new Exception('There was a problem loading the sites.json file'); + } + if ($rawjson === '') { + throw new Exception('The sites.json file is empty'); + } + $decodedjson = json_decode($rawjson, true); + if (!is_array($decodedjson)) { + throw new Exception('Provided sites json does not contain a top-level array'); + } + foreach ($decodedjson as $array) { + $sites[] = new Site($array); + } + return $sites; + }); + } + + /** + * Return the loaded sites. + * + * @return array of sites loaded from sites.json + */ + public function get_sites(): array { + return $this->loadedsites; + } + + /** + * Given a URL, does that site exist in our list of sites? + * + * @param string $url The URL to search for. + * @return Site|null + */ + public function get_site_by_url(string $url): Site { + $found = array_search($url, array_column($this->get_sites(), 'url')); + if (!$found) { + throw new Exception('The site could not be found ('.$url.')'); + } + return $this->loadedsites[$found]; + } +} \ No newline at end of file diff --git a/web/composer.json b/web/composer.json new file mode 100644 index 0000000..a4eb9f2 --- /dev/null +++ b/web/composer.json @@ -0,0 +1,16 @@ +{ + "name": "daledavies/jump", + "description": "A startpage for stuff", + "type": "project", + "autoload": { + "psr-4": { + "Jump\\": "classes/" + } + }, + "require": { + "mustache/mustache": "~2.5", + "arthurhoaro/favicon": "~1.0", + "nette/caching": "^3.1", + "phlak/config": "^7.0" + } +} diff --git a/web/composer.lock b/web/composer.lock new file mode 100644 index 0000000..85755ed --- /dev/null +++ b/web/composer.lock @@ -0,0 +1,647 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "content-hash": "7ea3804d37d3b0050903f4604d6a82ab", + "packages": [ + { + "name": "arthurhoaro/favicon", + "version": "v1.3.3", + "source": { + "type": "git", + "url": "https://github.com/ArthurHoaro/favicon.git", + "reference": "b1acd8b87d6b37e5251fe0559ed488a95078f5b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ArthurHoaro/favicon/zipball/b1acd8b87d6b37e5251fe0559ed488a95078f5b9", + "reference": "b1acd8b87d6b37e5251fe0559ed488a95078f5b9", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-fileinfo": "*", + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "~4.8", + "squizlabs/php_codesniffer": "^3.5", + "weew/helpers-filesystem": "~1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Favicon\\": "src/Favicon/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Chris Shiflett", + "homepage": "http://shiflett.org/" + }, + { + "name": "Arthur Hoaro", + "homepage": "http://hoa.ro" + } + ], + "description": "PHP Library used to discover favicon from given URL", + "homepage": "https://github.com/ArthurHoaro/favicon", + "keywords": [ + "favicon", + "finder", + "icon" + ], + "time": "2021-08-06T05:41:25+00:00" + }, + { + "name": "mustache/mustache", + "version": "v2.14.1", + "source": { + "type": "git", + "url": "https://github.com/bobthecow/mustache.php.git", + "reference": "579ffa5c96e1d292c060b3dd62811ff01ad8c24e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bobthecow/mustache.php/zipball/579ffa5c96e1d292c060b3dd62811ff01ad8c24e", + "reference": "579ffa5c96e1d292c060b3dd62811ff01ad8c24e", + "shasum": "" + }, + "require": { + "php": ">=5.2.4" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~1.11", + "phpunit/phpunit": "~3.7|~4.0|~5.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "Mustache": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Justin Hileman", + "email": "justin@justinhileman.info", + "homepage": "http://justinhileman.com" + } + ], + "description": "A Mustache implementation in PHP.", + "homepage": "https://github.com/bobthecow/mustache.php", + "keywords": [ + "mustache", + "templating" + ], + "time": "2022-01-21T06:08:36+00:00" + }, + { + "name": "nette/caching", + "version": "v3.1.2", + "source": { + "type": "git", + "url": "https://github.com/nette/caching.git", + "reference": "27d8f0048eb1a9c7e49e0268f39b2db7d3ce7ae9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/caching/zipball/27d8f0048eb1a9c7e49e0268f39b2db7d3ce7ae9", + "reference": "27d8f0048eb1a9c7e49e0268f39b2db7d3ce7ae9", + "shasum": "" + }, + "require": { + "nette/finder": "^2.4 || ^3.0", + "nette/utils": "^2.4 || ^3.0", + "php": ">=7.2 <8.2" + }, + "require-dev": { + "latte/latte": "^2.10", + "nette/di": "^v3.0", + "nette/tester": "^2.0", + "phpstan/phpstan": "^0.12", + "tracy/tracy": "^2.4" + }, + "suggest": { + "ext-pdo_sqlite": "to use SQLiteStorage or SQLiteJournal" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "⏱ Nette Caching: library with easy-to-use API and many cache backends.", + "homepage": "https://nette.org", + "keywords": [ + "cache", + "journal", + "memcached", + "nette", + "sqlite" + ], + "time": "2021-08-24T23:45:03+00:00" + }, + { + "name": "nette/finder", + "version": "v2.5.3", + "source": { + "type": "git", + "url": "https://github.com/nette/finder.git", + "reference": "64dc25b7929b731e72a1bc84a9e57727f5d5d3e8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/finder/zipball/64dc25b7929b731e72a1bc84a9e57727f5d5d3e8", + "reference": "64dc25b7929b731e72a1bc84a9e57727f5d5d3e8", + "shasum": "" + }, + "require": { + "nette/utils": "^2.4 || ^3.0", + "php": ">=7.1" + }, + "conflict": { + "nette/nette": "<2.2" + }, + "require-dev": { + "nette/tester": "^2.0", + "phpstan/phpstan": "^0.12", + "tracy/tracy": "^2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.5-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🔍 Nette Finder: find files and directories with an intuitive API.", + "homepage": "https://nette.org", + "keywords": [ + "filesystem", + "glob", + "iterator", + "nette" + ], + "time": "2021-12-12T17:43:24+00:00" + }, + { + "name": "nette/utils", + "version": "v3.2.7", + "source": { + "type": "git", + "url": "https://github.com/nette/utils.git", + "reference": "0af4e3de4df9f1543534beab255ccf459e7a2c99" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/utils/zipball/0af4e3de4df9f1543534beab255ccf459e7a2c99", + "reference": "0af4e3de4df9f1543534beab255ccf459e7a2c99", + "shasum": "" + }, + "require": { + "php": ">=7.2 <8.2" + }, + "conflict": { + "nette/di": "<3.0.6" + }, + "require-dev": { + "nette/tester": "~2.0", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.3" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()", + "ext-xml": "to use Strings::length() etc. when mbstring is not available" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "homepage": "https://nette.org", + "keywords": [ + "array", + "core", + "datetime", + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" + ], + "time": "2022-01-24T11:29:14+00:00" + }, + { + "name": "phlak/config", + "version": "7.0.0", + "source": { + "type": "git", + "url": "https://github.com/PHLAK/Config.git", + "reference": "a67af04eef18eabfad06442c86ddf692ca5bab0e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHLAK/Config/zipball/a67af04eef18eabfad06442c86ddf692ca5bab0e", + "reference": "a67af04eef18eabfad06442c86ddf692ca5bab0e", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "symfony/yaml": "^3.0 || ^4.0 || ^5.0", + "yosymfony/toml": "^1.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.16.1", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "psy/psysh": "^0.10", + "vimeo/psalm": "^3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHLAK\\Config\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Kankiewicz", + "email": "Chris@ChrisKankiewicz.com" + } + ], + "description": "Config loading and management", + "time": "2020-03-16T18:49:13+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v2.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/6f981ee24cf69ee7ce9736146d1c57c2780598a8", + "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "time": "2021-07-12T14:48:14+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.24.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "30885182c981ab175d4d034db0f6f469898070ab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", + "reference": "30885182c981ab175d4d034db0f6f469898070ab", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "time": "2021-10-20T20:35:02+00:00" + }, + { + "name": "symfony/yaml", + "version": "v5.4.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "e80f87d2c9495966768310fc531b487ce64237a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/e80f87d2c9495966768310fc531b487ce64237a2", + "reference": "e80f87d2c9495966768310fc531b487ce64237a2", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/console": "<5.3" + }, + "require-dev": { + "symfony/console": "^5.3|^6.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "bin": [ + "Resources/bin/yaml-lint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "time": "2022-01-26T16:32:32+00:00" + }, + { + "name": "yosymfony/parser-utils", + "version": "v2.0.0", + "source": { + "type": "git", + "url": "https://github.com/yosymfony/parser-utils.git", + "reference": "00bec9a12722b21f2baf7f9db35f127e90c162c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/yosymfony/parser-utils/zipball/00bec9a12722b21f2baf7f9db35f127e90c162c9", + "reference": "00bec9a12722b21f2baf7f9db35f127e90c162c9", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "^6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Yosymfony\\ParserUtils\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Victor Puertas", + "email": "vpgugr@gmail.com", + "homepage": "http://yosymfony.com" + } + ], + "description": "Parser utilities", + "homepage": "http://github.com/yosymfony/toml", + "keywords": [ + "lexer", + "parser" + ], + "time": "2018-06-29T15:31:11+00:00" + }, + { + "name": "yosymfony/toml", + "version": "v1.0.4", + "source": { + "type": "git", + "url": "https://github.com/yosymfony/toml.git", + "reference": "bdab92ad920d0e36810a3a3e4a998d23f3498f8e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/yosymfony/toml/zipball/bdab92ad920d0e36810a3a3e4a998d23f3498f8e", + "reference": "bdab92ad920d0e36810a3a3e4a998d23f3498f8e", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "yosymfony/parser-utils": "^2.0" + }, + "require-dev": { + "phpunit/phpunit": "^7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Yosymfony\\Toml\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Victor Puertas", + "email": "vpgugr@gmail.com", + "homepage": "http://yosymfony.com" + } + ], + "description": "A PHP parser for TOML compatible with specification 0.4.0", + "homepage": "http://github.com/yosymfony/toml", + "keywords": [ + "mojombo", + "parser", + "toml" + ], + "time": "2018-08-08T15:08:14+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/web/config.php b/web/config.php new file mode 100644 index 0000000..aa1787a --- /dev/null +++ b/web/config.php @@ -0,0 +1,9 @@ + getenv('SITENAME') ?: 'Jump', + 'wwwroot' => getenv('WWWROOT') ?: '/var/www/html', + 'cachebypass' => getenv('CACHEBYPASS') ?: false, + 'cachedir' => getenv('CACHEDIR') ?: '/var/www/cache', + 'noindex' => getenv('NOINDEX') ?: true, +]; \ No newline at end of file diff --git a/web/index.php b/web/index.php new file mode 100644 index 0000000..2b6e40d --- /dev/null +++ b/web/index.php @@ -0,0 +1,8 @@ +build_index_page(); +echo $jumpapp->get_output(); diff --git a/web/sites/icons/bitwarden.png b/web/sites/icons/bitwarden.png new file mode 100644 index 0000000..f10836c Binary files /dev/null and b/web/sites/icons/bitwarden.png differ diff --git a/web/sites/icons/gitea.png b/web/sites/icons/gitea.png new file mode 100644 index 0000000..dcd4edb Binary files /dev/null and b/web/sites/icons/gitea.png differ diff --git a/web/sites/icons/nextcloud.png b/web/sites/icons/nextcloud.png new file mode 100644 index 0000000..80144b6 Binary files /dev/null and b/web/sites/icons/nextcloud.png differ diff --git a/web/sites/icons/paperless.jpg b/web/sites/icons/paperless.jpg new file mode 100644 index 0000000..2a4c54a Binary files /dev/null and b/web/sites/icons/paperless.jpg differ diff --git a/web/sites/sites.json b/web/sites/sites.json new file mode 100644 index 0000000..855b2fc --- /dev/null +++ b/web/sites/sites.json @@ -0,0 +1,30 @@ +[ + { + "name": "Bitwarden", + "url" : "https://bitwarden.leannedale.co.uk", + "nofollow": true, + "icon": "bitwarden.png" + }, + { + "name": "Gitea", + "url" : "https://git.leannedale.co.uk", + "nofollow": true, + "icon": "gitea.png" + }, + { + "name": "Nextcloud", + "url" : "https://cloud.leannedale.co.uk", + "nofollow": true, + "icon": "nextcloud.png" + }, + { + "name": "Paperless", + "url" : "https://paperless.leannedale.co.uk", + "nofollow": true, + "icon": "paperless.jpg" + }, + { + "name": "Google", + "url" : "https://www.google.com" + } +] \ No newline at end of file diff --git a/web/templates/footer.mustache b/web/templates/footer.mustache new file mode 100644 index 0000000..562cd41 --- /dev/null +++ b/web/templates/footer.mustache @@ -0,0 +1,5 @@ + +
+ {{! }} + + \ No newline at end of file diff --git a/web/templates/greeting.mustache b/web/templates/greeting.mustache new file mode 100644 index 0000000..1ecb770 --- /dev/null +++ b/web/templates/greeting.mustache @@ -0,0 +1 @@ +
Good {{greeting}}
\ No newline at end of file diff --git a/web/templates/header.mustache b/web/templates/header.mustache new file mode 100644 index 0000000..373b187 --- /dev/null +++ b/web/templates/header.mustache @@ -0,0 +1,16 @@ + + + + + + + {{# noindex}}{{/ noindex}} + + {{sitename}} + + + + + + +
\ No newline at end of file diff --git a/web/templates/sites.mustache b/web/templates/sites.mustache new file mode 100644 index 0000000..89b8073 --- /dev/null +++ b/web/templates/sites.mustache @@ -0,0 +1,14 @@ +{{# hassites}} + +{{/ hassites}} \ No newline at end of file