-
" alt="= $data['title'] ?> cover image" />
+
@@ -47,9 +51,14 @@
= $helper->a($link, $char['name']); ?>
- = $helper->img($urlGenerator->assetUrl('images/characters', "{$id}.jpg"), [
+
+ img($urlGenerator->assetUrl('images/characters', "{$id}.jpg"), [
'width' => '225'
- ]) ?>
+ ]) ?> */ ?>
diff --git a/app/views/settings.php b/app/views/settings.php
index 15aa5ecd..0269231b 100644
--- a/app/views/settings.php
+++ b/app/views/settings.php
@@ -1,60 +1,42 @@
get('config_dir'));
-
if ( ! $auth->isAuthenticated())
{
echo 'Not Authorized
';
return;
}
+$sectionMapping = [
+ 'config' => 'General Settings',
+ 'cache' => 'Caching',
+ 'database' => 'Collection Database Settings',
+];
-function render_settings_form ($data, $file)
-{
- ob_start();
- foreach ($data as $key => $value)
- {
- ?>
-
- |
-
-
-
-
- = render_settings_form($value, $file); ?>
-
- |
-
-
= print_r($_POST, TRUE) ?>
- $properties): ?>
-
diff --git a/public/css/app.min.css b/public/css/app.min.css
index 8204e9a0..b90a8c28 100644
--- a/public/css/app.min.css
+++ b/public/css/app.min.css
@@ -1 +1 @@
-:root{-moz-text-size-adjust:100%;-ms-text-size-adjust:100%;-webkit-box-sizing:border-box;-webkit-text-size-adjust:100%;box-sizing:border-box;cursor:default;font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Droid Sans,Helvetica Neue,sans-serif;line-height:1.4;overflow-y:scroll;scroll-behavior:smooth;text-size-adjust:100%}audio:not([controls]){display:none}details{display:block}input[type=search]{-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}main{margin:0 auto;padding:0 1.6rem 1.6rem}main,pre,summary{display:block}pre{background:#efefef;color:#444;font-family:Anonymous Pro,Fira Code,Menlo,Monaco,Consolas,Courier New,monospace;font-size:1.4em;font-size:14px;font-size:1.4rem;margin:1.6rem 0;overflow:auto;padding:1.6rem;word-break:break-all;word-wrap:break-word}progress{display:inline-block}small{color:#777;font-size:75%}big{font-size:125%}template{display:none}textarea{border:.1rem solid #ccc;border-radius:0;display:block;margin-bottom:.8rem;overflow:auto;padding:.8rem;resize:vertical;vertical-align:middle}[hidden]{display:none}[unselectable]{-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none}*,:after,:before{-webkit-box-sizing:inherit;border-style:solid;border-width:0;box-sizing:inherit}*{font-size:inherit;line-height:inherit;margin:0;padding:0}:after,:before{text-decoration:inherit;vertical-align:inherit}a{-webkit-transition:.25s ease;color:#1271db;text-decoration:none;transition:.25s ease}audio,canvas,iframe,img,svg,video{vertical-align:middle}button,input,select,textarea{border:.1rem solid #ccc;color:inherit;font-family:inherit;font-style:inherit;font-weight:inherit;min-height:1.4em}code,kbd,pre,samp{font-family:Anonymous Pro,Fira Code,Menlo,Monaco,Consolas,Courier New,monospace}table{border-collapse:collapse;border-spacing:0;margin-bottom:1.6rem}::-moz-selection{background-color:#b3d4fc;text-shadow:none}::selection{background-color:#b3d4fc;text-shadow:none}button::-moz-focus-inner{border:0}body{color:#444;font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Droid Sans,Helvetica Neue,sans-serif;font-size:16px;font-size:1.6rem;font-style:normal;font-weight:400;padding:0}p{margin:0 0 1.6rem}h1,h2,h3,h4,h5,h6{font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Droid Sans,Helvetica Neue,sans-serif;margin:2rem 0 1.6rem}h1{border-bottom:.1rem solid rgba(0,0,0,.2);font-size:3.6em;font-size:36px;font-size:3.6rem}h1,h2{font-style:normal;font-weight:500}h2{font-size:3em;font-size:30px;font-size:3rem}h3{font-size:2.4em;font-size:24px;font-size:2.4rem;font-style:normal;font-weight:500;margin:1.6rem 0 .4rem}h4{font-size:1.8em;font-size:18px;font-size:1.8rem}h4,h5{font-style:normal;font-weight:600;margin:1.6rem 0 .4rem}h5{font-size:1.6em;font-size:16px;font-size:1.6rem}h6{color:#777;font-size:1.4em;font-style:normal;font-weight:600;margin:1.6rem 0 .4rem}code,h6{font-size:14px;font-size:1.4rem}code{background:#efefef;color:#444;font-family:Anonymous Pro,Fira Code,Menlo,Monaco,Consolas,Courier New,monospace;word-break:break-all;word-wrap:break-word}a:focus,a:hover{text-decoration:none}dl{margin-bottom:1.6rem}dd{margin-left:4rem}ol,ul{margin-bottom:.8rem;padding-left:2rem}blockquote{border-left:.2rem solid #1271db;font-style:italic;margin:1.6rem 0;padding-left:1.6rem}blockquote,figcaption{font-family:Georgia,Times,Times New Roman,serif}html{font-size:62.5%}article,aside,details,footer,header,main,section,summary{display:block;height:auto;margin:0 auto;width:100%}footer{clear:both;display:inline-block;float:left;max-width:100%;padding:1rem 0;text-align:center}footer,hr{border-top:.1rem solid rgba(0,0,0,.2)}hr{display:block;margin-bottom:1.6rem;width:100%}img{height:auto;vertical-align:baseline}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select{border:.1rem solid #ccc;border-radius:0;display:inline-block;padding:.8rem;vertical-align:middle}input:not([type]){-webkit-appearance:none;background-clip:padding-box;background-color:#fff;border:.1rem solid #ccc;border-radius:0;color:#444;display:inline-block;padding:.8rem;text-align:left}input[type=color]{padding:.8rem 1.6rem}input:not([type]):focus,input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus,select:focus,textarea:focus{border-color:#b3d4fc}input[type=checkbox],input[type=radio]{vertical-align:middle}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:1px thin solid #444;outline:.1rem thin solid #444}input:not([type])[disabled],input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled],select[disabled],textarea[disabled]{background-color:#efefef;color:#777;cursor:not-allowed}input[readonly],select[readonly],textarea[readonly]{background-color:#efefef;border-color:#ccc;color:#777}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{border-color:#e9322d;color:#b94a48}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#ff4136}select{background-color:#fff;border:.1rem solid #ccc}select[multiple]{height:auto}label{line-height:2}fieldset{border:0;margin:0;padding:.8rem 0}legend{border-bottom:.1rem solid #ccc;color:#444;display:block;margin-bottom:.8rem;padding:.8rem 0;width:100%}button,input[type=submit]{-moz-user-select:none;-ms-user-select:none;-webkit-transition:.25s ease;-webkit-user-drag:none;-webkit-user-select:none;border:.2rem solid #444;border-radius:0;color:#444;cursor:pointer;display:inline-block;margin-bottom:.8rem;margin-right:.4rem;padding:.8rem 1.6rem;text-align:center;text-decoration:none;text-transform:uppercase;transition:.25s ease;user-select:none;vertical-align:baseline}button a,input[type=submit] a{color:#444}button::-moz-focus-inner,input[type=submit]::-moz-focus-inner{padding:0}button:hover,input[type=submit]:hover{background:#444;border-color:#444;color:#fff}button:hover a,input[type=submit]:hover a{color:#fff}button:active,input[type=submit]:active{background:#6a6a6a;border-color:#6a6a6a;color:#fff}button:active a,input[type=submit]:active a{color:#fff}button:disabled,input[type=submit]:disabled{-webkit-box-shadow:none;box-shadow:none;cursor:not-allowed;opacity:.4}nav ul{list-style:none;margin:0;padding:0;text-align:center}nav ul li{display:inline}nav a{-webkit-transition:.25s ease;border-bottom:.2rem solid transparent;color:#444;padding:.8rem 1.6rem;text-decoration:none;transition:.25s ease}nav a:hover,nav li.selected a{border-color:rgba(0,0,0,.2)}nav a:active{border-color:rgba(0,0,0,.56)}caption{padding:.8rem 0}thead th{background:#efefef;color:#444}tr{background:#fff;margin-bottom:.8rem}td,th{border:.1rem solid #ccc;padding:.8rem 1.6rem;text-align:center;vertical-align:inherit}tfoot tr{background:none}tfoot td{color:#efefef;font-size:8px;font-size:.8rem;font-style:italic;padding:1.6rem .4rem}@media screen{[hidden~=screen]{display:inherit}[hidden~=screen]:not(:active):not(:focus):not(:target){clip:rect(0)!important;position:absolute!important}}@media screen and max-width 40rem{article,aside,section{clear:both;display:block;max-width:100%}img{margin-right:1.6rem}}.media[hidden],[hidden=hidden],template{display:none}body{margin:.5em}button{background:hsla(0,0%,100%,.65);margin:0}table{margin:0 auto}td{padding:1rem}thead td,thead th{padding:.5rem}input[type=number]{width:4em}tbody>tr:nth-child(odd){background:#ddd}a:active,a:hover{color:#7d12db}.bracketed{color:#12db18}#main-nav a,.bracketed{text-shadow:1px 1px 1px #000}.bracketed:before{content:"[\00a0"}.bracketed:after{content:"\00a0]"}.bracketed:active,.bracketed:hover{color:#db7d12}.grow-1{-ms-flex-positive:1;-webkit-box-flex:1;flex-grow:1}.flex-wrap{-ms-flex-wrap:wrap;flex-wrap:wrap}.flex-no-wrap{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.flex-align-end{-ms-flex-align:end;-webkit-box-align:end;align-items:flex-end}.flex-align-space-around{-ms-flex-line-pack:distribute;align-content:space-around}.flex-justify-space-around{-ms-flex-pack:distribute;justify-content:space-around}.flex-self-center{-ms-flex-item-align:center;align-self:center}.flex{display:-webkit-box;display:-ms-flexbox;display:flex}.small-font{font-size:16px;font-size:1.6rem}.justify{text-align:justify}.align_center{text-align:center!important}.align_left{text-align:left!important}.align_right{text-align:right!important}.valign_top{vertical-align:top}.no_border{border:none}.media-wrap{margin:0 auto;position:relative;text-align:center}.danger{background-color:#ff4136;border-color:#924949;color:#fff}.danger:active,.danger:hover{background-color:#924949;border-color:#ff4136;color:#fff}.user-btn{border-color:#12db18;color:#12db18;padding:0 .5rem;text-shadow:1px 1px 1px #000}.user-btn:active,.user-btn:hover{background-color:#db7d12;border-color:#db7d12}.full_width{width:100%}#main-nav{border-bottom:.1rem solid rgba(0,0,0,.2);font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Droid Sans,Helvetica Neue,sans-serif;font-size:3.6em;font-size:36px;font-size:3.6rem;font-style:normal;font-weight:500;margin:2rem 0 1.6rem}.cssload-loader{-webkit-perspective:780px;border-radius:50%;height:62px;left:calc(50% - 31px);perspective:780px;position:relative;width:62px}.cssload-inner{-webkit-box-sizing:border-box;border-radius:50%;box-sizing:border-box;height:100%;position:absolute;width:100%}.cssload-inner.cssload-one{-webkit-animation:cssload-rotate-one 1.15s linear infinite;animation:cssload-rotate-one 1.15s linear infinite;border-bottom:3px solid #000;left:0;top:0}.cssload-inner.cssload-two{-webkit-animation:cssload-rotate-two 1.15s linear infinite;animation:cssload-rotate-two 1.15s linear infinite;border-right:3px solid #000;right:0;top:0}.cssload-inner.cssload-three{-webkit-animation:cssload-rotate-three 1.15s linear infinite;animation:cssload-rotate-three 1.15s linear infinite;border-top:3px solid #000;bottom:0;right:0}@-webkit-keyframes cssload-rotate-one{0%{-webkit-transform:rotateX(35deg) rotateY(-45deg) rotate(0deg);transform:rotateX(35deg) rotateY(-45deg) rotate(0deg)}to{-webkit-transform:rotateX(35deg) rotateY(-45deg) rotate(1turn);transform:rotateX(35deg) rotateY(-45deg) rotate(1turn)}}@keyframes cssload-rotate-one{0%{-webkit-transform:rotateX(35deg) rotateY(-45deg) rotate(0deg);transform:rotateX(35deg) rotateY(-45deg) rotate(0deg)}to{-webkit-transform:rotateX(35deg) rotateY(-45deg) rotate(1turn);transform:rotateX(35deg) rotateY(-45deg) rotate(1turn)}}@-webkit-keyframes cssload-rotate-two{0%{-webkit-transform:rotateX(50deg) rotateY(10deg) rotate(0deg);transform:rotateX(50deg) rotateY(10deg) rotate(0deg)}to{-webkit-transform:rotateX(50deg) rotateY(10deg) rotate(1turn);transform:rotateX(50deg) rotateY(10deg) rotate(1turn)}}@keyframes cssload-rotate-two{0%{-webkit-transform:rotateX(50deg) rotateY(10deg) rotate(0deg);transform:rotateX(50deg) rotateY(10deg) rotate(0deg)}to{-webkit-transform:rotateX(50deg) rotateY(10deg) rotate(1turn);transform:rotateX(50deg) rotateY(10deg) rotate(1turn)}}@-webkit-keyframes cssload-rotate-three{0%{-webkit-transform:rotateX(35deg) rotateY(55deg) rotate(0deg);transform:rotateX(35deg) rotateY(55deg) rotate(0deg)}to{-webkit-transform:rotateX(35deg) rotateY(55deg) rotate(1turn);transform:rotateX(35deg) rotateY(55deg) rotate(1turn)}}@keyframes cssload-rotate-three{0%{-webkit-transform:rotateX(35deg) rotateY(55deg) rotate(0deg);transform:rotateX(35deg) rotateY(55deg) rotate(0deg)}to{-webkit-transform:rotateX(35deg) rotateY(55deg) rotate(1turn);transform:rotateX(35deg) rotateY(55deg) rotate(1turn)}}.sorting,.sorting_asc,.sorting_desc{vertical-align:text-bottom}.sorting:before{content:" ↕\00a0"}.sorting_asc:before{content:" ↑\00a0"}.sorting_desc:before{content:" ↓\00a0"}.form thead th,.form thead tr{background:inherit;border:0}.form tr>td:nth-child(odd){max-width:30%;min-width:25px;text-align:right}.form tr>td:nth-child(2n){text-align:left}.invisible tbody>tr:nth-child(odd){background:inherit}.invisible td,.invisible th,.invisible tr{border:0}.message{margin:.5em auto;padding:.5em;position:relative;width:95%}.message .close{height:1em;line-height:1em;position:absolute;right:.5em;text-align:center;top:.5em;vertical-align:middle;width:1em}.message:hover .close:after{content:"☒"}.message:hover{cursor:pointer}.message .icon{left:.5em;margin-right:1em;top:.5em}.message.error{background:#f3e6e6;border:1px solid #924949}.message.error .icon:after{content:"✘"}.message.success{background:#70dda9;border:1px solid #1f8454}.message.success .icon:after{content:"✔"}.message.info{background:#ffc;border:1px solid #bfbe3a}.message.info .icon:after{content:"⚠"}.character,.media,.small_character{display:inline-block;height:311px;margin:.25em .125em;position:relative;text-align:center;vertical-align:top;width:220px;z-index:0}.character>img,.media>img,.small_character>img{width:100%}.media .edit_buttons>button{margin:.5em auto}.media_metadata>div,.medium_metadata>div,.name,.row{color:#fff;padding:.25em .125em;text-align:right;text-shadow:2px 2px 2px #000;z-index:2}.age_rating,.media_type{text-align:left}.media>.media_metadata{bottom:0;position:absolute;right:0}.media>.medium_metadata{bottom:0;left:0;position:absolute}.media>.name{position:absolute;top:0}.media>.name a{-webkit-transition:none;transition:none}.media .name a:before{content:"";display:block;height:311px;left:0;position:absolute;top:0;width:220px;z-index:-1}.media-list .media:hover .name a:before{background:rgba(0,0,0,.75)}.media>.name span.canonical{font-weight:700}.media>.name small{font-weight:400}.media:hover .name{background:rgba(0,0,0,.75)}.media-list .media>.name a:hover,.media-list .media>.name a:hover small{color:#1271db}.media:hover>.edit_buttons[hidden],.media:hover>button[hidden]{-webkit-transition:.25s ease;display:block;transition:.25s ease}.media:hover{-webkit-transition:.25s ease;transition:.25s ease}.character>.name a,.character>.name a small,.media>.name a,.media>.name a small,.small_character>.name a,.small_character>.name a small{background:none;color:#fff;text-shadow:2px 2px 2px #000}.anime .name,.manga .name{background:#000;background:rgba(0,0,0,.45);padding:.5em .25em;text-align:center;width:100%}.anime .age_rating,.anime .airing_status,.anime .completion,.anime .delete,.anime .edit,.anime .media_type,.anime .user_rating{background:none;text-align:center}.anime .table,.manga .table{bottom:0;left:0;position:absolute;width:100%}.anime .row,.manga .row{-ms-flex-line-pack:distribute;-ms-flex-pack:distribute;align-content:space-around;display:-webkit-box;display:-ms-flexbox;display:flex;justify-content:space-around;padding:0 inherit;text-align:center;width:100%}.anime .row>span,.manga .row>span{text-align:left;z-index:2}.anime .row>div,.manga .row>div{-ms-flex-item-align:center;align-self:center;display:flex-item;font-size:.8em;text-align:center;vertical-align:middle;z-index:2}.anime .media>button.plus_one{border-color:hsla(0,0%,100%,.65);left:44px;left:calc(50% - 66.5px);position:absolute;top:138px;top:calc(50% - 21.5px);z-index:50}.anime .media>button.plus_one:hover{background:#888;color:hsla(0,0%,100%,.65)}.anime .media>button.plus_one:active{background:#444}.manga .row{padding:1px}.manga .media{height:310px;margin:.25em}.manga .media>.edit_buttons{left:43.5px;left:calc(50% - 66.5px);position:absolute;top:86px;top:calc(50% - 22.4px);z-index:40}.manga .media>.edit_buttons button{border-color:hsla(0,0%,100%,.65)}.manga .media>.edit_buttons:hover button{background:#888;color:hsla(0,0%,100%,.65)}.manga .media>.edit_buttons button:active{background:#444}.media.search>.name{background-color:#555;background-color:rgba(0,0,0,.35);background-repeat:no-repeat;background-size:cover;background-size:contain}.media.search>.row{z-index:6}.big-check,.mal-check{display:none}.big-check:checked+label{-webkit-transition:.25s ease;background:rgba(0,0,0,.75);transition:.25s ease}.big-check:checked+label:after{color:#adff2f;content:"✓";font-size:15em;font-size:150px;font-size:15rem;height:100%;left:0;position:absolute;text-align:center;top:147px;width:100%;z-index:5}#series_list article.media{position:relative}#series_list .name,#series_list .name label{display:block;height:100%;left:0;line-height:1.25em;position:absolute;top:0;vertical-align:middle;width:100%}#series_list .name small{color:#fff}.details{font-size:inherit;margin:1.5rem auto 0;padding:1rem}.description{max-width:800px;max-width:80rem}.fixed{max-width:930px;max-width:93rem}.details .cover{display:block;width:284px}.details h2{margin-top:0}.details .flex>div{margin:1rem}.details .media_details{max-width:300px}.details .media_details td{padding:0 1.5rem}.details p{text-align:justify}.details .media_details td:nth-child(odd){text-align:right;white-space:nowrap;width:1%}.details .media_details td:nth-child(2n){text-align:left}.character,.small_character{height:350px;vertical-align:middle;white-space:nowrap;width:225px}.character:hover .name,.small_character:hover .name{background:rgba(0,0,0,.8)}.small_character a{display:inline-block;height:100%;width:100%}.character .name,.small_character .name{bottom:0;left:0;position:absolute;z-index:10}.character img,.small_character img{-webkit-transform:translateY(-50%);position:relative;top:50%;transform:translateY(-50%);width:100%;z-index:5}.min-table{margin-left:0;min-width:0}.small_character{height:250px;width:160px}.user-page .media-wrap{text-align:left}.media a{display:inline-block;height:100%;width:100%}@media screen and (max-width:40em){nav a{line-height:4em;line-height:4rem}.media{margin:2px 0}main{padding:0 .5rem .5rem}}.streaming-logo{height:50px;vertical-align:middle;width:50px}.cover_streaming_link{display:none}.media:hover .cover_streaming_link{display:block}.cover_streaming_link .streaming-logo{-webkit-filter:drop-shadow(0 -1px 4px #fff);filter:drop-shadow(0 -1px 4px #fff);height:20px;width:20px}#loading-shadow{background:rgba(0,0,0,.8);z-index:500}#loading-shadow,#loading-shadow .loading-wrapper{height:100%;left:0;position:fixed;top:0;width:100%}#loading-shadow .loading-wrapper{-ms-flex-align:center;-ms-flex-pack:center;-webkit-box-align:center;-webkit-box-pack:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;justify-content:center;z-index:501}#loading-shadow .loading-content{color:#fff;position:relative}.loading-content .cssload-inner.cssload-one,.loading-content .cssload-inner.cssload-three,.loading-content .cssload-inner.cssload-two{border-color:#fff}.tabs{-ms-flex-wrap:wrap;-webkit-box-shadow:0 48px 80px -32px rgba(0,0,0,.3);background:#efefef;box-shadow:0 48px 80px -32px rgba(0,0,0,.3);display:-webkit-box;display:-ms-flexbox;display:flex;flex-wrap:wrap;margin-top:1.5em}.tabs label{-webkit-transition:background .1s,color .1s;background:#e5e5e5;border:1px solid #e5e5e5;color:#7f7f7f;cursor:pointer;font-size:18px;font-weight:700;padding:20px 30px;transition:background .1s,color .1s;width:100%}.tabs label:hover{background:#d8d8d8}.tabs label:active{background:#ccc}.tabs [type=radio]:focus+label{-webkit-box-shadow:inset 0 0 0 3px #2aa1c0;box-shadow:inset 0 0 0 3px #2aa1c0;z-index:1}.tabs [type=radio]{opacity:0;position:absolute}.tabs [type=radio]:checked+label{background:#fff;border-bottom:1px solid #fff;color:#000}.tabs [type=radio]:checked+label+.content{background:#fff;border:1px solid #e5e5e5;border-top:0;display:block;padding:20px 30px 30px;width:100%}.tabs .content{display:none}@media (min-width:600px){.tabs label{width:auto}.tabs .content{-ms-flex-order:99;-webkit-box-ordinal-group:100;order:99}}
\ No newline at end of file
+:root{-moz-text-size-adjust:100%;-ms-text-size-adjust:100%;-webkit-box-sizing:border-box;-webkit-text-size-adjust:100%;box-sizing:border-box;cursor:default;font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Droid Sans,Helvetica Neue,sans-serif;line-height:1.4;overflow-y:scroll;scroll-behavior:smooth;text-size-adjust:100%}audio:not([controls]){display:none}details{display:block}input[type=search]{-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}main{margin:0 auto;padding:0 1.6rem 1.6rem}main,pre,summary{display:block}pre{background:#efefef;color:#444;font-family:Anonymous Pro,Fira Code,Menlo,Monaco,Consolas,Courier New,monospace;font-size:1.4em;font-size:14px;font-size:1.4rem;margin:1.6rem 0;overflow:auto;padding:1.6rem;word-break:break-all;word-wrap:break-word}progress{display:inline-block}small{color:#777;font-size:75%}big{font-size:125%}template{display:none}textarea{border:.1rem solid #ccc;border-radius:0;display:block;margin-bottom:.8rem;overflow:auto;padding:.8rem;resize:vertical;vertical-align:middle}[hidden]{display:none}[unselectable]{-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none}*,:after,:before{-webkit-box-sizing:inherit;border-style:solid;border-width:0;box-sizing:inherit}*{font-size:inherit;line-height:inherit;margin:0;padding:0}:after,:before{text-decoration:inherit;vertical-align:inherit}a{-webkit-transition:.25s ease;color:#1271db;text-decoration:none;transition:.25s ease}audio,canvas,iframe,img,svg,video{vertical-align:middle}button,input,select,textarea{border:.1rem solid #ccc;color:inherit;font-family:inherit;font-style:inherit;font-weight:inherit;min-height:1.4em}code,kbd,pre,samp{font-family:Anonymous Pro,Fira Code,Menlo,Monaco,Consolas,Courier New,monospace}table{border-collapse:collapse;border-spacing:0;margin-bottom:1.6rem}::-moz-selection{background-color:#b3d4fc;text-shadow:none}::selection{background-color:#b3d4fc;text-shadow:none}button::-moz-focus-inner{border:0}body{color:#444;font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Droid Sans,Helvetica Neue,sans-serif;font-size:16px;font-size:1.6rem;font-style:normal;font-weight:400;padding:0}p{margin:0 0 1.6rem}h1,h2,h3,h4,h5,h6{font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Droid Sans,Helvetica Neue,sans-serif;margin:2rem 0 1.6rem}h1{border-bottom:.1rem solid rgba(0,0,0,.2);font-size:3.6em;font-size:36px;font-size:3.6rem}h1,h2{font-style:normal;font-weight:500}h2{font-size:3em;font-size:30px;font-size:3rem}h3{font-size:2.4em;font-size:24px;font-size:2.4rem;font-style:normal;font-weight:500;margin:1.6rem 0 .4rem}h4{font-size:1.8em;font-size:18px;font-size:1.8rem}h4,h5{font-style:normal;font-weight:600;margin:1.6rem 0 .4rem}h5{font-size:1.6em;font-size:16px;font-size:1.6rem}h6{color:#777;font-size:1.4em;font-style:normal;font-weight:600;margin:1.6rem 0 .4rem}code,h6{font-size:14px;font-size:1.4rem}code{background:#efefef;color:#444;font-family:Anonymous Pro,Fira Code,Menlo,Monaco,Consolas,Courier New,monospace;word-break:break-all;word-wrap:break-word}a:focus,a:hover{text-decoration:none}dl{margin-bottom:1.6rem}dd{margin-left:4rem}ol,ul{margin-bottom:.8rem;padding-left:2rem}blockquote{border-left:.2rem solid #1271db;font-style:italic;margin:1.6rem 0;padding-left:1.6rem}blockquote,figcaption{font-family:Georgia,Times,Times New Roman,serif}html{font-size:62.5%}article,aside,details,footer,header,main,section,summary{display:block;height:auto;margin:0 auto;width:100%}footer{clear:both;display:inline-block;float:left;max-width:100%;padding:1rem 0;text-align:center}footer,hr{border-top:.1rem solid rgba(0,0,0,.2)}hr{display:block;margin-bottom:1.6rem;width:100%}img{height:auto;vertical-align:baseline}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select{border:.1rem solid #ccc;border-radius:0;display:inline-block;padding:.8rem;vertical-align:middle}input:not([type]){-webkit-appearance:none;background-clip:padding-box;background-color:#fff;border:.1rem solid #ccc;border-radius:0;color:#444;display:inline-block;padding:.8rem;text-align:left}input[type=color]{padding:.8rem 1.6rem}input:not([type]):focus,input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus,select:focus,textarea:focus{border-color:#b3d4fc}input[type=checkbox],input[type=radio]{vertical-align:middle}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:1px thin solid #444;outline:.1rem thin solid #444}input:not([type])[disabled],input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled],select[disabled],textarea[disabled]{background-color:#efefef;color:#777;cursor:not-allowed}input[readonly],select[readonly],textarea[readonly]{background-color:#efefef;border-color:#ccc;color:#777}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{border-color:#e9322d;color:#b94a48}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#ff4136}select{background-color:#fff;border:.1rem solid #ccc}select[multiple]{height:auto}label{line-height:2}fieldset{border:0;margin:0;padding:.8rem 0}legend{border-bottom:.1rem solid #ccc;color:#444;display:block;margin-bottom:.8rem;padding:.8rem 0;width:100%}button,input[type=submit]{-moz-user-select:none;-ms-user-select:none;-webkit-transition:.25s ease;-webkit-user-drag:none;-webkit-user-select:none;border:.2rem solid #444;border-radius:0;color:#444;cursor:pointer;display:inline-block;margin-bottom:.8rem;margin-right:.4rem;padding:.8rem 1.6rem;text-align:center;text-decoration:none;text-transform:uppercase;transition:.25s ease;user-select:none;vertical-align:baseline}button a,input[type=submit] a{color:#444}button::-moz-focus-inner,input[type=submit]::-moz-focus-inner{padding:0}button:hover,input[type=submit]:hover{background:#444;border-color:#444;color:#fff}button:hover a,input[type=submit]:hover a{color:#fff}button:active,input[type=submit]:active{background:#6a6a6a;border-color:#6a6a6a;color:#fff}button:active a,input[type=submit]:active a{color:#fff}button:disabled,input[type=submit]:disabled{-webkit-box-shadow:none;box-shadow:none;cursor:not-allowed;opacity:.4}nav ul{list-style:none;margin:0;padding:0;text-align:center}nav ul li{display:inline}nav a{-webkit-transition:.25s ease;border-bottom:.2rem solid transparent;color:#444;padding:.8rem 1.6rem;text-decoration:none;transition:.25s ease}nav a:hover,nav li.selected a{border-color:rgba(0,0,0,.2)}nav a:active{border-color:rgba(0,0,0,.56)}caption{padding:.8rem 0}thead th{background:#efefef;color:#444}tr{background:#fff;margin-bottom:.8rem}td,th{border:.1rem solid #ccc;padding:.8rem 1.6rem;text-align:center;vertical-align:inherit}tfoot tr{background:none}tfoot td{color:#efefef;font-size:8px;font-size:.8rem;font-style:italic;padding:1.6rem .4rem}@media screen{[hidden~=screen]{display:inherit}[hidden~=screen]:not(:active):not(:focus):not(:target){clip:rect(0)!important;position:absolute!important}}@media screen and max-width 40rem{article,aside,section{clear:both;display:block;max-width:100%}img{margin-right:1.6rem}}.media[hidden],[hidden=hidden],template{display:none}body{margin:.5em}button{background:hsla(0,0%,100%,.65);margin:0}table{margin:0 auto}td{padding:1rem}thead td,thead th{padding:.5rem}input[type=number]{width:4em}tbody>tr:nth-child(odd){background:#ddd}a:active,a:hover{color:#7d12db}.bracketed{color:#12db18}#main-nav a,.bracketed{text-shadow:1px 1px 1px #000}.bracketed:before{content:"[\00a0"}.bracketed:after{content:"\00a0]"}.bracketed:active,.bracketed:hover{color:#db7d12}.grow-1{-ms-flex-positive:1;-webkit-box-flex:1;flex-grow:1}.flex-wrap{-ms-flex-wrap:wrap;flex-wrap:wrap}.flex-no-wrap{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.flex-align-end{-ms-flex-align:end;-webkit-box-align:end;align-items:flex-end}.flex-align-space-around{-ms-flex-line-pack:distribute;align-content:space-around}.flex-justify-space-around{-ms-flex-pack:distribute;justify-content:space-around}.flex-self-center{-ms-flex-item-align:center;align-self:center}.flex{display:-webkit-box;display:-ms-flexbox;display:flex}.small-font{font-size:16px;font-size:1.6rem}.justify{text-align:justify}.align_center{text-align:center!important}.align_left{text-align:left!important}.align_right{text-align:right!important}.valign_top{vertical-align:top}.no_border{border:none}.media-wrap{margin:0 auto;position:relative;text-align:center}.danger{background-color:#ff4136;border-color:#924949;color:#fff}.danger:active,.danger:hover{background-color:#924949;border-color:#ff4136;color:#fff}.user-btn{border-color:#12db18;color:#12db18;padding:0 .5rem;text-shadow:1px 1px 1px #000}.user-btn:active,.user-btn:hover{background-color:#db7d12;border-color:#db7d12}.full_width{width:100%}#main-nav{border-bottom:.1rem solid rgba(0,0,0,.2);font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Droid Sans,Helvetica Neue,sans-serif;font-size:3.6em;font-size:36px;font-size:3.6rem;font-style:normal;font-weight:500;margin:2rem 0 1.6rem}.cssload-loader{-webkit-perspective:780px;border-radius:50%;height:62px;left:calc(50% - 31px);perspective:780px;position:relative;width:62px}.cssload-inner{-webkit-box-sizing:border-box;border-radius:50%;box-sizing:border-box;height:100%;position:absolute;width:100%}.cssload-inner.cssload-one{-webkit-animation:cssload-rotate-one 1.15s linear infinite;animation:cssload-rotate-one 1.15s linear infinite;border-bottom:3px solid #000;left:0;top:0}.cssload-inner.cssload-two{-webkit-animation:cssload-rotate-two 1.15s linear infinite;animation:cssload-rotate-two 1.15s linear infinite;border-right:3px solid #000;right:0;top:0}.cssload-inner.cssload-three{-webkit-animation:cssload-rotate-three 1.15s linear infinite;animation:cssload-rotate-three 1.15s linear infinite;border-top:3px solid #000;bottom:0;right:0}@-webkit-keyframes cssload-rotate-one{0%{-webkit-transform:rotateX(35deg) rotateY(-45deg) rotate(0deg);transform:rotateX(35deg) rotateY(-45deg) rotate(0deg)}to{-webkit-transform:rotateX(35deg) rotateY(-45deg) rotate(1turn);transform:rotateX(35deg) rotateY(-45deg) rotate(1turn)}}@keyframes cssload-rotate-one{0%{-webkit-transform:rotateX(35deg) rotateY(-45deg) rotate(0deg);transform:rotateX(35deg) rotateY(-45deg) rotate(0deg)}to{-webkit-transform:rotateX(35deg) rotateY(-45deg) rotate(1turn);transform:rotateX(35deg) rotateY(-45deg) rotate(1turn)}}@-webkit-keyframes cssload-rotate-two{0%{-webkit-transform:rotateX(50deg) rotateY(10deg) rotate(0deg);transform:rotateX(50deg) rotateY(10deg) rotate(0deg)}to{-webkit-transform:rotateX(50deg) rotateY(10deg) rotate(1turn);transform:rotateX(50deg) rotateY(10deg) rotate(1turn)}}@keyframes cssload-rotate-two{0%{-webkit-transform:rotateX(50deg) rotateY(10deg) rotate(0deg);transform:rotateX(50deg) rotateY(10deg) rotate(0deg)}to{-webkit-transform:rotateX(50deg) rotateY(10deg) rotate(1turn);transform:rotateX(50deg) rotateY(10deg) rotate(1turn)}}@-webkit-keyframes cssload-rotate-three{0%{-webkit-transform:rotateX(35deg) rotateY(55deg) rotate(0deg);transform:rotateX(35deg) rotateY(55deg) rotate(0deg)}to{-webkit-transform:rotateX(35deg) rotateY(55deg) rotate(1turn);transform:rotateX(35deg) rotateY(55deg) rotate(1turn)}}@keyframes cssload-rotate-three{0%{-webkit-transform:rotateX(35deg) rotateY(55deg) rotate(0deg);transform:rotateX(35deg) rotateY(55deg) rotate(0deg)}to{-webkit-transform:rotateX(35deg) rotateY(55deg) rotate(1turn);transform:rotateX(35deg) rotateY(55deg) rotate(1turn)}}.sorting,.sorting_asc,.sorting_desc{vertical-align:text-bottom}.sorting:before{content:" ↕\00a0"}.sorting_asc:before{content:" ↑\00a0"}.sorting_desc:before{content:" ↓\00a0"}.form thead th,.form thead tr{background:inherit;border:0}.form tr>td:nth-child(odd){max-width:30%;min-width:25px;text-align:right}.form tr>td:nth-child(2n){text-align:left}.invisible tbody>tr:nth-child(odd){background:inherit}.invisible td,.invisible th,.invisible tr{border:0}.message{margin:.5em auto;padding:.5em;position:relative;width:95%}.message .close{height:1em;line-height:1em;position:absolute;right:.5em;text-align:center;top:.5em;vertical-align:middle;width:1em}.message:hover .close:after{content:"☒"}.message:hover{cursor:pointer}.message .icon{left:.5em;margin-right:1em;top:.5em}.message.error{background:#f3e6e6;border:1px solid #924949}.message.error .icon:after{content:"✘"}.message.success{background:#70dda9;border:1px solid #1f8454}.message.success .icon:after{content:"✔"}.message.info{background:#ffc;border:1px solid #bfbe3a}.message.info .icon:after{content:"⚠"}.character,.media,.small_character{display:inline-block;height:311px;margin:.25em .125em;position:relative;text-align:center;vertical-align:top;width:220px;z-index:0}.details picture.cover,picture.cover{display:inline;display:initial;width:100%}.character>img,.media>img,.small_character>img{width:100%}.media .edit_buttons>button{margin:.5em auto}.media_metadata>div,.medium_metadata>div,.name,.row{color:#fff;padding:.25em .125em;text-align:right;text-shadow:2px 2px 2px #000;z-index:2}.age_rating,.media_type{text-align:left}.media>.media_metadata{bottom:0;position:absolute;right:0}.media>.medium_metadata{bottom:0;left:0;position:absolute}.media>.name{position:absolute;top:0}.media>.name a{-webkit-transition:none;transition:none}.media .name a:before{content:"";display:block;height:311px;left:0;position:absolute;top:0;width:220px;z-index:-1}.media-list .media:hover .name a:before{background:rgba(0,0,0,.75)}.media>.name span.canonical{font-weight:700}.media>.name small{font-weight:400}.media:hover .name{background:rgba(0,0,0,.75)}.media-list .media>.name a:hover,.media-list .media>.name a:hover small{color:#1271db}.media:hover>.edit_buttons[hidden],.media:hover>button[hidden]{-webkit-transition:.25s ease;display:block;transition:.25s ease}.media:hover{-webkit-transition:.25s ease;transition:.25s ease}.character>.name a,.character>.name a small,.media>.name a,.media>.name a small,.small_character>.name a,.small_character>.name a small{background:none;color:#fff;text-shadow:2px 2px 2px #000}.anime .name,.manga .name{background:#000;background:rgba(0,0,0,.45);padding:.5em .25em;text-align:center;width:100%}.anime .age_rating,.anime .airing_status,.anime .completion,.anime .delete,.anime .edit,.anime .media_type,.anime .user_rating{background:none;text-align:center}.anime .table,.manga .table{bottom:0;left:0;position:absolute;width:100%}.anime .row,.manga .row{-ms-flex-line-pack:distribute;-ms-flex-pack:distribute;align-content:space-around;display:-webkit-box;display:-ms-flexbox;display:flex;justify-content:space-around;padding:0 inherit;text-align:center;width:100%}.anime .row>span,.manga .row>span{text-align:left;z-index:2}.anime .row>div,.manga .row>div{-ms-flex-item-align:center;align-self:center;display:flex-item;font-size:.8em;text-align:center;vertical-align:middle;z-index:2}.anime .media>button.plus_one{border-color:hsla(0,0%,100%,.65);left:44px;left:calc(50% - 66.5px);position:absolute;top:138px;top:calc(50% - 21.5px);z-index:50}.anime .media>button.plus_one:hover{background:#888;color:hsla(0,0%,100%,.65)}.anime .media>button.plus_one:active{background:#444}.manga .row{padding:1px}.manga .media{height:310px;margin:.25em}.manga .media>.edit_buttons{left:43.5px;left:calc(50% - 66.5px);position:absolute;top:86px;top:calc(50% - 22.4px);z-index:40}.manga .media>.edit_buttons button{border-color:hsla(0,0%,100%,.65)}.manga .media>.edit_buttons:hover button{background:#888;color:hsla(0,0%,100%,.65)}.manga .media>.edit_buttons button:active{background:#444}.media.search>.name{background-color:#555;background-color:rgba(0,0,0,.35);background-repeat:no-repeat;background-size:cover;background-size:contain}.media.search>.row{z-index:6}.big-check,.mal-check{display:none}.big-check:checked+label{-webkit-transition:.25s ease;background:rgba(0,0,0,.75);transition:.25s ease}.big-check:checked+label:after{color:#adff2f;content:"✓";font-size:15em;font-size:150px;font-size:15rem;height:100%;left:0;position:absolute;text-align:center;top:147px;width:100%;z-index:5}#series_list article.media{position:relative}#series_list .name,#series_list .name label{display:block;height:100%;left:0;line-height:1.25em;position:absolute;top:0;vertical-align:middle;width:100%}#series_list .name small{color:#fff}.details{font-size:inherit;margin:1.5rem auto 0;padding:1rem}.description{max-width:800px;max-width:80rem}.fixed{max-width:930px;max-width:93rem}.details .cover{display:block;width:284px}.details h2{margin-top:0}.details .flex>div{margin:1rem}.details .media_details{max-width:300px}.details .media_details td{padding:0 1.5rem}.details p{text-align:justify}.details .media_details td:nth-child(odd){text-align:right;white-space:nowrap;width:1%}.details .media_details td:nth-child(2n){text-align:left}.character,.small_character{height:350px;vertical-align:middle;white-space:nowrap;width:225px}.character:hover .name,.small_character:hover .name{background:rgba(0,0,0,.8)}.small_character a{display:inline-block;height:100%;width:100%}.character .name,.small_character .name{bottom:0;left:0;position:absolute;z-index:10}.character img,.small_character img{-webkit-transform:translateY(-50%);position:relative;top:50%;transform:translateY(-50%);width:100%;z-index:5}.min-table{margin-left:0;min-width:0}.small_character{height:250px;width:160px}.user-page .media-wrap{text-align:left}.media a{display:inline-block;height:100%;width:100%}@media screen and (max-width:40em){nav a{line-height:4em;line-height:4rem}.media{margin:2px 0}main{padding:0 .5rem .5rem}}.streaming-logo{height:50px;vertical-align:middle;width:50px}.cover_streaming_link{display:none}.media:hover .cover_streaming_link{display:block}.cover_streaming_link .streaming-logo{-webkit-filter:drop-shadow(0 -1px 4px #fff);filter:drop-shadow(0 -1px 4px #fff);height:20px;width:20px}#loading-shadow{background:rgba(0,0,0,.8);z-index:500}#loading-shadow,#loading-shadow .loading-wrapper{height:100%;left:0;position:fixed;top:0;width:100%}#loading-shadow .loading-wrapper{-ms-flex-align:center;-ms-flex-pack:center;-webkit-box-align:center;-webkit-box-pack:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;justify-content:center;z-index:501}#loading-shadow .loading-content{color:#fff;position:relative}.loading-content .cssload-inner.cssload-one,.loading-content .cssload-inner.cssload-three,.loading-content .cssload-inner.cssload-two{border-color:#fff}.tabs{-ms-flex-wrap:wrap;-webkit-box-shadow:0 48px 80px -32px rgba(0,0,0,.3);background:#efefef;box-shadow:0 48px 80px -32px rgba(0,0,0,.3);display:-webkit-box;display:-ms-flexbox;display:flex;flex-wrap:wrap;margin-top:1.5em}.tabs label{-webkit-transition:background .1s,color .1s;background:#e5e5e5;border:1px solid #e5e5e5;color:#7f7f7f;cursor:pointer;font-size:18px;font-weight:700;padding:20px 30px;transition:background .1s,color .1s;width:100%}.tabs label:hover{background:#d8d8d8}.tabs label:active{background:#ccc}.tabs [type=radio]:focus+label{-webkit-box-shadow:inset 0 0 0 3px #2aa1c0;box-shadow:inset 0 0 0 3px #2aa1c0;z-index:1}.tabs [type=radio]{opacity:0;position:absolute}.tabs [type=radio]:checked+label{background:#fff;border-bottom:1px solid #fff;color:#000}.tabs [type=radio]:checked+label+.content{background:#fff;border:1px solid #e5e5e5;border-top:0;display:block;padding:20px 30px 30px;width:100%}.tabs .content{display:none}@media (min-width:600px){.tabs label{width:auto}.tabs .content{-ms-flex-order:99;-webkit-box-ordinal-group:100;order:99}}fieldset.box{display:inline-block;margin:2em;vertical-align:top;width:40%}fieldset.box section{margin:0 auto;text-align:center}fieldset.box article{margin:auto;text-align:left}
\ No newline at end of file
diff --git a/public/css/base.css b/public/css/base.css
index 63f1be7c..a319ef7b 100644
--- a/public/css/base.css
+++ b/public/css/base.css
@@ -384,6 +384,12 @@ a:hover, a:active {
z-index: 0;
}
+.details picture.cover,
+picture.cover {
+ display: initial;
+ width: 100%;
+}
+
.media > img,
.character > img,
.small_character > img {
@@ -915,3 +921,23 @@ CSS Tabs
}
}
+/* ----------------------------------------------------------------------------
+Settings page forms
+-----------------------------------------------------------------------------*/
+fieldset.box {
+ display: inline-block;
+ vertical-align:top;
+ width:40%;
+ margin: 2em;
+}
+
+fieldset.box section {
+ margin: 0 auto;
+ text-align:center;
+}
+
+fieldset.box article {
+ margin: auto;
+ text-align:left;
+}
+
diff --git a/src/Controller.php b/src/Controller.php
index da2efd69..995a6ba5 100644
--- a/src/Controller.php
+++ b/src/Controller.php
@@ -86,11 +86,11 @@ class Controller {
];
/**
- * Constructor
+ * Controller constructor.
*
- * @throws \Aviat\Ion\Di\ContainerException
- * @throws \Aviat\Ion\Di\NotFoundException
* @param ContainerInterface $container
+ * @throws \Aviat\Ion\Di\Exception\ContainerException
+ * @throws \Aviat\Ion\Di\Exception\NotFoundException
*/
public function __construct(ContainerInterface $container)
{
@@ -140,10 +140,9 @@ class Controller {
/**
* Set the current url in the session as the target of a future redirect
*
- * @throws \Aviat\Ion\Di\ContainerException
- * @throws \Aviat\Ion\Di\NotFoundException
- * @param string|null $url
- * @return void
+ * @param string|NULL $url
+ * @throws \Aviat\Ion\Di\Exception\ContainerException
+ * @throws \Aviat\Ion\Di\Exception\NotFoundException
*/
public function setSessionRedirect(string $url = NULL): void
{
@@ -180,8 +179,8 @@ class Controller {
* Redirect to the url previously set in the session
*
* @throws InvalidArgumentException
- * @throws \Aviat\Ion\Di\ContainerException
- * @throws \Aviat\Ion\Di\NotFoundException
+ * @throws \Aviat\Ion\Di\Exception\ContainerException
+ * @throws \Aviat\Ion\Di\Exception\NotFoundException
* @return void
*/
public function sessionRedirect()
@@ -205,8 +204,8 @@ class Controller {
* @param string $template
* @param array $data
* @throws InvalidArgumentException
- * @throws \Aviat\Ion\Di\ContainerException
- * @throws \Aviat\Ion\Di\NotFoundException
+ * @throws \Aviat\Ion\Di\Exception\ContainerException
+ * @throws \Aviat\Ion\Di\Exception\NotFoundException
* @return string
*/
protected function loadPartial($view, string $template, array $data = [])
@@ -239,8 +238,8 @@ class Controller {
* @param string $template
* @param array $data
* @throws InvalidArgumentException
- * @throws \Aviat\Ion\Di\ContainerException
- * @throws \Aviat\Ion\Di\NotFoundException
+ * @throws \Aviat\Ion\Di\Exception\ContainerException
+ * @throws \Aviat\Ion\Di\Exception\NotFoundException
* @return void
*/
protected function renderFullPage($view, string $template, array $data)
@@ -269,8 +268,8 @@ class Controller {
* @param string $title
* @param string $message
* @throws InvalidArgumentException
- * @throws \Aviat\Ion\Di\ContainerException
- * @throws \Aviat\Ion\Di\NotFoundException
+ * @throws \Aviat\Ion\Di\Exception\ContainerException
+ * @throws \Aviat\Ion\Di\Exception\NotFoundException
* @return void
*/
public function notFound(
@@ -292,8 +291,8 @@ class Controller {
* @param string $message
* @param string $long_message
* @throws InvalidArgumentException
- * @throws \Aviat\Ion\Di\ContainerException
- * @throws \Aviat\Ion\Di\NotFoundException
+ * @throws \Aviat\Ion\Di\Exception\ContainerException
+ * @throws \Aviat\Ion\Di\Exception\NotFoundException
* @return void
*/
public function errorPage(int $httpCode, string $title, string $message, string $long_message = ''): void
@@ -313,7 +312,7 @@ class Controller {
*/
public function redirectToDefaultRoute(): void
{
- $defaultType = $this->config->get(['routes', 'route_config', 'default_list']) ?? 'anime';
+ $defaultType = $this->config->get('default_list') ?? 'anime';
$this->redirect($this->urlGenerator->defaultUrl($defaultType), 303);
}
@@ -360,8 +359,8 @@ class Controller {
* @param string $type
* @param string $message
* @throws InvalidArgumentException
- * @throws \Aviat\Ion\Di\ContainerException
- * @throws \Aviat\Ion\Di\NotFoundException
+ * @throws \Aviat\Ion\Di\Exception\ContainerException
+ * @throws \Aviat\Ion\Di\Exception\NotFoundException
* @return string
*/
protected function showMessage($view, string $type, string $message): string
@@ -380,8 +379,8 @@ class Controller {
* @param HtmlView|null $view
* @param int $code
* @throws InvalidArgumentException
- * @throws \Aviat\Ion\Di\ContainerException
- * @throws \Aviat\Ion\Di\NotFoundException
+ * @throws \Aviat\Ion\Di\Exception\ContainerException
+ * @throws \Aviat\Ion\Di\Exception\NotFoundException
* @return void
*/
protected function outputHTML(string $template, array $data = [], $view = NULL, int $code = 200)
@@ -393,6 +392,7 @@ class Controller {
$view->setStatusCode($code);
$this->renderFullPage($view, $template, $data);
+ exit();
}
/**
@@ -407,8 +407,9 @@ class Controller {
{
(new JsonView($this->container))
->setStatusCode($code)
- ->setOutput($data)
- ->send();
+ ->setOutput($data);
+ // ->send();
+ exit();
}
/**
diff --git a/src/Controller/Index.php b/src/Controller/Index.php
index b30fa09e..d509402a 100644
--- a/src/Controller/Index.php
+++ b/src/Controller/Index.php
@@ -20,12 +20,21 @@ use function Amp\Promise\wait;
use Aviat\AnimeClient\Controller as BaseController;
use Aviat\AnimeClient\API\{HummingbirdClient, JsonAPI};
+use Aviat\Ion\Di\ContainerInterface;
use Aviat\Ion\View\HtmlView;
/**
* Controller for handling routes that don't fit elsewhere
*/
final class Index extends BaseController {
+ private $settingsModel;
+
+ public function __construct(ContainerInterface $container)
+ {
+ parent::__construct($container);
+
+ $this->settingsModel = $container->get('settings-model');
+ }
/**
* Purges the API cache
@@ -91,6 +100,7 @@ final class Index extends BaseController {
*/
public function anilistCallback()
{
+ dump($_GET);
$this->outputHTML('blank', [
'title' => 'Oauth!'
]);
@@ -169,8 +179,10 @@ final class Index extends BaseController {
public function settings()
{
$auth = $this->container->get('auth');
+ $form = $this->settingsModel->getSettingsForm();
$this->outputHTML('settings', [
'auth' => $auth,
+ 'form' => $form,
'config' => $this->config,
'title' => $this->config->get('whose_list') . "'s Settings",
]);
@@ -191,6 +203,7 @@ final class Index extends BaseController {
*
* @param string $type The category of image
* @param string $file The filename to look for
+ * @param bool $display Whether to output the image to the server
* @throws \Aviat\Ion\Di\ContainerException
* @throws \Aviat\Ion\Di\NotFoundException
* @throws \InvalidArgumentException
@@ -199,26 +212,30 @@ final class Index extends BaseController {
* @throws \Throwable
* @return void
*/
- public function images(string $type, string $file): void
+ public function images(string $type, string $file, $display = TRUE): void
{
$kitsuUrl = 'https://media.kitsu.io/';
- [$id, $ext] = explode('.', basename($file));
+ $fileName = str_replace('-original', '', $file);
+ [$id, $ext] = explode('.', basename($fileName));
switch ($type)
{
case 'anime':
- $kitsuUrl .= "anime/poster_images/{$id}/small.{$ext}";
+ $kitsuUrl .= "anime/poster_images/{$id}/small.jpg";
+ $width = 220;
break;
case 'avatars':
- $kitsuUrl .= "users/avatars/{$id}/original.{$ext}";
+ $kitsuUrl .= "users/avatars/{$id}/original.jpg";
break;
case 'manga':
- $kitsuUrl .= "manga/poster_images/{$id}/small.{$ext}";
+ $kitsuUrl .= "manga/poster_images/{$id}/small.jpg";
+ $width = 220;
break;
case 'characters':
- $kitsuUrl .= "characters/images/{$id}/original.{$ext}";
+ $kitsuUrl .= "characters/images/{$id}/original.jpg";
+ $width = 225;
break;
default:
@@ -231,9 +248,38 @@ final class Index extends BaseController {
$data = wait($response->getBody());
$baseSavePath = $this->config->get('img_cache_path');
- file_put_contents("{$baseSavePath}/{$type}/{$id}.{$ext}", $data);
- header('Content-type: ' . $response->getHeader('content-type')[0]);
- echo $data;
+ $filePrefix = "{$baseSavePath}/{$type}/{$id}";
+
+ [$origWidth, $origHeight] = getimagesizefromstring($data);
+ $gdImg = imagecreatefromstring($data);
+ $resizedImg = imagescale($gdImg, $width ?? $origWidth);
+
+ // save the webp versions
+ imagewebp($gdImg, "{$filePrefix}-original.webp");
+ imagewebp($resizedImg, "{$filePrefix}.webp");
+
+ // save the scaled jpeg file
+ imagejpeg($resizedImg, "{$filePrefix}.jpg");
+
+ imagedestroy($gdImg);
+ imagedestroy($resizedImg);
+
+ // And the original
+ file_put_contents("{$filePrefix}-original.jpg", $data);
+
+ if ($display)
+ {
+ $contentType = ($ext === 'webp')
+ ? "image/webp"
+ : $response->getHeader('content-type')[0];
+
+ $outputFile = (strpos($file, '-original') !== FALSE)
+ ? "{$filePrefix}-original.{$ext}"
+ : "{$filePrefix}.{$ext}";
+
+ header("Content-Type: {$contentType}");
+ echo file_get_contents($outputFile);
+ }
}
/**
diff --git a/src/FormGenerator.php b/src/FormGenerator.php
new file mode 100644
index 00000000..1a642347
--- /dev/null
+++ b/src/FormGenerator.php
@@ -0,0 +1,115 @@
+
+ * @copyright 2015 - 2018 Timothy J. Warren
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ * @version 4.1
+ * @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
+ */
+
+namespace Aviat\AnimeClient;
+
+use Aviat\Ion\
+{
+ ArrayWrapper, StringWrapper
+};
+use Aviat\Ion\Di\ContainerInterface;
+
+/**
+ * Helper object to manage form generation, especially for config editing
+ */
+final class FormGenerator {
+ use ArrayWrapper;
+ use StringWrapper;
+
+ /**
+ * Injection Container
+ * @var ContainerInterface $container
+ */
+ protected $container;
+
+ /**
+ * Html generation helper
+ *
+ * @var \Aura\Html\HelperLocator
+ */
+ protected $helper;
+
+ public function __construct(ContainerInterface $container)
+ {
+ $this->container = $container;
+ $this->helper = $container->get('html-helper');
+ }
+
+ /**
+ * Generate the html structure of the form
+ *
+ * @param string $name
+ * @param array $form
+ * @return string
+ */
+ public function generate(string $name, array $form)
+ {
+ $type = $form['type'];
+
+ if ($form['display'] === FALSE)
+ {
+ return $this->helper->input([
+ 'type' => 'hidden',
+ 'name' => $name,
+ 'value' => $form['value'],
+ ]);
+ }
+
+ $params = [
+ 'name' => $name,
+ 'value' => $form['value'],
+ 'attribs' => [
+ 'id' => $name,
+ ],
+ ];
+
+ switch($type)
+ {
+ case 'boolean':
+ /* $params['type'] = 'checkbox';
+ $params['attribs']['label'] = $form['description'];
+ $params['attribs']['value'] = TRUE;
+ $params['attribs']['value_unchecked'] = '0'; */
+
+ $params['type'] = 'radio';
+ $params['options'] = [
+ '1' => 'Yes',
+ '0' => 'No',
+ ];
+ unset($params['attribs']['id']);
+ break;
+
+ case 'string':
+ $params['type'] = 'text';
+ break;
+
+ case 'select':
+ $params['type'] = 'select';
+ $params['options'] = array_flip($form['options']);
+ break;
+ }
+
+ foreach (['readonly', 'disabled'] as $key)
+ {
+ if ($form[$key] !== FALSE)
+ {
+ $params['attribs'][$key] = $form[$key];
+ }
+ }
+
+ return $this->helper->input($params);
+ }
+}
\ No newline at end of file
diff --git a/src/Helper/Form.php b/src/Helper/Form.php
new file mode 100644
index 00000000..244030ab
--- /dev/null
+++ b/src/Helper/Form.php
@@ -0,0 +1,41 @@
+
+ * @copyright 2015 - 2018 Timothy J. Warren
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ * @version 4.1
+ * @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
+ */
+
+namespace Aviat\AnimeClient\Helper;
+
+use Aviat\AnimeClient\FormGenerator;
+use Aviat\Ion\Di\ContainerAware;
+
+/**
+ * MenuGenerator helper wrapper
+ */
+final class Form {
+
+ use ContainerAware;
+
+ /**
+ * Create the html for the selected menu
+ *
+ * @param string $name
+ * @param array $form
+ * @return string
+ */
+ public function __invoke(string $name, array $form)
+ {
+ return (new FormGenerator($this->container))->generate($name, $form);
+ }
+}
+// End of Menu.php
\ No newline at end of file
diff --git a/src/Model/Settings.php b/src/Model/Settings.php
new file mode 100644
index 00000000..fcb8fab4
--- /dev/null
+++ b/src/Model/Settings.php
@@ -0,0 +1,286 @@
+
+ * @copyright 2015 - 2018 Timothy J. Warren
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ * @version 4.1
+ * @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
+ */
+
+namespace Aviat\AnimeClient\Model;
+
+use Aviat\AnimeClient\Types\{Config, UndefinedPropertyException};
+
+use Aviat\Ion\ConfigInterface;
+use Aviat\Ion\Di\ContainerAware;
+use Aviat\Ion\StringWrapper;
+
+/**
+ * Model for handling settings control panel
+ */
+final class Settings {
+ use ContainerAware;
+ use StringWrapper;
+
+ private $config;
+
+ /**
+ * Map the config values to types and form fields
+ */
+ private const SETTINGS_MAP = [
+ 'anilist' => [
+
+ ],
+ 'config' => [
+ 'kitsu_username' => [
+ 'type' => 'string',
+ 'title' => 'Kitsu Username',
+ 'default' => '',
+ 'readonly' => TRUE,
+ 'description' => 'Username of the account to pull list data from.',
+ ],
+ 'whose_list' => [
+ 'type' => 'string',
+ 'title' => 'Whose List',
+ 'default' => 'Somebody',
+ 'readonly' => TRUE,
+ 'description' => 'Name of the owner of the list data.',
+ ],
+ 'show_anime_collection' => [
+ 'type' => 'boolean',
+ 'title' => 'Show Anime Collection',
+ 'default' => FALSE,
+ 'description' => 'Should the anime collection be shown?',
+ ],
+ 'show_manga_collection' => [
+ 'type' => 'boolean',
+ 'title' => 'Show Manga Collection',
+ 'default' => FALSE,
+ 'description' => 'Should the manga collection be shown?',
+ ],
+ 'asset_path' => [
+ 'type' => 'string',
+ 'display' => FALSE,
+ 'description' => 'Path to public directory, where images/css/javascript are located',
+ ],
+ 'default_list' => [
+ 'type' => 'select',
+ 'title' => 'Default List',
+ 'description' => 'Which list to show by default.',
+ 'options' => [
+ 'Anime' => 'anime',
+ 'Manga' => 'manga',
+ ],
+ ],
+ 'default_anime_list_path' => [ //watching|plan_to_watch|on_hold|dropped|completed|all
+ 'type' => 'select',
+ 'title' => 'Default Anime List Section',
+ 'description' => 'Which part of the anime list to show by default.',
+ 'options' => [
+ 'Watching' => 'watching',
+ 'Plan to Watch' => 'plan_to_watch',
+ 'On Hold' => 'on_hold',
+ 'Dropped' => 'dropped',
+ 'Completed' => 'completed',
+ 'All' => 'all',
+ ]
+ ],
+ 'default_manga_list_path' => [ //reading|plan_to_read|on_hold|dropped|completed|all
+ 'type' => 'select',
+ 'title' => 'Default Manga List Section',
+ 'description' => 'Which part of the manga list to show by default.',
+ 'options' => [
+ 'Reading' => 'reading',
+ 'Plan to Read' => 'plan_to_read',
+ 'On Hold' => 'on_hold',
+ 'Dropped' => 'dropped',
+ 'Completed' => 'completed',
+ 'All' => 'all',
+ ]
+ ]
+ ],
+ 'cache' => [
+ 'driver' => [
+ 'type' => 'select',
+ 'title' => 'Cache Type',
+ 'description' => 'The Cache backend',
+ 'options' => [
+ 'APCu' => 'apcu',
+ 'Memcached' => 'memcached',
+ 'Redis' => 'redis',
+ 'No Cache' => 'null'
+ ],
+ ],
+ 'connection' => [
+ 'type' => 'subfield',
+ 'title' => 'Connection',
+ 'fields' => [
+ 'host' => [
+ 'type' => 'string',
+ 'title' => 'Cache Host',
+ 'description' => 'Host of the cache backend to connect to',
+ ],
+ 'port' => [
+ 'type' => 'string',
+ 'title' => 'Cache Port',
+ 'description' => 'Port of the cache backend to connect to',
+ ],
+ 'password' => [
+ 'type' => 'string',
+ 'title' => 'Cache Password',
+ 'description' => 'Password to connect to cache backend',
+ ],
+ 'database' => [
+ 'type' => 'string',
+ 'title' => 'Cache Database',
+ 'description' => 'Cache database number for Redis',
+ ],
+ ],
+ ],
+ ],
+ 'database' => [
+ 'type' => [
+ 'type' => 'select',
+ 'title' => 'Database Type',
+ 'options' => [
+ 'MySQL' => 'mysql',
+ 'PostgreSQL' => 'pgsql',
+ 'SQLite' => 'sqlite',
+ ],
+ 'description' => 'Type of database to connect to',
+ ],
+ 'host' => [
+ 'type' => 'string',
+ 'title' => 'Host',
+ 'description' => 'The host of the database server',
+ ],
+ 'user' => [
+ 'type' => 'string',
+ 'title' => 'User',
+ 'description' => 'Database connection user',
+ ],
+ 'pass' => [
+ 'type' => 'string',
+ 'title' => 'Password',
+ 'description' => 'Database connection password'
+ ],
+ 'port' => [
+ 'type' => 'string',
+ 'title' => 'Port',
+ 'description' => 'Database connection port'
+ ],
+ 'database' => [
+ 'type' => 'string',
+ 'title' => 'Database Name',
+ 'description' => 'Name of the database/schema to connect to',
+ ],
+ 'file' => [
+ 'type' => 'string',
+ 'title' => 'Database File',
+ 'description' => 'Path to the database file, if required by the current database type.'
+ ],
+ ],
+ ];
+
+ public function __construct(ConfigInterface $config)
+ {
+ $this->config = $config;
+ }
+
+ public function getSettings()
+ {
+ $settings = [
+ 'config' => [],
+ ];
+
+ foreach(static::SETTINGS_MAP as $file => $values)
+ {
+ if ($file === 'config')
+ {
+ $keys = array_keys($values);
+ foreach($keys as $key)
+ {
+ $settings['config'][$key] = $this->config->get($key);
+ }
+ }
+ else
+ {
+ $settings[$file] = $this->config->get($file);
+ }
+ }
+
+ return $settings;
+ }
+
+ public function getSettingsForm()
+ {
+ $output = [];
+
+ $settings = $this->getSettings();
+
+ foreach($settings as $file => $values)
+ {
+ foreach(static::SETTINGS_MAP[$file] as $key => $value)
+ {
+ if ($value['type'] === 'subfield')
+ {
+ foreach($value['fields'] as $k => $field)
+ {
+ $value['fields'][$k]['value'] = $values[$key][$k] ?? '';
+ $value['fields'][$k]['display'] = TRUE;
+ $value['fields'][$k]['readonly'] = FALSE;
+ $value['fields'][$k]['disabled'] = FALSE;
+ }
+ }
+
+ if (is_scalar($values[$key]))
+ {
+ $value['value'] = $values[$key];
+ }
+
+ foreach (['readonly', 'disabled'] as $flag)
+ {
+ if ( ! array_key_exists($flag, $value))
+ {
+ $value[$flag] = FALSE;
+ }
+ }
+
+ if ( ! array_key_exists('display', $value))
+ {
+ $value['display'] = TRUE;
+ }
+
+ $output[$file][$key] = $value;
+ }
+ }
+
+ return $output;
+ }
+
+ public function validateSettings(array $settings): bool
+ {
+ try
+ {
+ new Config($settings);
+ }
+ catch (UndefinedPropertyException $e)
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ public function saveSettingsFile()
+ {
+
+ }
+}
\ No newline at end of file