Welcome back, mio!
This commit is contained in:
parent
19d19adec3
commit
d058036da1
38 changed files with 1210 additions and 235 deletions
14
assets/less/auth/classes/button.less
Normal file
14
assets/less/auth/classes/button.less
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
.button {
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 0;
|
||||||
|
padding: 7px 10px;
|
||||||
|
background: #462e55;
|
||||||
|
color: #fff;
|
||||||
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
|
line-height: 1.4em;
|
||||||
|
display: inline-block;
|
||||||
|
text-decoration: none;
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
5
assets/less/auth/classes/container.less
Normal file
5
assets/less/auth/classes/container.less
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
.container {
|
||||||
|
box-shadow: 0 2px 5px fade(#111, 80%);
|
||||||
|
background: #222;
|
||||||
|
margin: 2px;
|
||||||
|
}
|
93
assets/less/auth/classes/form.less
Normal file
93
assets/less/auth/classes/form.less
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
.form {
|
||||||
|
height: @auth-title-height;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: height .3s ease-in-out;
|
||||||
|
|
||||||
|
&__wrapper {
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
border-bottom: 1px solid #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__toggle {
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
&:checked ~ .form {
|
||||||
|
height: @auth-form-height;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:checked) ~ .form .form__title:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
background: #333;
|
||||||
|
z-index: 100;
|
||||||
|
box-shadow: 0 2px 5px fade(#111, 80%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-size: 1.4em;
|
||||||
|
display: block;
|
||||||
|
padding: 10px;
|
||||||
|
height: @auth-title-height;
|
||||||
|
transition: background .2s, box-shadow .2s;
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-khtml-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin: 0 5px;
|
||||||
|
height: @auth-form-height - @auth-title-height;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: height .5s ease-in-out;
|
||||||
|
align-items: center;
|
||||||
|
flex-grow: 1;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
&--no-registration {
|
||||||
|
max-width: 400px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__link {
|
||||||
|
color: #88c;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
color: #c88;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__row {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&--columns {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__column {
|
||||||
|
|
||||||
|
&--message {
|
||||||
|
padding-left: 10px;
|
||||||
|
color: #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--error {
|
||||||
|
color: #a33;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
assets/less/auth/classes/logout.less
Normal file
20
assets/less/auth/classes/logout.less
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
.logout {
|
||||||
|
max-width: 400px;
|
||||||
|
padding: 5px;
|
||||||
|
|
||||||
|
&__message {
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__paragraph {
|
||||||
|
&:not(:last-child) {
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__buttons {
|
||||||
|
margin-top: 5px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
}
|
17
assets/less/auth/classes/text.less
Normal file
17
assets/less/auth/classes/text.less
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
.text {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
border: 0;
|
||||||
|
background: #1a1a1a;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: #fff;
|
||||||
|
padding: 5px;
|
||||||
|
|
||||||
|
@media (max-width: @auth-mobile) {
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
44
assets/less/auth/main.less
Normal file
44
assets/less/auth/main.less
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
@auth-mobile: 500px;
|
||||||
|
@auth-title-height: 40px;
|
||||||
|
@auth-form-height: 200px;
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: #5e3e71 url('https://static.flash.moe/images/grid.png');
|
||||||
|
font: 12px/20px sans-serif;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth {
|
||||||
|
min-width: 400px;
|
||||||
|
min-height: @auth-form-height;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
@media (max-width: @auth-mobile) {
|
||||||
|
min-width: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@import "classes/button";
|
||||||
|
@import "classes/container";
|
||||||
|
@import "classes/form";
|
||||||
|
@import "classes/logout";
|
||||||
|
@import "classes/text";
|
11
assets/less/mio/classes/avatar.less
Normal file
11
assets/less/mio/classes/avatar.less
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
.mio__avatar {
|
||||||
|
flex-shrink: 0;
|
||||||
|
background-color: #fbeeff;
|
||||||
|
background-size: contain;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: 50%;
|
||||||
|
display: block;
|
||||||
|
border: 1px solid #9475b2;
|
||||||
|
max-height: 200px;
|
||||||
|
max-width: 200px;
|
||||||
|
}
|
19
assets/less/mio/classes/container.less
Normal file
19
assets/less/mio/classes/container.less
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
.mio__container {
|
||||||
|
border: 1px solid #9475b2;
|
||||||
|
background-color: #fbeeff;
|
||||||
|
margin: 2px 0;
|
||||||
|
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
background-color: #9475b2;
|
||||||
|
color: #306;
|
||||||
|
font-size: 1.17em;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 3px;
|
||||||
|
font-family: Verdana, Arial, Helvetica, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
margin: 2px 5px;
|
||||||
|
}
|
||||||
|
}
|
25
assets/less/mio/classes/footer.less
Normal file
25
assets/less/mio/classes/footer.less
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
.mio__footer {
|
||||||
|
text-align: center;
|
||||||
|
font-size: .9em;
|
||||||
|
line-height: 1.5em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
|
||||||
|
&__copyright__link {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__links__link {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
margin: 0 2px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
81
assets/less/mio/classes/forum/listing.less
Normal file
81
assets/less/mio/classes/forum/listing.less
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
@mio-forum-listing-mobile: 500px;
|
||||||
|
|
||||||
|
.mio__forum__listing {
|
||||||
|
&__forums {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__entry {
|
||||||
|
display: flex;
|
||||||
|
padding: 2px 0;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
border-bottom: 1px solid #9475b2;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
width: 50px;
|
||||||
|
line-height: 50px;
|
||||||
|
font-size: 2.5em;
|
||||||
|
text-align: center;
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__info {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-size: 1.2em;
|
||||||
|
line-height: 1.5em;
|
||||||
|
color: #306;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__description {
|
||||||
|
font-size: .8em;
|
||||||
|
line-height: 1.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__stats {
|
||||||
|
text-align: right;
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-style: italic;
|
||||||
|
font-family: Verdana, Arial, Helvetica, sans-serif;
|
||||||
|
|
||||||
|
@media (max-width: @mio-forum-listing-mobile) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__topics {
|
||||||
|
font-size: 1.5em;
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__posts {
|
||||||
|
font-size: .9em;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__activity {
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
text-align: right;
|
||||||
|
margin: 0 10px;
|
||||||
|
width: 220px;
|
||||||
|
|
||||||
|
@media (max-width: @mio-forum-listing-mobile) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
90
assets/less/mio/classes/header.less
Normal file
90
assets/less/mio/classes/header.less
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
@mio-header-mobile: 700px;
|
||||||
|
|
||||||
|
.mio__header {
|
||||||
|
display: flex;
|
||||||
|
margin: 4px 0;
|
||||||
|
|
||||||
|
@media (max-width: @mio-header-mobile) {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__logo {
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
&__link {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__image {
|
||||||
|
vertical-align: bottom;
|
||||||
|
|
||||||
|
@media (max-width: @mio-header-mobile) {
|
||||||
|
max-width: 200px;
|
||||||
|
max-height: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__menu {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
@media (max-width: @mio-header-mobile) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__user {
|
||||||
|
border: 1px solid #9475b2;
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
margin: 2px;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__avatar {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__links {
|
||||||
|
text-align: right;
|
||||||
|
list-style: none;
|
||||||
|
margin: 0 2px;
|
||||||
|
line-height: 1.5em;
|
||||||
|
|
||||||
|
&__container {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: @mio-header-mobile) {
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__link {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
display: block;
|
||||||
|
min-width: 70px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: @mio-header-mobile) {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
5
assets/less/mio/classes/heading.less
Normal file
5
assets/less/mio/classes/heading.less
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
.mio__heading {
|
||||||
|
&--1 {
|
||||||
|
line-height: 1.2em;
|
||||||
|
}
|
||||||
|
}
|
29
assets/less/mio/classes/input/button.less
Normal file
29
assets/less/mio/classes/input/button.less
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
.mio__input__button {
|
||||||
|
font-family: 'visitor1';
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 1.25em;
|
||||||
|
color: #fff;
|
||||||
|
background: #9475b2;
|
||||||
|
border: 1px solid #306;
|
||||||
|
box-shadow: inset 0 0 0 1px #643b8c;
|
||||||
|
border-radius: 2px;
|
||||||
|
padding: 1px 10px;
|
||||||
|
transition: background .2s, border-color .2s;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: left;
|
||||||
|
display: inline-block;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
border-color: #407;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #A586c3;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
border-color: #306;
|
||||||
|
background: #8364a1;
|
||||||
|
}
|
||||||
|
}
|
15
assets/less/mio/classes/input/text.less
Normal file
15
assets/less/mio/classes/input/text.less
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
.mio__input__text {
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
padding: 1px;
|
||||||
|
background: #fff;
|
||||||
|
color: #111;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
border-color: #9475b2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mio--dark .mio__input__text {
|
||||||
|
background: #111;
|
||||||
|
color: #fff;
|
||||||
|
}
|
16
assets/less/mio/classes/input/textarea.less
Normal file
16
assets/less/mio/classes/input/textarea.less
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
.mio__input__textarea {
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
padding: 1px;
|
||||||
|
vertical-align: bottom;
|
||||||
|
background: #fff;
|
||||||
|
color: #111;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
border-color: #9475b2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mio--dark .mio__input__textarea {
|
||||||
|
background: #111;
|
||||||
|
color: #fff;
|
||||||
|
}
|
111
assets/less/mio/classes/navigation.less
Normal file
111
assets/less/mio/classes/navigation.less
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
@mio-navigation-mobile: 1000px;
|
||||||
|
|
||||||
|
.mio__navigation {
|
||||||
|
margin: 5px 0;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
border: 0 solid #000;
|
||||||
|
border-top-width: 1px;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
@media (max-width: @mio-navigation-mobile) {
|
||||||
|
border: none;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--top {
|
||||||
|
border-top-width: 0;
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
align-items: flex-end;
|
||||||
|
|
||||||
|
.mio__navigation__option {
|
||||||
|
border-top-width: 1px;
|
||||||
|
border-bottom-width: 0;
|
||||||
|
|
||||||
|
&--selected {
|
||||||
|
top: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__option {
|
||||||
|
list-style: none;
|
||||||
|
background-color: #c9bbcc;
|
||||||
|
border: 1px solid #000;
|
||||||
|
border-top-width: 0;
|
||||||
|
flex-grow: 0;
|
||||||
|
|
||||||
|
@media (max-width: @mio-navigation-mobile) {
|
||||||
|
background-color: #9475b2;
|
||||||
|
width: 100%;
|
||||||
|
border: none;
|
||||||
|
flex-grow: 1;
|
||||||
|
margin-bottom: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:first-child) {
|
||||||
|
border-left-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--selected {
|
||||||
|
background-color: #fbeeff;
|
||||||
|
top: -1px;
|
||||||
|
|
||||||
|
@media (max-width: @mio-navigation-mobile) {
|
||||||
|
background-color: #A586c3;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:first-child) {
|
||||||
|
margin-left: -1px;
|
||||||
|
border-left-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mio__navigation__link {
|
||||||
|
padding: 3px 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__link {
|
||||||
|
display: block;
|
||||||
|
padding: 2px 1em;
|
||||||
|
color: #000;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
@media (max-width: @mio-navigation-mobile) {
|
||||||
|
padding: 10px 15px;
|
||||||
|
color: #306;
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #609;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mio--dark {
|
||||||
|
.mio__navigation,
|
||||||
|
.mio__navigation__option {
|
||||||
|
border-color: #9475b2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mio__navigation__option {
|
||||||
|
background-color: #462e55;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mio__navigation__option--selected {
|
||||||
|
background-color: #23172a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mio__navigation__link {
|
||||||
|
color: #9475b2;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #a586c3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
120
assets/less/mio/classes/profile.less
Normal file
120
assets/less/mio/classes/profile.less
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
@mio-profile-mobile: 700px;
|
||||||
|
|
||||||
|
.mio__profile {
|
||||||
|
&__avatar {
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
|
||||||
|
@media (max-width: @mio-profile-mobile) {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__header {
|
||||||
|
height: 300px;
|
||||||
|
background-color: #fbeeff;
|
||||||
|
background-size: cover;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: 50%;
|
||||||
|
|
||||||
|
@media (max-width: @mio-profile-mobile) {
|
||||||
|
height: auto;
|
||||||
|
background-size: 700px auto;
|
||||||
|
background-position: center top;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
margin: 2px;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
@media (max-width: @mio-profile-mobile) {
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__info {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
@media (max-width: @mio-profile-mobile) {
|
||||||
|
flex-direction: column;
|
||||||
|
background-color: #9475b2;
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__section {
|
||||||
|
margin-right: 2px;
|
||||||
|
|
||||||
|
@media (max-width: @mio-profile-mobile) {
|
||||||
|
margin: 0 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__block {
|
||||||
|
border: 1px solid #9475b2;
|
||||||
|
padding: 2px 4px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
background-color: rgba(251, 238, 255, .9);
|
||||||
|
|
||||||
|
@media (max-width: @mio-profile-mobile) {
|
||||||
|
background-color: #fbeeff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__row {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__column {
|
||||||
|
min-width: 80px;
|
||||||
|
|
||||||
|
@media (max-width: @mio-profile-mobile) {
|
||||||
|
min-width: auto;
|
||||||
|
flex-grow: 1;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--heading {
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
@media (max-width: @mio-profile-mobile) {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--numeric {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--user-title {
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--icons {
|
||||||
|
text-align: center;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--country {
|
||||||
|
font-size: .8em;
|
||||||
|
line-height: 1.4em;
|
||||||
|
width: 110px;
|
||||||
|
text-align: center;
|
||||||
|
align-self: flex-end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
52
assets/less/mio/main.less
Normal file
52
assets/less/mio/main.less
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mio {
|
||||||
|
background-color: #fbeeff;
|
||||||
|
background-image: linear-gradient(180deg, #c2affe, transparent);
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
background-size: 100% 150px;
|
||||||
|
font: 12px/20px Tahoma, Verdana, Arial, Helvetica, sans-serif;
|
||||||
|
color: #000;
|
||||||
|
|
||||||
|
&__wrapper {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--dark {
|
||||||
|
background-color: #23172a;
|
||||||
|
background-image: linear-gradient(180deg, #462e55, transparent);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input elements
|
||||||
|
@import "classes/input/button";
|
||||||
|
@import "classes/input/text";
|
||||||
|
@import "classes/input/textarea";
|
||||||
|
|
||||||
|
// Base styles
|
||||||
|
@import "classes/avatar";
|
||||||
|
@import "classes/container";
|
||||||
|
@import "classes/heading";
|
||||||
|
|
||||||
|
// Specific styles
|
||||||
|
@import "classes/footer";
|
||||||
|
@import "classes/header";
|
||||||
|
@import "classes/navigation";
|
||||||
|
@import "classes/profile";
|
||||||
|
|
||||||
|
// Forums
|
||||||
|
@import "classes/forum/listing";
|
36
build.sh
36
build.sh
|
@ -40,24 +40,24 @@ lessc --verbose $STYLE_DIR/$LESS_ENTRY_FILE $PUBLIC_CSS/$STYLE_NAME.css
|
||||||
echo
|
echo
|
||||||
done
|
done
|
||||||
|
|
||||||
# scripts
|
# scripts (don't need yet, build script gets stuck here bc no files exists)
|
||||||
echo
|
# echo
|
||||||
echo "=> TypeScript"
|
# echo "=> TypeScript"
|
||||||
for SCRIPT_DIR in $ASSETS_TS/*/; do
|
# for SCRIPT_DIR in $ASSETS_TS/*/; do
|
||||||
SCRIPT_NAME=`basename $SCRIPT_DIR`
|
# SCRIPT_NAME=`basename $SCRIPT_DIR`
|
||||||
SCRIPT_NAME_LOWER=`echo $SCRIPT_NAME | tr '[A-Z]' '[a-z]'`
|
# SCRIPT_NAME_LOWER=`echo $SCRIPT_NAME | tr '[A-Z]' '[a-z]'`
|
||||||
echo "==> $SCRIPT_NAME"
|
# echo "==> $SCRIPT_NAME"
|
||||||
find $SCRIPT_DIR -name "*.ts" | xargs tsc \
|
# find $SCRIPT_DIR -name "*.ts" | xargs tsc \
|
||||||
-d \
|
# -d \
|
||||||
-t es5 \
|
# -t es5 \
|
||||||
--listFiles \
|
# --listFiles \
|
||||||
--listEmittedFiles \
|
# --listEmittedFiles \
|
||||||
--noImplicitAny \
|
# --noImplicitAny \
|
||||||
--removeComments \
|
# --removeComments \
|
||||||
--outFile $PUBLIC_JS/$SCRIPT_NAME_LOWER.js
|
# --outFile $PUBLIC_JS/$SCRIPT_NAME_LOWER.js
|
||||||
mv -v $PUBLIC_JS/$SCRIPT_NAME_LOWER.d.ts $ASSETS_TS/$SCRIPT_NAME.d.ts
|
# mv -v $PUBLIC_JS/$SCRIPT_NAME_LOWER.d.ts $ASSETS_TS/$SCRIPT_NAME.d.ts
|
||||||
echo
|
# echo
|
||||||
done
|
# done
|
||||||
|
|
||||||
# node imports
|
# node imports
|
||||||
echo
|
echo
|
||||||
|
|
|
@ -19,36 +19,50 @@ $username_validation_errors = [
|
||||||
];
|
];
|
||||||
|
|
||||||
$mode = $_GET['m'] ?? 'login';
|
$mode = $_GET['m'] ?? 'login';
|
||||||
|
$prevent_registration = $app->config->get('Auth', 'prevent_registration', 'bool', false);
|
||||||
$app->templating->var('auth_mode', $mode);
|
$app->templating->var('auth_mode', $mode);
|
||||||
|
$app->templating->addPath('auth', __DIR__ . '/../views/auth');
|
||||||
|
$app->templating->var('prevent_registration', $prevent_registration);
|
||||||
|
|
||||||
|
if (!empty($_REQUEST['username'])) {
|
||||||
|
$app->templating->var('auth_username', $_REQUEST['username']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($_REQUEST['email'])) {
|
||||||
|
$app->templating->var('auth_email', $_REQUEST['email']);
|
||||||
|
}
|
||||||
|
|
||||||
switch ($mode) {
|
switch ($mode) {
|
||||||
case 'logout':
|
case 'logout':
|
||||||
if ($app->getSession() === null) {
|
if ($app->getSession() === null) {
|
||||||
echo "You aren't logged in.";
|
header('Location: /');
|
||||||
} else {
|
return;
|
||||||
echo "You've been logged out.";
|
}
|
||||||
|
|
||||||
|
// this is temporary, don't scream at me for using md5
|
||||||
|
if (isset($_GET['s']) && md5($app->getSession()->session_key) === $_GET['s']) {
|
||||||
set_cookie_m('uid', '', -3600);
|
set_cookie_m('uid', '', -3600);
|
||||||
set_cookie_m('sid', '', -3600);
|
set_cookie_m('sid', '', -3600);
|
||||||
$app->getSession()->delete();
|
$app->getSession()->delete();
|
||||||
$app->setSession(null);
|
$app->setSession(null);
|
||||||
|
header('Location: /');
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
echo '<meta http-equiv="refresh" content="1; url=/">';
|
echo $app->templating->render('logout');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'login':
|
case 'login':
|
||||||
if ($app->getSession() !== null) {
|
if ($app->getSession() !== null) {
|
||||||
echo '<meta http-equiv="refresh" content="0; url=/">';
|
header('Location: /');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
$auth_login_error = '';
|
||||||
echo $app->templating->render('auth.login');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
while ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
if (!isset($_POST['username'], $_POST['password'])) {
|
if (!isset($_POST['username'], $_POST['password'])) {
|
||||||
echo json_encode_m(['error' => "You didn't fill all the forms!"]);
|
$auth_login_error = "You didn't fill all the forms!";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,12 +72,12 @@ switch ($mode) {
|
||||||
try {
|
try {
|
||||||
$user = User::where('username', $username)->orWhere('email', $username)->firstOrFail();
|
$user = User::where('username', $username)->orWhere('email', $username)->firstOrFail();
|
||||||
} catch (ModelNotFoundException $e) {
|
} catch (ModelNotFoundException $e) {
|
||||||
echo json_encode_m(['error' => 'Invalid username or password!']);
|
$auth_login_error = 'Invalid username or password!';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$user->validatePassword($password)) {
|
if (!$user->validatePassword($password)) {
|
||||||
echo json_encode_m(['error' => 'Invalid username or password!']);
|
$auth_login_error = 'Invalid username or password!';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,30 +95,32 @@ switch ($mode) {
|
||||||
|
|
||||||
setcookie('msz_tmp_id', $user->user_id, time() + 604800, '/', '.flashii.net');
|
setcookie('msz_tmp_id', $user->user_id, time() + 604800, '/', '.flashii.net');
|
||||||
setcookie('msz_tmp_key', $user->user_chat_key, time() + 604800, '/', '.flashii.net');
|
setcookie('msz_tmp_key', $user->user_chat_key, time() + 604800, '/', '.flashii.net');
|
||||||
|
header('Location: /');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
echo json_encode_m(['error' => 'You are now logged in!', 'next' => '/']);
|
if (!empty($auth_login_error)) {
|
||||||
|
$app->templating->var('auth_login_error', $auth_login_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo $app->templating->render('auth');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'register':
|
case 'register':
|
||||||
if ($app->getSession() !== null) {
|
if ($app->getSession() !== null) {
|
||||||
return '<meta http-equiv="refresh" content="0; url=/">';
|
header('Location: /');
|
||||||
}
|
}
|
||||||
|
|
||||||
$prevent_registration = $app->config->get('Auth', 'prevent_registration', 'bool', false);
|
$auth_register_error = '';
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
|
||||||
$app->templating->var('prevent_registration', $prevent_registration);
|
|
||||||
echo $app->templating->render('auth.register');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
while ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
if ($prevent_registration) {
|
if ($prevent_registration) {
|
||||||
echo json_encode_m(['error' => 'Registration is not allowed on this instance.']);
|
$auth_register_error = 'Registration is not allowed on this instance.';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($_POST['username'], $_POST['password'], $_POST['email'])) {
|
if (!isset($_POST['username'], $_POST['password'], $_POST['email'])) {
|
||||||
echo json_encode_m(['error' => "You didn't fill all the forms!"]);
|
$auth_register_error = "You didn't fill all the forms!";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +130,7 @@ switch ($mode) {
|
||||||
$email = $_POST['email'] ?? '';
|
$email = $_POST['email'] ?? '';
|
||||||
|
|
||||||
if ($username_validate !== '') {
|
if ($username_validate !== '') {
|
||||||
echo json_encode_m(['error' => $username_validation_errors[$username_validate]]);
|
$auth_register_error = $username_validation_errors[$username_validate];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,14 +138,14 @@ switch ($mode) {
|
||||||
$existing = User::where('username', $username)->firstOrFail();
|
$existing = User::where('username', $username)->firstOrFail();
|
||||||
|
|
||||||
if ($existing->user_id > 0) {
|
if ($existing->user_id > 0) {
|
||||||
echo json_encode_m(['error' => 'This username is already taken!']);
|
$auth_register_error = 'This username is already taken!';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch (ModelNotFoundException $e) {
|
} catch (ModelNotFoundException $e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL) || !check_mx_record($email)) {
|
if (!filter_var($email, FILTER_VALIDATE_EMAIL) || !check_mx_record($email)) {
|
||||||
echo json_encode_m(['error' => 'The e-mail address you entered is invalid!']);
|
$auth_register_error = 'The e-mail address you entered is invalid!';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,19 +153,26 @@ switch ($mode) {
|
||||||
$existing = User::where('email', $email)->firstOrFail();
|
$existing = User::where('email', $email)->firstOrFail();
|
||||||
|
|
||||||
if ($existing->user_id > 0) {
|
if ($existing->user_id > 0) {
|
||||||
echo json_encode_m(['error' => 'This e-mail address has already been used!']);
|
$auth_register_error = 'This e-mail address has already been used!';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch (ModelNotFoundException $e) {
|
} catch (ModelNotFoundException $e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (password_entropy($password) < 32) {
|
if (password_entropy($password) < 32) {
|
||||||
echo json_encode_m(['error' => 'Your password is too weak!']);
|
$auth_register_error = 'Your password is too weak!';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
User::createUser($username, $password, $email);
|
User::createUser($username, $password, $email);
|
||||||
|
$app->templating->var('auth_register_message', 'Welcome to Flashii! You may now log in.');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
echo json_encode_m(['error' => 'Welcome to Flashii! You may now log in.', 'next' => '/auth.php?m=login']);
|
if (!empty($auth_register_error)) {
|
||||||
|
$app->templating->var('auth_register_error', $auth_register_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo $app->templating->render('auth');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,6 +119,8 @@ class Application extends ApplicationBase
|
||||||
|
|
||||||
$twig->addFilter('json_decode');
|
$twig->addFilter('json_decode');
|
||||||
$twig->addFilter('byte_symbol');
|
$twig->addFilter('byte_symbol');
|
||||||
|
$twig->addFilter('country_name', 'get_country_name');
|
||||||
|
$twig->addFilter('md5'); // using this for logout CSRF for now, remove this when proper CSRF is in place
|
||||||
|
|
||||||
$twig->addFunction('byte_symbol');
|
$twig->addFunction('byte_symbol');
|
||||||
$twig->addFunction('session_id');
|
$twig->addFunction('session_id');
|
||||||
|
@ -128,6 +130,6 @@ class Application extends ApplicationBase
|
||||||
|
|
||||||
$twig->var('app', $this);
|
$twig->var('app', $this);
|
||||||
|
|
||||||
$twig->addPath('nova', __DIR__ . '/../views/nova');
|
$twig->addPath('mio', __DIR__ . '/../views/mio');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ class TemplateEngine
|
||||||
private $vars = [];
|
private $vars = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the twig environment and registers the utility filters and functions.
|
* Creates the twig environment.
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
?string $cache = null,
|
?string $cache = null,
|
||||||
|
|
17
utility.php
17
utility.php
|
@ -113,6 +113,23 @@ function get_country_code(string $ipAddr, string $fallback = 'XX'): string
|
||||||
return $fallback;
|
return $fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function get_country_name(string $code): string
|
||||||
|
{
|
||||||
|
switch (strtolower($code)) {
|
||||||
|
case 'xx':
|
||||||
|
return 'Unknown';
|
||||||
|
|
||||||
|
case 'a1':
|
||||||
|
return 'Anonymous Proxy';
|
||||||
|
|
||||||
|
case 'a2':
|
||||||
|
return 'Satellite Provider';
|
||||||
|
|
||||||
|
default:
|
||||||
|
return locale_get_display_region("-{$code}", 'en');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function is_int_ex($value, int $boundary_low, int $boundary_high): bool
|
function is_int_ex($value, int $boundary_low, int $boundary_high): bool
|
||||||
{
|
{
|
||||||
return is_int($value) && $value >= $boundary_low && $value <= $boundary_high;
|
return is_int($value) && $value >= $boundary_low && $value <= $boundary_high;
|
||||||
|
|
80
views/auth/auth.twig
Normal file
80
views/auth/auth.twig
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
{% extends '@auth/master.twig' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container">
|
||||||
|
<div class="form__wrapper">
|
||||||
|
<input class="form__toggle" id="_authmode_login" type="radio" name="_authmode"{% if auth_mode == 'login' %} checked{% endif %}>
|
||||||
|
<div class="form form--login">
|
||||||
|
<label class="form__title" for="_authmode_login">Login</label>
|
||||||
|
<form class="form__content" method="post" action="?m=login">
|
||||||
|
<label class="form__row">
|
||||||
|
<input class="text text--username" type="text" name="username" placeholder="username" value="{{ auth_username|default('') }}" required>
|
||||||
|
</label>
|
||||||
|
<label class="form__row">
|
||||||
|
<input class="text text--password" type="password" name="password" placeholder="password" required>
|
||||||
|
</label>
|
||||||
|
<div class="form__row form__row--columns">
|
||||||
|
<div class="form__column form__column--message{% if auth_login_error is defined %} form__column--error{% endif %}">
|
||||||
|
{{ auth_login_message|default(auth_login_error|default('')) }}
|
||||||
|
</div>
|
||||||
|
<div class="form__column">
|
||||||
|
<button class="button button--login">Login</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form__wrapper">
|
||||||
|
<input class="form__toggle" id="_authmode_register" type="radio" name="_authmode"{% if auth_mode == 'register' %} checked{% endif %}>
|
||||||
|
<div class="form form-register">
|
||||||
|
<label class="form__title" for="_authmode_register">Create an account</label>
|
||||||
|
{% if prevent_registration|default(false) %}
|
||||||
|
<div class="form__content form__content--no-registration">
|
||||||
|
<p>You're currently using the site via the public testing website, if you want to create an account please do so from the <a class="form__link" href="https://flashii.net/auth.php?m=register" rel="noopener noreferrer">main website</a>.</p>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<form class="form__content" method="post" action="?m=register">
|
||||||
|
<label class="form__row">
|
||||||
|
<input class="text text--username" type="text" name="username" placeholder="username" value="{{ auth_username|default('') }}" required>
|
||||||
|
</label>
|
||||||
|
<label class="form__row">
|
||||||
|
<input class="text text--password" type="password" name="password" placeholder="password" required>
|
||||||
|
</label>
|
||||||
|
<label class="form__row">
|
||||||
|
<input class="text text--email" type="text" name="email" placeholder="e-mail" value="{{ auth_email|default('') }}" required>
|
||||||
|
</label>
|
||||||
|
<div class="form__row form__row--columns">
|
||||||
|
<div class="form__column form__column--message{% if auth_register_error is defined %} form__column--error{% endif %}">
|
||||||
|
{{ auth_register_message|default(auth_register_error|default('')) }}
|
||||||
|
</div>
|
||||||
|
<div class="form__column">
|
||||||
|
<button class="button button--register">Sign up</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{# <div class="form__wrapper">
|
||||||
|
<input class="form__toggle" id="_authmode_restore" type="radio" name="_authmode"{% if auth_mode == 'restore' %} checked{% endif %}>
|
||||||
|
<div class="form form--restore">
|
||||||
|
<label class="form__title" for="_authmode_restore">Forgot login details</label>
|
||||||
|
<form class="form__content" method="post" action="?m=restore">
|
||||||
|
<label class="form__row">
|
||||||
|
<input class="text text--email" type="text" name="email" placeholder="e-mail" value="{{ auth_email|default('') }}" required>
|
||||||
|
</label>
|
||||||
|
<div class="form__row form__row--columns">
|
||||||
|
<div class="form__column form__column--message{% if auth_restore_error is defined %} form__column--error{% endif %}">
|
||||||
|
{{ auth_restore_message|default(auth_restore_error|default('')) }}
|
||||||
|
</div>
|
||||||
|
<div class="form__column">
|
||||||
|
<button class="button button--restore">Send reminder</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div> #}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
13
views/auth/logout.twig
Normal file
13
views/auth/logout.twig
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{% extends '@auth/master.twig' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container logout">
|
||||||
|
<div class="logout__message">
|
||||||
|
<p class="logout__paragraph">We couldn't verify that you were actually the person attempting to log out.</p>
|
||||||
|
<p class="logout__paragraph">Press the button below to verify the logout request, otherwise click back in your browser or close this tab.</p>
|
||||||
|
</div>
|
||||||
|
<div class="logout__buttons">
|
||||||
|
<a href="?m=logout&s={{ app.session.session_key|md5 }}" class="button button--logout">Logout</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
14
views/auth/master.twig
Normal file
14
views/auth/master.twig
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Authentication</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link href="/css/auth.css" rel="stylesheet" type="text/css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="auth">
|
||||||
|
{{ block('content') is defined ? block('content') : '' }}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
21
views/mio/_layout/meta.twig
Normal file
21
views/mio/_layout/meta.twig
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{% set title = title|default('Flashii') %}
|
||||||
|
{% set description = description|default("Where the floor doesn't fall far from the carrot.") %}
|
||||||
|
|
||||||
|
<title>{{ title }}</title>
|
||||||
|
|
||||||
|
<meta name="twitter:title" content="{{ title }}">
|
||||||
|
<meta property="og:title" content="{{ title }}">
|
||||||
|
|
||||||
|
<meta name="description" content="{{ description }}">
|
||||||
|
<meta name="twitter:description" content="{{ description }}">
|
||||||
|
<meta property="og:description" content="{{ description }}">
|
||||||
|
|
||||||
|
<meta name="twitter:card" content="summary">
|
||||||
|
|
||||||
|
<meta property="og:type" content="object">
|
||||||
|
<meta property="og:site_name" content="Flashii">
|
||||||
|
|
||||||
|
{% if icon is defined %}
|
||||||
|
<meta name="twitter:image:src" content="{{ icon }}">
|
||||||
|
<meta property="og:image" content="{{ icon }}">
|
||||||
|
{% endif %}
|
25
views/mio/home/landing.twig
Normal file
25
views/mio/home/landing.twig
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{% extends '@mio/home/master.twig' %}
|
||||||
|
{% from '@mio/macros.twig' import navigation, link %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="mio__container">
|
||||||
|
<div class="mio__container__title">Welcome!</div>
|
||||||
|
<div class="mio__container__content">
|
||||||
|
<p>Welcome to Flashii, the site is still heavily in development. You can follow us on {{ link('https://twitter.com/flashiinet', 'Twitter') }} where we'll post updates every so often, we'll also announce when the site is ready for public use there!</p>
|
||||||
|
{% if app.session == null %}
|
||||||
|
<p>You can <a href="/auth.php?m=register">create an account</a> already though, if you'd like!</p>
|
||||||
|
{% else %}
|
||||||
|
<p>If you want a custom avatar, let me (flash) know and I'll set it for you. The settings page doesn't exist yet..</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="mio__container__title">What happened to the previous design?</div>
|
||||||
|
<div class="mio__container__content">
|
||||||
|
<p>I decided to shelve it for a bit. I'm working on this all by myself and I'm not a designer, so coming up with good designs that flow nicely together isn't easy for me.</p>
|
||||||
|
<p>This layout is a LOT simpler to work with than the other one, so this'll be the main design until later.</p>
|
||||||
|
<p>A dark mode will also be available at a later date and for those that grow attached this to javascript light style, you will eventually be able to switch to this design whenever you like from your settings!</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ navigation(mio_navigation, '/') }}
|
||||||
|
{% endblock %}
|
||||||
|
|
1
views/mio/home/master.twig
Normal file
1
views/mio/home/master.twig
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{% extends '@mio/master.twig' %}
|
16
views/mio/macros.twig
Normal file
16
views/mio/macros.twig
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{% macro link(url, content, class) %}
|
||||||
|
{% spaceless %}
|
||||||
|
<a href="{{ url }}" {% if '://' in url %} target="_blank" rel="noreferrer noopener"{% endif %} {% if class is defined %}class="{{ class }}"{% endif %}>{{ content|raw }}</a>
|
||||||
|
{% endspaceless %}
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% macro navigation(links, current, top) %}
|
||||||
|
{% set top = top|default(false) == true %}
|
||||||
|
{% set current = current|default(null) %}
|
||||||
|
|
||||||
|
<ul class="mio__navigation{% if top %} mio__navigation--top{% endif %}">
|
||||||
|
{% for name, url in links %}
|
||||||
|
<li class="mio__navigation__option{% if url == current or name == current %} mio__navigation__option--selected{% endif %}"><a href="{{ url }}" class="mio__navigation__link">{{ name }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endmacro %}
|
73
views/mio/master.twig
Normal file
73
views/mio/master.twig
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
{% from '@mio/macros.twig' import link, navigation %}
|
||||||
|
|
||||||
|
{% set mio_navigation = {
|
||||||
|
'Home':'/',
|
||||||
|
'Chat':'https://chat.flashii.net',
|
||||||
|
} %}
|
||||||
|
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
{% include '@mio/_layout/meta.twig' %}
|
||||||
|
<link href="https://static.flash.moe/fonts/visitor/visitor1.css" rel="stylesheet">
|
||||||
|
<link href="https://use.fontawesome.com/releases/v5.0.8/css/all.css" rel="stylesheet">
|
||||||
|
<link href="/css/mio.css" rel="stylesheet" type="text/css">
|
||||||
|
</head>
|
||||||
|
<body class="mio">
|
||||||
|
<div class="mio__wrapper">
|
||||||
|
<div class="mio__header">
|
||||||
|
<div class="mio__header__logo">
|
||||||
|
<a href="/" class="mio__header__logo__link">
|
||||||
|
<img class="mio__header__logo__image" src="https://static.flash.moe/logos/logo-exo.png" alt="Flashii">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="mio__header__menu">
|
||||||
|
{% if app.session is not null %}
|
||||||
|
<div class="mio__container mio__header__user">
|
||||||
|
<div class="mio__container__title">Hey, {{ app.session.user.username }}!</div>
|
||||||
|
<div class="mio__container__content mio__header__user__content">
|
||||||
|
<div class="mio__avatar mio__header__user__avatar" style="background-image:url('https://secret.flashii.net/avatar-serve.php?id={{ app.session.user.user_id }}');"></div>
|
||||||
|
<div class="mio__header__user__links__container">
|
||||||
|
<ul class="mio__header__user__links">
|
||||||
|
<li class="mio__header__user__option"><a class="mio__header__user__link" href="/profile.php?u={{ app.session.user.user_id }}">Profile</a></li>
|
||||||
|
<li class="mio__header__user__option"><a class="mio__header__user__link" href="/auth.php?m=logout&s={{ app.session.session_key|md5 }}">Logout</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<a href="/auth.php" class="mio__input__button">Login/Register</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="mio__container">
|
||||||
|
<div class="mio__container__title">Hello!</div>
|
||||||
|
<div class="mio__container__content">
|
||||||
|
This page has no content!
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ navigation(mio_navigation) }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
<div class="mio__footer">
|
||||||
|
<div class="mio__footer__copyright">
|
||||||
|
{{ link('https://flash.moe', 'flash.moe', 'mio__footer__copyright__link') }} 2013-{{
|
||||||
|
''|date('Y') }} /
|
||||||
|
{{ link('https://github.com/flashwave/misuzu/tree/' ~ git_branch(), git_branch(), 'mio__footer__copyright__link') }} # {{ link('https://github.com/flashwave/misuzu/commit/' ~ git_hash(true), git_hash(), 'mio__footer__copyright__link') }}
|
||||||
|
</div>
|
||||||
|
<div class="mio__footer__links">
|
||||||
|
{{ link('#', 'Terms of Service', 'mio__footer__links__link') }}
|
||||||
|
{{ link('#', 'Rules', 'mio__footer__links__link') }}
|
||||||
|
{{ link('#', 'Contact', 'mio__footer__links__link') }}
|
||||||
|
{{ link('#', 'Status', 'mio__footer__links__link') }}
|
||||||
|
{{ link('https://twitter.com/flashiinet', 'Twitter', 'mio__footer__links__link') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
1
views/mio/user/master.twig
Normal file
1
views/mio/user/master.twig
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{% extends '@mio/master.twig' %}
|
42
views/mio/user/view.twig
Normal file
42
views/mio/user/view.twig
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
{% extends '@mio/user/master.twig' %}
|
||||||
|
{% from '@mio/macros.twig' import navigation %}
|
||||||
|
|
||||||
|
{% set title = 'Profile of ' ~ profile.username %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{{ navigation(mio_navigation, false, true) }}
|
||||||
|
|
||||||
|
<div class="mio__profile">
|
||||||
|
<div class="mio__container mio__profile__header">
|
||||||
|
<div class="mio__container__title">Profile of {{ profile.username }}</div>
|
||||||
|
<div class="mio__container__content mio__profile__header__content">
|
||||||
|
<div class="mio__profile__info">
|
||||||
|
<div class="mio__profile__info__section">
|
||||||
|
<div class="mio__profile__info__block">
|
||||||
|
<div class="mio__profile__info__row">
|
||||||
|
<div class="mio__profile__info__column mio__profile__info__column--icons">
|
||||||
|
<img class="mio__profile__icon" src="https://static.flash.moe/flags/fff/{{ profile.user_country|lower }}.png" alt="{{ profile.user_country }}">
|
||||||
|
</div>
|
||||||
|
<div class="mio__profile__info__column mio__profile__info__column--country">
|
||||||
|
{{ profile.user_country|country_name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mio__profile__info__block">
|
||||||
|
<div class="mio__profile__info__row" title="{{ profile.created_at.format('r') }}">
|
||||||
|
<div class="mio__profile__info__column mio__profile__info__column--heading">
|
||||||
|
Joined
|
||||||
|
</div>
|
||||||
|
<div class="mio__profile__info__column">
|
||||||
|
{{ profile.created_at.diffForHumans }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mio__avatar mio__profile__avatar" style="background-image:url('https://secret.flashii.net/avatar-serve.php?id={{ profile.user_id }}');"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -1,25 +0,0 @@
|
||||||
{% extends '@nova/auth/master.twig' %}
|
|
||||||
|
|
||||||
{% set banner_classes = 'banner--large landing__banner' %}
|
|
||||||
|
|
||||||
{% block banner_content %}
|
|
||||||
<h1 style="align-self: center; text-align: left; flex-grow: 1; padding-left: 2em">Welcome back!</h1>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="platform form" id="auth-form">
|
|
||||||
<div>
|
|
||||||
<a href="/auth.php?m=register"><button class="button" type="button">Click here if you don't have an account yet</button></a>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<input class="form__text" type="text" name="username" placeholder="Username">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<input class="form__text" type="password" name="password" placeholder="Password">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<button class="button">Login!</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{ parent() }}
|
|
||||||
{% endblock %}
|
|
|
@ -1,58 +0,0 @@
|
||||||
{% extends '@nova/master.twig' %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<script>
|
|
||||||
var authHttp;
|
|
||||||
|
|
||||||
window.addEventListener('load', function () {
|
|
||||||
var authf = document.getElementById('auth-form');
|
|
||||||
|
|
||||||
if (!authf)
|
|
||||||
return;
|
|
||||||
|
|
||||||
authHttp = new XMLHttpRequest();
|
|
||||||
authHttp.addEventListener('readystatechange', function () {
|
|
||||||
if (authHttp.readyState === 4 && authHttp.status === 200)
|
|
||||||
authfHandle(JSON.parse(authHttp.responseText));
|
|
||||||
});
|
|
||||||
|
|
||||||
authf.addEventListener('keydown', function (e) {
|
|
||||||
if (e.keyCode === 13)
|
|
||||||
authfSubmit();
|
|
||||||
});
|
|
||||||
|
|
||||||
var buttons = document.getElementsByTagName('button');
|
|
||||||
|
|
||||||
buttons[buttons.length - 1].addEventListener('click', function () { authfSubmit(); });
|
|
||||||
});
|
|
||||||
|
|
||||||
function authfHandle(obj)
|
|
||||||
{
|
|
||||||
if (obj.error)
|
|
||||||
alert(obj.error);
|
|
||||||
|
|
||||||
if (obj.next)
|
|
||||||
location.assign(obj.next);
|
|
||||||
}
|
|
||||||
|
|
||||||
function authfSubmit()
|
|
||||||
{
|
|
||||||
authHttp.open('POST', location.pathname + '?m={{ auth_mode }}', true);
|
|
||||||
authHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
|
||||||
authHttp.send(authfForms());
|
|
||||||
}
|
|
||||||
|
|
||||||
function authfForms()
|
|
||||||
{
|
|
||||||
var elems = document.getElementsByTagName('input');
|
|
||||||
var str = "";
|
|
||||||
|
|
||||||
for (var i = 0; i < elems.length; i++) {
|
|
||||||
var elem = elems[i];
|
|
||||||
str += encodeURIComponent(elem.name) + "=" + encodeURIComponent(elem.value) + "&";
|
|
||||||
}
|
|
||||||
|
|
||||||
return str.slice(0, -1);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
|
@ -1,37 +0,0 @@
|
||||||
{% extends '@nova/auth/master.twig' %}
|
|
||||||
|
|
||||||
{% set banner_classes = 'banner--large landing__banner' %}
|
|
||||||
|
|
||||||
{% block banner_content %}
|
|
||||||
<h1 style="align-self: center; text-align: left; flex-grow: 1; padding-left: 2em">
|
|
||||||
{% if not prevent_registration %}
|
|
||||||
Welcome, thanks for dropping by!
|
|
||||||
{% else %}
|
|
||||||
Stop!
|
|
||||||
{% endif %}
|
|
||||||
</h1>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
{% if not prevent_registration %}
|
|
||||||
<div class="platform form" id="auth-form">
|
|
||||||
<div>
|
|
||||||
<input class="form__text" type="text" name="username" placeholder="Username">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<input class="form__text" type="password" name="password" placeholder="Password">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<input class="form__text" type="text" name="email" placeholder="E-mail">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<button class="button">Create your account!</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{ parent() }}
|
|
||||||
{% else %}
|
|
||||||
<div class="platform">
|
|
||||||
<p>You're currently using the site via the public testing end, if you want to create an account please do so from the main website.</p>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
|
|
@ -4,7 +4,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
{% include '@nova/_layout/meta.twig' %}
|
{% include '@nova/_layout/meta.twig' %}
|
||||||
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" type="text/css">
|
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" type="text/css">
|
||||||
<link href="https://fonts.googleapis.com/css?family=Exo+2:200,200italic,300,300italic,400,400italic" rel="stylesheet" type="text/css">
|
<link href="https://fonts.googleapis.com/css?family=Exo+2:200,200italic,300,300italic,400,400italic" rel="stylesheet" type="text/css">
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
<div class="profile__content">
|
<div class="profile__content">
|
||||||
{% spaceless %}
|
{% spaceless %}
|
||||||
<div class="profile__container profile__container--left">
|
<div class="profile__container profile__container--left">
|
||||||
<div class="profile__avatar" style="background-image: url('https://static.flash.moe/images/discord-logo.png');"></div>
|
<div class="profile__avatar" style="background-image: url('https://secret.flashii.net/avatar-serve.php?id={{ profile.user_id }}');"></div>
|
||||||
<div class="platform profile__platform profile__hierarchies">
|
<div class="platform profile__platform profile__hierarchies">
|
||||||
{% for id, data in hierarchies %}
|
{% for id, data in hierarchies %}
|
||||||
{% if data.display %}
|
{% if data.display %}
|
||||||
|
|
Loading…
Add table
Reference in a new issue