editor-projects #29

Merged
rodude123 merged 7 commits from editor-projects into master 2023-02-07 03:35:44 +00:00
19 changed files with 418 additions and 117 deletions
Showing only changes of commit cef7cc5e64 - Show all commits

3
.fleet/settings.json Normal file
View File

@ -0,0 +1,3 @@
{
"editor.guides": []
}

191
composer.lock generated
View File

@ -121,16 +121,16 @@
}, },
{ {
"name": "guzzlehttp/psr7", "name": "guzzlehttp/psr7",
"version": "2.4.0", "version": "2.4.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/psr7.git", "url": "https://github.com/guzzle/psr7.git",
"reference": "13388f00956b1503577598873fffb5ae994b5737" "reference": "67c26b443f348a51926030c83481b85718457d3d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/13388f00956b1503577598873fffb5ae994b5737", "url": "https://api.github.com/repos/guzzle/psr7/zipball/67c26b443f348a51926030c83481b85718457d3d",
"reference": "13388f00956b1503577598873fffb5ae994b5737", "reference": "67c26b443f348a51926030c83481b85718457d3d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -144,15 +144,19 @@
"psr/http-message-implementation": "1.0" "psr/http-message-implementation": "1.0"
}, },
"require-dev": { "require-dev": {
"bamarni/composer-bin-plugin": "^1.4.1", "bamarni/composer-bin-plugin": "^1.8.1",
"http-interop/http-factory-tests": "^0.9", "http-interop/http-factory-tests": "^0.9",
"phpunit/phpunit": "^8.5.8 || ^9.3.10" "phpunit/phpunit": "^8.5.29 || ^9.5.23"
}, },
"suggest": { "suggest": {
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"bamarni-bin": {
"bin-links": true,
"forward-command": false
},
"branch-alias": { "branch-alias": {
"dev-master": "2.4-dev" "dev-master": "2.4-dev"
} }
@ -216,7 +220,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/guzzle/psr7/issues", "issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.4.0" "source": "https://github.com/guzzle/psr7/tree/2.4.3"
}, },
"funding": [ "funding": [
{ {
@ -232,7 +236,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-06-20T21:43:11+00:00" "time": "2022-10-26T14:07:24+00:00"
}, },
{ {
"name": "http-interop/http-factory-guzzle", "name": "http-interop/http-factory-guzzle",
@ -294,25 +298,24 @@
}, },
{ {
"name": "laminas/laminas-diactoros", "name": "laminas/laminas-diactoros",
"version": "2.14.0", "version": "2.24.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laminas/laminas-diactoros.git", "url": "https://github.com/laminas/laminas-diactoros.git",
"reference": "6cb35f61913f06b2c91075db00f67cfd78869e28" "reference": "6028af6c3b5ced4d063a680d2483cce67578b902"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/6cb35f61913f06b2c91075db00f67cfd78869e28", "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/6028af6c3b5ced4d063a680d2483cce67578b902",
"reference": "6cb35f61913f06b2c91075db00f67cfd78869e28", "reference": "6028af6c3b5ced4d063a680d2483cce67578b902",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^7.3 || ~8.0.0 || ~8.1.0", "php": "~8.0.0 || ~8.1.0 || ~8.2.0",
"psr/http-factory": "^1.0", "psr/http-factory": "^1.0",
"psr/http-message": "^1.0" "psr/http-message": "^1.0"
}, },
"conflict": { "conflict": {
"phpspec/prophecy": "<1.9.0",
"zendframework/zend-diactoros": "*" "zendframework/zend-diactoros": "*"
}, },
"provide": { "provide": {
@ -325,12 +328,11 @@
"ext-gd": "*", "ext-gd": "*",
"ext-libxml": "*", "ext-libxml": "*",
"http-interop/http-factory-tests": "^0.9.0", "http-interop/http-factory-tests": "^0.9.0",
"laminas/laminas-coding-standard": "~2.3.0", "laminas/laminas-coding-standard": "^2.4.0",
"php-http/psr7-integration-tests": "^1.1.1", "php-http/psr7-integration-tests": "^1.2",
"phpspec/prophecy-phpunit": "^2.0", "phpunit/phpunit": "^9.5.27",
"phpunit/phpunit": "^9.5", "psalm/plugin-phpunit": "^0.18.4",
"psalm/plugin-phpunit": "^0.17.0", "vimeo/psalm": "^5.4"
"vimeo/psalm": "^4.24.0"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
@ -389,34 +391,34 @@
"type": "community_bridge" "type": "community_bridge"
} }
], ],
"time": "2022-07-28T12:23:48+00:00" "time": "2022-12-20T12:22:40+00:00"
}, },
{ {
"name": "laminas/laminas-httphandlerrunner", "name": "laminas/laminas-httphandlerrunner",
"version": "2.1.0", "version": "2.5.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laminas/laminas-httphandlerrunner.git", "url": "https://github.com/laminas/laminas-httphandlerrunner.git",
"reference": "4d337cde83e6b901a4443b0ab5c3b97cbaa46413" "reference": "7a47834aaad7852816d2ec4fdbb0492163b039ae"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laminas/laminas-httphandlerrunner/zipball/4d337cde83e6b901a4443b0ab5c3b97cbaa46413", "url": "https://api.github.com/repos/laminas/laminas-httphandlerrunner/zipball/7a47834aaad7852816d2ec4fdbb0492163b039ae",
"reference": "4d337cde83e6b901a4443b0ab5c3b97cbaa46413", "reference": "7a47834aaad7852816d2ec4fdbb0492163b039ae",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^7.3 || ~8.0.0 || ~8.1.0", "php": "~8.0.0 || ~8.1.0 || ~8.2.0",
"psr/http-message": "^1.0", "psr/http-message": "^1.0",
"psr/http-message-implementation": "^1.0", "psr/http-message-implementation": "^1.0",
"psr/http-server-handler": "^1.0" "psr/http-server-handler": "^1.0"
}, },
"require-dev": { "require-dev": {
"laminas/laminas-coding-standard": "~2.3.0", "laminas/laminas-coding-standard": "~2.4.0",
"laminas/laminas-diactoros": "^2.8.0", "laminas/laminas-diactoros": "^2.18",
"phpunit/phpunit": "^9.5.9", "phpunit/phpunit": "^9.5.26",
"psalm/plugin-phpunit": "^0.16.1", "psalm/plugin-phpunit": "^0.18.0",
"vimeo/psalm": "^4.10.0" "vimeo/psalm": "^5.0.0"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
@ -456,29 +458,30 @@
"type": "community_bridge" "type": "community_bridge"
} }
], ],
"time": "2021-09-22T09:27:36+00:00" "time": "2023-01-05T21:54:03+00:00"
}, },
{ {
"name": "laravel/serializable-closure", "name": "laravel/serializable-closure",
"version": "v1.2.0", "version": "v1.2.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/serializable-closure.git", "url": "https://github.com/laravel/serializable-closure.git",
"reference": "09f0e9fb61829f628205b7c94906c28740ff9540" "reference": "47afb7fae28ed29057fdca37e16a84f90cc62fae"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/09f0e9fb61829f628205b7c94906c28740ff9540", "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/47afb7fae28ed29057fdca37e16a84f90cc62fae",
"reference": "09f0e9fb61829f628205b7c94906c28740ff9540", "reference": "47afb7fae28ed29057fdca37e16a84f90cc62fae",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^7.3|^8.0" "php": "^7.3|^8.0"
}, },
"require-dev": { "require-dev": {
"pestphp/pest": "^1.18", "nesbot/carbon": "^2.61",
"phpstan/phpstan": "^0.12.98", "pestphp/pest": "^1.21.3",
"symfony/var-dumper": "^5.3" "phpstan/phpstan": "^1.8.2",
"symfony/var-dumper": "^5.4.11"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
@ -515,7 +518,7 @@
"issues": "https://github.com/laravel/serializable-closure/issues", "issues": "https://github.com/laravel/serializable-closure/issues",
"source": "https://github.com/laravel/serializable-closure" "source": "https://github.com/laravel/serializable-closure"
}, },
"time": "2022-05-16T17:09:47+00:00" "time": "2022-09-08T13:45:54+00:00"
}, },
{ {
"name": "monolog/monolog", "name": "monolog/monolog",
@ -1582,40 +1585,40 @@
}, },
{ {
"name": "slim/psr7", "name": "slim/psr7",
"version": "1.5", "version": "1.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/slimphp/Slim-Psr7.git", "url": "https://github.com/slimphp/Slim-Psr7.git",
"reference": "a47b43a8da7c0208b4c228af0cb29ea36080635a" "reference": "3471c22c1a0d26c51c78f6aeb06489d38cf46a4d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/slimphp/Slim-Psr7/zipball/a47b43a8da7c0208b4c228af0cb29ea36080635a", "url": "https://api.github.com/repos/slimphp/Slim-Psr7/zipball/3471c22c1a0d26c51c78f6aeb06489d38cf46a4d",
"reference": "a47b43a8da7c0208b4c228af0cb29ea36080635a", "reference": "3471c22c1a0d26c51c78f6aeb06489d38cf46a4d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"fig/http-message-util": "^1.1.5", "fig/http-message-util": "^1.1.5",
"php": "^7.3 || ^8.0", "php": "^7.4 || ^8.0",
"psr/http-factory": "^1.0", "psr/http-factory": "^1.0",
"psr/http-message": "^1.0", "psr/http-message": "^1.0",
"ralouphie/getallheaders": "^3.0", "ralouphie/getallheaders": "^3.0",
"symfony/polyfill-php80": "^1.23" "symfony/polyfill-php80": "^1.26"
}, },
"provide": { "provide": {
"psr/http-factory-implementation": "1.0", "psr/http-factory-implementation": "1.0",
"psr/http-message-implementation": "1.0" "psr/http-message-implementation": "1.0"
}, },
"require-dev": { "require-dev": {
"adriansuter/php-autoload-override": "^1.2", "adriansuter/php-autoload-override": "^1.3",
"ext-json": "*", "ext-json": "*",
"http-interop/http-factory-tests": "^0.9.0", "http-interop/http-factory-tests": "^0.9.0",
"php-http/psr7-integration-tests": "dev-master", "php-http/psr7-integration-tests": "dev-master",
"phpspec/prophecy": "^1.14", "phpspec/prophecy": "^1.15",
"phpspec/prophecy-phpunit": "^2.0", "phpspec/prophecy-phpunit": "^2.0",
"phpstan/phpstan": "^0.12.99", "phpstan/phpstan": "^1.8",
"phpunit/phpunit": "^9.5", "phpunit/phpunit": "^9.5",
"squizlabs/php_codesniffer": "^3.6" "squizlabs/php_codesniffer": "^3.7"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -1658,22 +1661,22 @@
], ],
"support": { "support": {
"issues": "https://github.com/slimphp/Slim-Psr7/issues", "issues": "https://github.com/slimphp/Slim-Psr7/issues",
"source": "https://github.com/slimphp/Slim-Psr7/tree/1.5" "source": "https://github.com/slimphp/Slim-Psr7/tree/1.6"
}, },
"time": "2021-09-22T04:33:00+00:00" "time": "2022-11-05T18:50:24+00:00"
}, },
{ {
"name": "slim/slim", "name": "slim/slim",
"version": "4.10.0", "version": "4.11.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/slimphp/Slim.git", "url": "https://github.com/slimphp/Slim.git",
"reference": "0dfc7d2fdf2553b361d864d51af3fe8a6ad168b0" "reference": "b0f4ca393ea037be9ac7292ba7d0a34d18bac0c7"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/slimphp/Slim/zipball/0dfc7d2fdf2553b361d864d51af3fe8a6ad168b0", "url": "https://api.github.com/repos/slimphp/Slim/zipball/b0f4ca393ea037be9ac7292ba7d0a34d18bac0c7",
"reference": "0dfc7d2fdf2553b361d864d51af3fe8a6ad168b0", "reference": "b0f4ca393ea037be9ac7292ba7d0a34d18bac0c7",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1688,21 +1691,21 @@
"psr/log": "^1.1 || ^2.0 || ^3.0" "psr/log": "^1.1 || ^2.0 || ^3.0"
}, },
"require-dev": { "require-dev": {
"adriansuter/php-autoload-override": "^1.2", "adriansuter/php-autoload-override": "^1.3",
"ext-simplexml": "*", "ext-simplexml": "*",
"guzzlehttp/psr7": "^2.1", "guzzlehttp/psr7": "^2.4",
"httpsoft/http-message": "^1.0", "httpsoft/http-message": "^1.0",
"httpsoft/http-server-request": "^1.0", "httpsoft/http-server-request": "^1.0",
"laminas/laminas-diactoros": "^2.8", "laminas/laminas-diactoros": "^2.17",
"nyholm/psr7": "^1.5", "nyholm/psr7": "^1.5",
"nyholm/psr7-server": "^1.0", "nyholm/psr7-server": "^1.0",
"phpspec/prophecy": "^1.15", "phpspec/prophecy": "^1.15",
"phpspec/prophecy-phpunit": "^2.0", "phpspec/prophecy-phpunit": "^2.0",
"phpstan/phpstan": "^1.4", "phpstan/phpstan": "^1.8",
"phpunit/phpunit": "^9.5", "phpunit/phpunit": "^9.5",
"slim/http": "^1.2", "slim/http": "^1.2",
"slim/psr7": "^1.5", "slim/psr7": "^1.5",
"squizlabs/php_codesniffer": "^3.6" "squizlabs/php_codesniffer": "^3.7"
}, },
"suggest": { "suggest": {
"ext-simplexml": "Needed to support XML format in BodyParsingMiddleware", "ext-simplexml": "Needed to support XML format in BodyParsingMiddleware",
@ -1775,37 +1778,37 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-03-14T14:18:23+00:00" "time": "2022-11-06T16:33:39+00:00"
}, },
{ {
"name": "slim/slim-skeleton", "name": "slim/slim-skeleton",
"version": "4.4.0", "version": "4.5.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/slimphp/Slim-Skeleton.git", "url": "https://github.com/slimphp/Slim-Skeleton.git",
"reference": "8a91d18b0a8e4623f1af9207e97477c7b8437f57" "reference": "1997d86c18837d26248a2cca204fabb6a430329c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/slimphp/Slim-Skeleton/zipball/8a91d18b0a8e4623f1af9207e97477c7b8437f57", "url": "https://api.github.com/repos/slimphp/Slim-Skeleton/zipball/1997d86c18837d26248a2cca204fabb6a430329c",
"reference": "8a91d18b0a8e4623f1af9207e97477c7b8437f57", "reference": "1997d86c18837d26248a2cca204fabb6a430329c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-json": "*", "ext-json": "*",
"monolog/monolog": "^2.3", "monolog/monolog": "^2.8",
"php": "^7.4 || ^8.0", "php": "^7.4 || ^8.0",
"php-di/php-di": "^6.3", "php-di/php-di": "^6.4",
"slim/psr7": "^1.5", "slim/psr7": "^1.5",
"slim/slim": "^4.9" "slim/slim": "^4.10"
}, },
"require-dev": { "require-dev": {
"jangregor/phpstan-prophecy": "^1.0.0", "jangregor/phpstan-prophecy": "^1.0.0",
"phpspec/prophecy-phpunit": "^2.0", "phpspec/prophecy-phpunit": "^2.0",
"phpstan/extension-installer": "^1.1.0", "phpstan/extension-installer": "^1.2.0",
"phpstan/phpstan": "^1.3", "phpstan/phpstan": "^1.8",
"phpunit/phpunit": "^9.5.11", "phpunit/phpunit": "^9.5.26",
"squizlabs/php_codesniffer": "^3.6" "squizlabs/php_codesniffer": "^3.7"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -1839,22 +1842,22 @@
], ],
"support": { "support": {
"issues": "https://github.com/slimphp/Slim-Skeleton/issues", "issues": "https://github.com/slimphp/Slim-Skeleton/issues",
"source": "https://github.com/slimphp/Slim-Skeleton/tree/4.4.0" "source": "https://github.com/slimphp/Slim-Skeleton/tree/4.5.0"
}, },
"time": "2022-01-14T19:30:57+00:00" "time": "2022-11-02T21:21:07+00:00"
}, },
{ {
"name": "symfony/polyfill-php80", "name": "symfony/polyfill-php80",
"version": "v1.26.0", "version": "v1.27.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-php80.git", "url": "https://github.com/symfony/polyfill-php80.git",
"reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace" "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace", "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
"reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace", "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1863,7 +1866,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "1.26-dev" "dev-main": "1.27-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
@ -1908,7 +1911,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0" "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0"
}, },
"funding": [ "funding": [
{ {
@ -1924,7 +1927,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-05-10T07:21:04+00:00" "time": "2022-11-03T14:55:06+00:00"
}, },
{ {
"name": "tuupola/callable-handler", "name": "tuupola/callable-handler",
@ -2057,34 +2060,34 @@
}, },
{ {
"name": "tuupola/slim-jwt-auth", "name": "tuupola/slim-jwt-auth",
"version": "3.6.0", "version": "3.7.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/tuupola/slim-jwt-auth.git", "url": "https://github.com/tuupola/slim-jwt-auth.git",
"reference": "d9ed8bca77a0ef2a95ab48e65ddc26073b99c5ff" "reference": "ef05b93d4dac7307ef6ef3b62feaff30c32e82c1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/tuupola/slim-jwt-auth/zipball/d9ed8bca77a0ef2a95ab48e65ddc26073b99c5ff", "url": "https://api.github.com/repos/tuupola/slim-jwt-auth/zipball/ef05b93d4dac7307ef6ef3b62feaff30c32e82c1",
"reference": "d9ed8bca77a0ef2a95ab48e65ddc26073b99c5ff", "reference": "ef05b93d4dac7307ef6ef3b62feaff30c32e82c1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"firebase/php-jwt": "^3.0|^4.0|^5.0", "firebase/php-jwt": "^3.0|^4.0|^5.0",
"php": "^7.1|^8.0", "php": "^7.2|^8.0",
"psr/http-message": "^1.0", "psr/http-message": "^1.0",
"psr/http-server-middleware": "^1.0", "psr/http-server-middleware": "^1.0",
"psr/log": "^1.0|^2.0|^3.0", "psr/log": "^1.0|^2.0|^3.0",
"tuupola/callable-handler": "^0.3.0|^0.4.0|^1.0", "tuupola/callable-handler": "^1.0",
"tuupola/http-factory": "^0.4.0|^1.0.2" "tuupola/http-factory": "^1.3"
}, },
"require-dev": { "require-dev": {
"equip/dispatch": "^2.0", "equip/dispatch": "^2.0",
"laminas/laminas-diactoros": "^2.0", "laminas/laminas-diactoros": "^2.0",
"overtrue/phplint": "^1.0", "overtrue/phplint": "^1.0",
"phpstan/phpstan": "^0.12.43", "phpstan/phpstan": "^1.8",
"phpunit/phpunit": "^7.0|^8.0|^9.0", "phpunit/phpunit": "^7.0|^8.5.30|^9.0",
"squizlabs/php_codesniffer": "^3.4" "squizlabs/php_codesniffer": "^3.7"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
@ -2121,7 +2124,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/tuupola/slim-jwt-auth/issues", "issues": "https://github.com/tuupola/slim-jwt-auth/issues",
"source": "https://github.com/tuupola/slim-jwt-auth/tree/3.6.0" "source": "https://github.com/tuupola/slim-jwt-auth/tree/3.7.0"
}, },
"funding": [ "funding": [
{ {
@ -2129,7 +2132,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2022-01-12T11:15:02+00:00" "time": "2022-12-23T11:23:05+00:00"
} }
], ],
"packages-dev": [], "packages-dev": [],

4
dist/api/.htaccess vendored
View File

@ -1,4 +0,0 @@
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [QSA,L]

3
dist/api/index.php vendored
View File

@ -54,6 +54,8 @@ $app->get("/timelineData/{timeline}", function (Request $request, Response $resp
return $response; return $response;
} }
// something went wrong // something went wrong
$response->getBody()->write(json_encode(array("errorMessage" => "Error, timeline data not found"))); $response->getBody()->write(json_encode(array("errorMessage" => "Error, timeline data not found")));
return $response->withStatus(404); return $response->withStatus(404);
@ -285,6 +287,7 @@ $app->post("/contact", function (Request $request, Response $response)
{ {
$response->getBody()->write(json_encode(array("errorMessage" => "Please fill out all the fields"))); $response->getBody()->write(json_encode(array("errorMessage" => "Please fill out all the fields")));
return $response->withStatus(400); return $response->withStatus(400);
} }
if (!filter_var($data["email"], FILTER_VALIDATE_EMAIL)) if (!filter_var($data["email"], FILTER_VALIDATE_EMAIL))

View File

@ -2,9 +2,14 @@
// middleware // middleware
namespace api; namespace api;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Slim\App; use Slim\App;
use Selective\SameSiteCookie\SameSiteCookieConfiguration; use Selective\SameSiteCookie\SameSiteCookieConfiguration;
use Selective\SameSiteCookie\SameSiteCookieMiddleware; use Selective\SameSiteCookie\SameSiteCookieMiddleware;
use Slim\Exception\HttpMethodNotAllowedException;
use Slim\Exception\HttpNotFoundException;
use Slim\Psr7\Response;
use Tuupola\Middleware\JwtAuthentication; use Tuupola\Middleware\JwtAuthentication;
use Tuupola\Middleware\JwtAuthentication\RequestMethodRule; use Tuupola\Middleware\JwtAuthentication\RequestMethodRule;
use Tuupola\Middleware\JwtAuthentication\RequestPathRule; use Tuupola\Middleware\JwtAuthentication\RequestPathRule;
@ -24,6 +29,7 @@ class middleware
$this->baseMiddleware($app); $this->baseMiddleware($app);
$this->sameSiteConfig($app); $this->sameSiteConfig($app);
$this->jwtAuth($app); $this->jwtAuth($app);
$this->errorHandling($app);
$this->returnAsJSON($app); $this->returnAsJSON($app);
} }
@ -86,7 +92,31 @@ class middleware
return $response->withStatus(401); return $response->withStatus(401);
} }
])); ]));
}
function errorHandling(App $app): void
{
$app->add(function (ServerRequestInterface $request, RequestHandlerInterface $handler)
{
try
{
return $handler->handle($request);
}
catch (HttpNotFoundException $httpException)
{
$response = (new Response())->withStatus(404);
$response->getBody()->write(json_encode(array("status" => "404", "message" => $request->getUri()->getPath() . " not found")));
return $response;
}
catch (HttpMethodNotAllowedException $httpException)
{
$response = (new Response())->withStatus(405);
$response->getBody()->write(json_encode(array("status" => "405", "message" => "Method not allowed")));
return $response;
}
});
$app->addErrorMiddleware(true, true, true); $app->addErrorMiddleware(true, true, true);
} }
} }

View File

@ -17,7 +17,7 @@ class projectData
function getProjectData(): array function getProjectData(): array
{ {
$conn = dbConn(); $conn = dbConn();
$stmt = $conn->prepare("SELECT title, isMainProject, information, imgLocation, projectLink, githubLink FROM projects order by date LIMIT 4;"); $stmt = $conn->prepare("SELECT title, isMainProject, information, imgLocation, projectLink, gitLink FROM projects order by date LIMIT 4;");
$stmt->execute(); $stmt->execute();
// set the resulting array to associative // set the resulting array to associative

2
dist/css/main.css vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Editor</title><link rel="stylesheet" href="css/main.css"><script src="https://kit.fontawesome.com/ed3c25598e.js" crossorigin="anonymous"></script></head><body><nav class="sideNav"><a href="#" class="closeBtn" id="navClose">&times;</a><ul><li><a href="#" class="active"><span>&lt;</span>CV<span>&gt;</span></a></li><li><a href="#"><span>&lt;</span>Projects<span>&gt;</span></a></li><li><a href="#"><span>&lt;</span>Settings<span>&gt;</span></a></li></ul></nav><main class="editor" style="margin-left: 250px;"><div class="title"><span id="navOpen">&#9776;</span><h1>Editor</h1></div><section id="curriculumVitae"><h2>curriculum vitae</h2><div class="cvGrid"><div><h3>Education</h3><div class="editorContainer"><form action="" method="POST" id="addEdu"><div class="formControl"><label for="dateFromE">Date From</label> <input type="date" id="dateFromE" name="dateFromE"></div><div class="formControl"><label for="dateToE">Date To</label> <input type="date" id="dateToE" name="dateToE"></div><div class="formControl"><label for="grade">Grade</label> <input type="text" id="grade" name="grade"></div><div class="formControl"><label for="courseTitle">Course Title</label> <input type="text" id="courseTitle" name="courseTitle"></div><div class="error hidden" id="eduError"><button class="close" type="button">&times;</button><div></div></div><input type="submit" class="btn btnPrimary boxShadowIn boxShadowOut" value="Add new course"></form><div class="timeline" id="edu"></div></div></div><div><h3>Work</h3><div class="editorContainer"><form action="" method="POST" id="addWork"><div class="formControl"><label for="dateFromW">Date From</label> <input type="date" id="dateFromW" name="dateFromW"></div><div class="formControl"><label for="dateToW">Date To</label> <input type="date" id="dateToW" name="dateToW"></div><div class="formControl"><label for="company">Company</label> <input type="text" id="company" name="company"></div><div class="formControl"><label for="area">Area</label> <input type="text" id="area" name="area"></div><div class="formControl"><label for="jobTitle">Job Title</label> <input type="text" id="jobTitle" name="jobTitle"></div><div class="error hidden" id="workError"><button class="close" type="button">&times;</button><div></div></div><input type="submit" class="btn btnPrimary boxShadowIn boxShadowOut" value="Add new job"></form><div class="timeline" id="work"></div></div></div></div></section></main><script src="js/editor.js"></script></body></html> <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Editor</title><link rel="stylesheet" href="css/main.css"><script src="https://kit.fontawesome.com/ed3c25598e.js" crossorigin="anonymous"></script></head><body><nav class="sideNav"><a href="#" class="closeBtn" id="navClose">&times;</a><ul><li><a href="#" id="goToCV" class="active"><span>&lt;</span>CV<span>&gt;</span></a></li><li><a href="#" id="goToProjects"><span>&lt;</span>Projects<span>&gt;</span></a></li><li><a href="#" id="goToSettings"><span>&lt;</span>Settings<span>&gt;</span></a></li><li><a href="#" id="logout"><span>&lt;</span>Logout<span>&gt;</span></a></li></ul></nav><main class="editor" style="margin-left: 250px;"><div class="title"><span id="navOpen">&#9776;</span><h1>Editor</h1></div><section id="curriculumVitae"><h2>curriculum vitae</h2><div class="cvGrid"><div><h3>Education</h3><div class="editorContainer"><form action="" method="POST" id="addEdu"><div class="formControl"><label for="dateFromE">Date From</label> <input type="date" id="dateFromE" name="dateFromE"></div><div class="formControl"><label for="dateToE">Date To</label> <input type="date" id="dateToE" name="dateToE"></div><div class="formControl"><label for="grade">Grade</label> <input type="text" id="grade" name="grade"></div><div class="formControl"><label for="courseTitle">Course Title</label> <input type="text" id="courseTitle" name="courseTitle"></div><div class="error hidden" id="eduError"><button class="close" type="button">&times;</button><div></div></div><input type="submit" class="btn btnPrimary boxShadowIn boxShadowOut" value="Add new course"></form><div class="timeline" id="edu"></div></div></div><div><h3>Work</h3><div class="editorContainer"><form action="" method="POST" id="addWork"><div class="formControl"><label for="dateFromW">Date From</label> <input type="date" id="dateFromW" name="dateFromW"></div><div class="formControl"><label for="dateToW">Date To</label> <input type="date" id="dateToW" name="dateToW"></div><div class="formControl"><label for="company">Company</label> <input type="text" id="company" name="company"></div><div class="formControl"><label for="area">Area</label> <input type="text" id="area" name="area"></div><div class="formControl"><label for="jobTitle">Job Title</label> <input type="text" id="jobTitle" name="jobTitle"></div><div class="error hidden" id="workError"><button class="close" type="button">&times;</button><div></div></div><input type="submit" class="btn btnPrimary boxShadowIn boxShadowOut" value="Add new job"></form><div class="timeline" id="work"></div></div></div></div></section><section id="projects"><h2>projects</h2><div class="projectsGrid"><form action="" id="addProj"><div class="formControl"><label for="projTitle">Title</label> <input type="text" name="projTitle" id="projTitle" required></div><div class="formControl"><label class="checkContainer" for="isMainProject">Is It The Main Project <input type="checkbox" id="isMainProject" name="isMainProject" required> <span class="checkmark"></span></label></div><div class="formControl"><label for="imgLoc">Image</label> <input type="file" name="imgLoc" id="imgLoc"></div><div class="formControl"><label for="projectLink">Project Link</label> <input type="text" name="projectLink" id="projectLink" pattern="https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)"></div><div class="formControl"><label for="gitLink">Git Link</label> <input type="text" name="gitLink" id="gitLink" pattern="https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)" required></div><input type="submit" value="Add new Project" class="btn btnPrimary boxShadowIn boxShadowOut"></form><div id="projList"></div></div></section></main><script src="js/editor.js"></script></body></html>

File diff suppressed because one or more lines are too long

2
dist/js/main.js vendored

File diff suppressed because one or more lines are too long

View File

@ -54,6 +54,8 @@ $app->get("/timelineData/{timeline}", function (Request $request, Response $resp
return $response; return $response;
} }
// something went wrong // something went wrong
$response->getBody()->write(json_encode(array("errorMessage" => "Error, timeline data not found"))); $response->getBody()->write(json_encode(array("errorMessage" => "Error, timeline data not found")));
return $response->withStatus(404); return $response->withStatus(404);
@ -285,6 +287,7 @@ $app->post("/contact", function (Request $request, Response $response)
{ {
$response->getBody()->write(json_encode(array("errorMessage" => "Please fill out all the fields"))); $response->getBody()->write(json_encode(array("errorMessage" => "Please fill out all the fields")));
return $response->withStatus(400); return $response->withStatus(400);
} }
if (!filter_var($data["email"], FILTER_VALIDATE_EMAIL)) if (!filter_var($data["email"], FILTER_VALIDATE_EMAIL))

View File

@ -2,9 +2,14 @@
// middleware // middleware
namespace api; namespace api;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Slim\App; use Slim\App;
use Selective\SameSiteCookie\SameSiteCookieConfiguration; use Selective\SameSiteCookie\SameSiteCookieConfiguration;
use Selective\SameSiteCookie\SameSiteCookieMiddleware; use Selective\SameSiteCookie\SameSiteCookieMiddleware;
use Slim\Exception\HttpMethodNotAllowedException;
use Slim\Exception\HttpNotFoundException;
use Slim\Psr7\Response;
use Tuupola\Middleware\JwtAuthentication; use Tuupola\Middleware\JwtAuthentication;
use Tuupola\Middleware\JwtAuthentication\RequestMethodRule; use Tuupola\Middleware\JwtAuthentication\RequestMethodRule;
use Tuupola\Middleware\JwtAuthentication\RequestPathRule; use Tuupola\Middleware\JwtAuthentication\RequestPathRule;
@ -24,6 +29,7 @@ class middleware
$this->baseMiddleware($app); $this->baseMiddleware($app);
$this->sameSiteConfig($app); $this->sameSiteConfig($app);
$this->jwtAuth($app); $this->jwtAuth($app);
$this->errorHandling($app);
$this->returnAsJSON($app); $this->returnAsJSON($app);
} }
@ -86,7 +92,31 @@ class middleware
return $response->withStatus(401); return $response->withStatus(401);
} }
])); ]));
}
function errorHandling(App $app): void
{
$app->add(function (ServerRequestInterface $request, RequestHandlerInterface $handler)
{
try
{
return $handler->handle($request);
}
catch (HttpNotFoundException $httpException)
{
$response = (new Response())->withStatus(404);
$response->getBody()->write(json_encode(array("status" => "404", "message" => $request->getUri()->getPath() . " not found")));
return $response;
}
catch (HttpMethodNotAllowedException $httpException)
{
$response = (new Response())->withStatus(405);
$response->getBody()->write(json_encode(array("status" => "405", "message" => "Method not allowed")));
return $response;
}
});
$app->addErrorMiddleware(true, true, true); $app->addErrorMiddleware(true, true, true);
} }
} }

View File

@ -17,7 +17,7 @@ class projectData
function getProjectData(): array function getProjectData(): array
{ {
$conn = dbConn(); $conn = dbConn();
$stmt = $conn->prepare("SELECT title, isMainProject, information, imgLocation, projectLink, githubLink FROM projects order by date LIMIT 4;"); $stmt = $conn->prepare("SELECT title, isMainProject, information, imgLocation, projectLink, gitLink FROM projects order by date LIMIT 4;");
$stmt->execute(); $stmt->execute();
// set the resulting array to associative // set the resulting array to associative

View File

@ -159,6 +159,10 @@ form .formControl input:not([type="submit"]) {
form .formControl { form .formControl {
width: 100%; width: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
} }
form input[type="submit"] { form input[type="submit"] {
@ -189,7 +193,8 @@ form .formControl input:not([type="submit"]).invalid:invalid:focus, form .formCo
box-shadow: 0 4px 2px 0 var(--mutedBlack); box-shadow: 0 4px 2px 0 var(--mutedBlack);
} }
form .formControl input:not([type="submit"]):focus, form .formControl textarea:focus { form .formControl input:not([type="submit"]):focus, form .formControl textarea:focus,
form .formControl input:not([type="submit"]):hover, form .formControl textarea:hover {
border: 4px solid var(--primaryHover); border: 4px solid var(--primaryHover);
} }
@ -208,6 +213,90 @@ form .formControl input:not([type="submit"]):focus + i.fa-eye-slash {
color: var(--primaryHover); color: var(--primaryHover);
} }
form .formControl .checkContainer {
display: block;
position: relative;
margin-bottom: 1.25em;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
form .formControl .checkContainer input {
position: absolute;
opacity: 0;
cursor: pointer;
height: 0;
width: 0;
}
form .formControl .checkContainer .checkmark {
position: absolute;
top: 1.25em;
left: 0;
height: 25px;
width: 25px;
background-color: var(--mutedGrey);
}
form .formControl .checkContainer:hover input ~ .checkmark {
background-color: var(--grey);
}
form .formControl .checkContainer input:checked ~ .checkmark {
background-color: var(--primaryDefault);
}
form .formControl .checkContainer input:checked:hover ~ .checkmark {
background-color: var(--primaryHover);
}
form .formControl .checkContainer .checkmark:after {
content: "";
position: absolute;
display: none;
}
form .formControl .checkContainer input:checked ~ .checkmark:after {
display: block;
}
form .formControl .checkContainer .checkmark:after {
left: 9px;
top: 5px;
width: 5px;
height: 10px;
border: solid white;
border-width: 0 3px 3px 0;
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
}
form .formControl input[type="file"] {
padding: 0;
}
form .formControl input[type="file"]::file-selector-button {
background-color: var(--primaryDefault);
border: 0;
border-right: 5px solid var(--mutedBlack);
padding: 15px;
margin-right: 20px;
-webkit-transition: all .5s;
-moz-transition: all .5s;
-ms-transition: all .5s;
-o-transition: all .5s;
transition: all .5s;
cursor: pointer;
}
form .formControl input[type="file"]:hover::file-selector-button {
background-color: var(--primaryHover);
}
section#about, section#curriculumVitae h1 { section#about, section#curriculumVitae h1 {
padding: 0 5rem; padding: 0 5rem;
} }

View File

@ -23,19 +23,27 @@ input[type="submit"] {
font-weight: 400; font-weight: 400;
} }
div.editorContainer { div.editorContainer, div.projectsGrid {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: center; justify-content: center;
align-items: baseline; align-items: flex-start;
gap: 2em; gap: 2em;
margin-bottom: 0.5em; margin-bottom: 0.5em;
} }
div.editorContainer > * { div.editorContainer > *, div.projectsGrid > * {
width: 45%; width: 45%;
} }
section#curriculumVitae {
display: block;
}
section#projects, section#settings {
display: none;
}
div.modifyBtnContainer { div.modifyBtnContainer {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -147,3 +155,49 @@ section#curriculumVitae form.timelineItem:not(.editing) input[type=submit] {
section#curriculumVitae form.timelineItem:not(.editing) div.companyAreaContainer input { section#curriculumVitae form.timelineItem:not(.editing) div.companyAreaContainer input {
width: 30%; width: 30%;
} }
section#projects #projList .projItem {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
margin: 0 auto;
width: 90%;
border: 1px solid var(--grey);
gap: 1em;
box-shadow: 0 6px 4px 0 var(--mutedBlack);
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
padding: 1em;
}
section#projects #projList {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 1em;
}
section#projects #projList .projItem img {
max-width: 15rem;
width: 100%;
padding: 0 1em;
}
section#projects .projItem .flexCol div:nth-child(2) {
display: flex;
flex-direction: row;
justify-content: flex-start;
gap: 3em;
margin-left: 2em;
}
section#projects .flexCol div:nth-child(2) .btn {
padding: 0.25em 0.5em;
}
#isMainProject {
width: auto;
}

View File

@ -10,9 +10,10 @@
<nav class="sideNav"> <nav class="sideNav">
<a href="#" class="closeBtn" id="navClose">&times;</a> <a href="#" class="closeBtn" id="navClose">&times;</a>
<ul> <ul>
<li><a href="#" class="active"><span>&lt;</span>CV<span>&gt;</span></a></li> <li><a href="#" id="goToCV" class="active"><span>&lt;</span>CV<span>&gt;</span></a></li>
<li><a href="#"><span>&lt;</span>Projects<span>&gt;</span></a></li> <li><a href="#" id="goToProjects"><span>&lt;</span>Projects<span>&gt;</span></a></li>
<li><a href="#"><span>&lt;</span>Settings<span>&gt;</span></a></li> <li><a href="#" id="goToSettings"><span>&lt;</span>Settings<span>&gt;</span></a></li>
<li><a href="#" id="logout"><span>&lt;</span>Logout<span>&gt;</span></a></li>
</ul> </ul>
</nav> </nav>
<main class="editor" style="margin-left: 250px;"> <main class="editor" style="margin-left: 250px;">
@ -109,7 +110,39 @@
</div> </div>
</section> </section>
section#projects>h2{projects}+div. <section id="projects">
<h2>projects</h2>
<div class="projectsGrid">
<form action="" id="addProj">
<div class="formControl">
<label for="projTitle">Title </label>
<input type="text" name="projTitle" id="projTitle" required>
</div>
<div class="formControl">
<label class="checkContainer" for="isMainProject">Is It The Main Project
<input type="checkbox" id="isMainProject" name="isMainProject" required>
<span class="checkmark"></span>
</label>
</div>
<div class="formControl">
<label for="imgLoc">Image</label>
<input type="file" name="imgLoc" id="imgLoc">
</div>
<div class="formControl">
<label for="projectLink">Project Link</label>
<input type="text" name="projectLink" id="projectLink" pattern="https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)">
</div>
<div class="formControl">
<label for="gitLink">Git Link</label>
<input type="text" name="gitLink" id="gitLink" pattern="https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)" required>
</div>
<input type="submit" value="Add new Project" class="btn btnPrimary boxShadowIn boxShadowOut">
</form>
<div id="projList">
</div>
</div>
</section>
</main> </main>
<script src="js/editor.js"></script> <script src="js/editor.js"></script>

View File

@ -46,6 +46,22 @@ document.addEventListener('DOMContentLoaded', () =>
document.querySelector("#edu").innerHTML = "No education data found"; document.querySelector("#edu").innerHTML = "No education data found";
}) })
}); });
fetch("/api/projectData").then(res =>
{
res.json().then(json =>
{
if (res.ok)
{
json.forEach(item =>
{
addProject(item["information"], item["projectLink"], item["gitLink"]);
})
return;
}
document.querySelector("#projects").innerHTML = "No project data found";
})
})
}) })
document.querySelector("#navOpen").addEventListener("click", e => document.querySelector("#navOpen").addEventListener("click", e =>
@ -134,6 +150,28 @@ document.querySelector("#addWork").addEventListener("submit", e =>
})); }));
}); });
document.querySelector("#goToCV").addEventListener("click", () =>
{
document.querySelector("#curriculumVitae").style.display = "block";
document.querySelector("#goToCV").classList.toggle("active");
document.querySelector("#projects").style.display = "none";
document.querySelector("#goToProjects").classList.toggle("active");
});
document.querySelector("#goToProjects").addEventListener("click", () =>
{
document.querySelector("#curriculumVitae").style.display = "none";
document.querySelector("#goToCV").classList.toggle("active");
document.querySelector("#projects").style.display = "block";
document.querySelector("#goToProjects").classList.toggle("active");
});
document.querySelector("#logout").addEventListener("click", () =>
{
document.cookie = "PHPSESSID=;Path=/cv;expires=Thu, 01 Jan 1970 00:00:01 GMT;";
window.location.reload();
});
/** /**
* Switches the timeline item between edit and view mode * Switches the timeline item between edit and view mode
@ -405,3 +443,22 @@ function deleteWorkItem(id)
}); });
} }
function addProject(information, projectLink, gitLink)
{
document.querySelector("#projList").innerHTML += `
<div class="projItem">
<img src="../imgs/500x400.jpg" alt="">
<div class="flexCol">
<div>
<p>${information}</p>
</div>
<div>
<a href="${(projectLink === "N/A") ? "#" : projectLink}" class="btn btnPrimary boxShadowIn boxShadowOut"${(projectLink === "N/A") ? "disabled=\"disabled\"" : ""}>View Project</a>
<a href="${(gitLink === "N/A") ? "#" : gitLink}" class="btn btnOutline boxShadowIn boxShadowOut">${(gitLink === "N/A") ? "disabled=\"disabled\"" : ""}Github</a>
</div>
</div>
</div>
`;
}

View File

@ -176,7 +176,7 @@ function getProjectData()
<p>${item["information"]}</p> <p>${item["information"]}</p>
<div class="flexCol"> <div class="flexCol">
<a href="${(item["projectLink"] === "N/A") ? "#" : item["projectLink"]}" class="btn btnPrimary boxShadowIn boxShadowOut" ${(item["projectLink"] === "N/A") ? "disabled=\"disabled\"" : ""}>View Project</a> <a href="${(item["projectLink"] === "N/A") ? "#" : item["projectLink"]}" class="btn btnPrimary boxShadowIn boxShadowOut" ${(item["projectLink"] === "N/A") ? "disabled=\"disabled\"" : ""}>View Project</a>
<a href="${(item["githubLink"] === "N/A") ? "#" : item["gitubLink"]}" class="btn btnOutline boxShadowIn boxShadowOut" ${(item["githubLink"] === "N/A") ? "disabled=\"disabled\"" : ""}>GitHub</a> <a href="${(item["gitLink"] === "N/A") ? "#" : item["gitLink"]}" class="btn btnOutline boxShadowIn boxShadowOut" ${(item["gitLink"] === "N/A") ? "disabled=\"disabled\"" : ""}>GitHub</a>
</div> </div>
</div> </div>
</div> </div>