Init
This commit is contained in:
56
.htaccess
Normal file
56
.htaccess
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# Enable RewriteEngine
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteBase /
|
||||||
|
|
||||||
|
# RewriteCond %{HTTPS} off
|
||||||
|
# RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
|
||||||
|
|
||||||
|
# Add trailing slash to URLs (except files and directories)
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
|
RewriteCond %{REQUEST_URI} !/$
|
||||||
|
RewriteRule ^(.+)$ $1/ [L,R=301]
|
||||||
|
|
||||||
|
# Handle 404 errors
|
||||||
|
ErrorDocument 404 /404
|
||||||
|
|
||||||
|
# Rewrite pretty URLs to index.php?page=
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
|
RewriteRule ^([^/]+)/$ index.php?page=$1 [L,QSA]
|
||||||
|
|
||||||
|
# Enable GZip compression
|
||||||
|
<IfModule mod_deflate.c>
|
||||||
|
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css
|
||||||
|
AddOutputFilterByType DEFLATE application/javascript application/json
|
||||||
|
AddOutputFilterByType DEFLATE application/xml application/xhtml+xml application/rss+xml
|
||||||
|
AddOutputFilterByType DEFLATE application/font-woff application/font-woff2
|
||||||
|
AddOutputFilterByType DEFLATE image/svg+xml image/webp
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
# Enable browser caching for static assets
|
||||||
|
<IfModule mod_expires.c>
|
||||||
|
ExpiresActive On
|
||||||
|
ExpiresByType image/jpeg "access plus 1 year"
|
||||||
|
ExpiresByType image/png "access plus 1 year"
|
||||||
|
ExpiresByType image/webp "access plus 1 year"
|
||||||
|
ExpiresByType image/svg+xml "access plus 1 year"
|
||||||
|
ExpiresByType text/css "access plus 1 month"
|
||||||
|
ExpiresByType application/javascript "access plus 1 month"
|
||||||
|
ExpiresByType image/x-icon "access plus 1 year"
|
||||||
|
ExpiresByType application/font-woff "access plus 1 year"
|
||||||
|
ExpiresByType application/font-woff2 "access plus 1 year"
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
|
||||||
|
# Prevent directory listing
|
||||||
|
Options -Indexes
|
||||||
|
|
||||||
|
# BEGIN cPanel-generated php ini directives, do not edit
|
||||||
|
<IfModule php8_module>
|
||||||
|
php_value output_buffering Off
|
||||||
|
</IfModule>
|
||||||
|
<IfModule lsapi_module>
|
||||||
|
php_value output_buffering Off
|
||||||
|
</IfModule>
|
||||||
|
# END cPanel-generated php ini directives, do not edit
|
||||||
6
index.php
Normal file
6
index.php
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?php
|
||||||
|
require_once($_SERVER['DOCUMENT_ROOT'] . '/rss/php/pageHandler.php');
|
||||||
|
include($_SERVER['DOCUMENT_ROOT'] . '/rss/php/includes/header.php');
|
||||||
|
loadContents();
|
||||||
|
include($_SERVER['DOCUMENT_ROOT'] . '/rss/php/includes/footer.php');
|
||||||
|
?>
|
||||||
1
robots.txt
Normal file
1
robots.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
User-agent: *
|
||||||
5078
rss/css/main.css
Normal file
5078
rss/css/main.css
Normal file
File diff suppressed because it is too large
Load Diff
1
rss/css/main.css.map
Normal file
1
rss/css/main.css.map
Normal file
File diff suppressed because one or more lines are too long
815
rss/css/main.scss
Normal file
815
rss/css/main.scss
Normal file
@@ -0,0 +1,815 @@
|
|||||||
|
@import 'variables';
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,200..1000;1,200..1000&display=swap');
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,200..1000;1,200..1000&family=Orbitron:wght@400..900&display=swap');
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,200..1000;1,200..1000&family=Orbitron:wght@400..900&family=Roboto:ital,wght@0,100..900;1,100..900&display=swap');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Reset */
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Typography utilities */
|
||||||
|
body {
|
||||||
|
font-family: $font-family-base;
|
||||||
|
// font-family: "Roboto", sans-serif;
|
||||||
|
|
||||||
|
font-size: map-get($font-sizes, base);
|
||||||
|
line-height: map-get($line-heights, normal);
|
||||||
|
color: map-get($colors, dark);
|
||||||
|
background-color: #{map-get($colors, white)};
|
||||||
|
}
|
||||||
|
|
||||||
|
a{
|
||||||
|
all: inherit;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6{
|
||||||
|
font-weight: #{map-get($font-weights, 'light')};
|
||||||
|
// font-size: #{map-get($font-sizes, 'heading')};
|
||||||
|
line-height: #{map-get($line-heights, 'normal')};
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 { font-size: 2.5rem; }
|
||||||
|
h2 { font-size: 2rem; }
|
||||||
|
h3 { font-size: 1.75rem; }
|
||||||
|
h4 { font-size: 1.5rem; }
|
||||||
|
h5 { font-size: 1.25rem; }
|
||||||
|
h6 { font-size: 1rem; }
|
||||||
|
|
||||||
|
|
||||||
|
p{
|
||||||
|
font-weight: #{map-get($font-weights, 'light')};
|
||||||
|
font-size: #{map-get($font-sizes, 'normal')};
|
||||||
|
line-height: #{map-get($line-heights, 'normal')};
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@each $name, $size in $font-sizes {
|
||||||
|
.text-#{$name} {
|
||||||
|
font-size: $size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@each $name, $weight in $font-weights {
|
||||||
|
.fw-#{$name} {
|
||||||
|
font-weight: $weight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@each $name, $lh in $line-heights {
|
||||||
|
.lh-#{$name} {
|
||||||
|
line-height: $lh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, .h1 { font-size: map-get($font-sizes, xxl); line-height: map-get($line-heights, heading); }
|
||||||
|
h2, .h2 { font-size: map-get($font-sizes, xl); line-height: map-get($line-heights, heading); }
|
||||||
|
h3, .h3 { font-size: map-get($font-sizes, lg); line-height: map-get($line-heights, heading); }
|
||||||
|
h4, .h4 { font-size: map-get($font-sizes, base); line-height: map-get($line-heights, heading); }
|
||||||
|
h5, .h5 { font-size: map-get($font-sizes, sm); line-height: map-get($line-heights, heading); }
|
||||||
|
h6, .h6 { font-size: map-get($font-sizes, xs); line-height: map-get($line-heights, heading); }
|
||||||
|
|
||||||
|
|
||||||
|
/* Container */
|
||||||
|
.container {
|
||||||
|
width: 100%;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-left: auto;
|
||||||
|
padding-right: $container-padding;
|
||||||
|
padding-left: $container-padding;
|
||||||
|
|
||||||
|
@each $breakpoint, $container-max-width in $container-max-widths {
|
||||||
|
@media (min-width: map-get($breakpoints, $breakpoint)) {
|
||||||
|
max-width: $container-max-width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Display utilities */
|
||||||
|
@each $type in $display-types {
|
||||||
|
.d-#{$type} {
|
||||||
|
display: $type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Color utilities */
|
||||||
|
@each $name, $color in $colors {
|
||||||
|
.text-#{$name} { color: $color !important; }
|
||||||
|
.bg-#{$name} { background-color: $color !important; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Margin and padding utilities */
|
||||||
|
@for $i from 0 through length($spacing-scale) - 1 {
|
||||||
|
$value: nth($spacing-scale, $i + 1);
|
||||||
|
|
||||||
|
.m-#{$i} { margin: $value !important; }
|
||||||
|
.p-#{$i} { padding: $value !important; }
|
||||||
|
|
||||||
|
.mt-#{$i} { margin-top: $value !important; }
|
||||||
|
.mb-#{$i} { margin-bottom: $value !important; }
|
||||||
|
.ml-#{$i} { margin-left: $value !important; }
|
||||||
|
.mr-#{$i} { margin-right: $value !important; }
|
||||||
|
|
||||||
|
.pt-#{$i} { padding-top: $value !important; }
|
||||||
|
.pb-#{$i} { padding-bottom: $value !important; }
|
||||||
|
.pl-#{$i} { padding-left: $value !important; }
|
||||||
|
.pr-#{$i} { padding-right: $value !important; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grid system */
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-right: -$container-padding;
|
||||||
|
margin-left: -$container-padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col {
|
||||||
|
flex: 1 0 0%;
|
||||||
|
padding-right: $container-padding;
|
||||||
|
padding-left: $container-padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-auto {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
width: auto;
|
||||||
|
padding-right: $container-padding;
|
||||||
|
padding-left: $container-padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
@for $i from 1 through $grid-columns {
|
||||||
|
.col-#{$i} {
|
||||||
|
flex: 0 0 percentage($i / $grid-columns);
|
||||||
|
max-width: percentage($i / $grid-columns);
|
||||||
|
padding-right: $container-padding;
|
||||||
|
padding-left: $container-padding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@each $breakpoint, $breakpoint-width in $breakpoints {
|
||||||
|
@media (min-width: $breakpoint-width) {
|
||||||
|
.col-#{$breakpoint} {
|
||||||
|
flex: 1 0 0%;
|
||||||
|
padding-right: $container-padding;
|
||||||
|
padding-left: $container-padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-#{$breakpoint}-auto {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
width: auto;
|
||||||
|
padding-right: $container-padding;
|
||||||
|
padding-left: $container-padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
@for $i from 1 through $grid-columns {
|
||||||
|
.col-#{$breakpoint}-#{$i} {
|
||||||
|
flex: 0 0 percentage($i / $grid-columns);
|
||||||
|
max-width: percentage($i / $grid-columns);
|
||||||
|
padding-right: $container-padding;
|
||||||
|
padding-left: $container-padding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Gutter utilities with .g-X */
|
||||||
|
.row {
|
||||||
|
margin-right: -#{map-get($gutters, 3)}; /* Default 1rem gutter */
|
||||||
|
margin-left: -#{map-get($gutters, 3)};
|
||||||
|
margin-top: -#{map-get($gutters, 3)}; /* Vertical gutter */
|
||||||
|
margin-bottom: -#{map-get($gutters, 3)};
|
||||||
|
}
|
||||||
|
|
||||||
|
.col {
|
||||||
|
padding-right: #{map-get($gutters, 3)}; /* Default 1rem padding */
|
||||||
|
padding-left: #{map-get($gutters, 3)};
|
||||||
|
padding-top: #{map-get($gutters, 3)}; /* Vertical padding */
|
||||||
|
padding-bottom: #{map-get($gutters, 3)};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Variable gutter classes */
|
||||||
|
@for $i from 0 through length($gutters) - 1 {
|
||||||
|
$gutter-value: map-get($gutters, $i);
|
||||||
|
.g-#{$i} {
|
||||||
|
margin-right: -$gutter-value;
|
||||||
|
margin-left: -$gutter-value;
|
||||||
|
margin-top: -$gutter-value;
|
||||||
|
margin-bottom: -$gutter-value;
|
||||||
|
}
|
||||||
|
.col {
|
||||||
|
&.g-#{$i} {
|
||||||
|
padding-right: $gutter-value;
|
||||||
|
padding-left: $gutter-value;
|
||||||
|
padding-top: $gutter-value;
|
||||||
|
padding-bottom: $gutter-value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive gutter classes */
|
||||||
|
@each $breakpoint, $breakpoint-width in $breakpoints {
|
||||||
|
@media (min-width: $breakpoint-width) {
|
||||||
|
@for $i from 0 through length($gutters) - 1 {
|
||||||
|
$gutter-value: map-get($gutters, $i);
|
||||||
|
.#{$breakpoint}-g-#{$i} {
|
||||||
|
margin-right: -$gutter-value;
|
||||||
|
margin-left: -$gutter-value;
|
||||||
|
margin-top: -$gutter-value;
|
||||||
|
margin-bottom: -$gutter-value;
|
||||||
|
}
|
||||||
|
.#{$breakpoint}-col {
|
||||||
|
&.g-#{$i} {
|
||||||
|
padding-right: $gutter-value;
|
||||||
|
padding-left: $gutter-value;
|
||||||
|
padding-top: $gutter-value;
|
||||||
|
padding-bottom: $gutter-value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shadow utilities */
|
||||||
|
@each $key, $shadow in $shadows {
|
||||||
|
.shadow-#{$key} {
|
||||||
|
box-shadow: #{$shadow} !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@each $key, $shadow in $drop-shadows {
|
||||||
|
.drop-shadow-#{$key} {
|
||||||
|
box-shadow: #{$shadow};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flex utilities */
|
||||||
|
@each $key, $value in $flex-directions {
|
||||||
|
.flex-#{$key} {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@each $key, $value in $justify-content-values {
|
||||||
|
.justify-#{$key} {
|
||||||
|
display: flex;
|
||||||
|
justify-content: $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@each $key, $value in $align-items-values {
|
||||||
|
.align-#{$key} {
|
||||||
|
display: flex;
|
||||||
|
align-items: $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Card component */
|
||||||
|
.card {
|
||||||
|
background-color: map-get($colors, white);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
box-shadow: map-get($shadows, 3);
|
||||||
|
transition: box-shadow 0.3s ease;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.card-header{
|
||||||
|
padding: 0.4rem;
|
||||||
|
|
||||||
|
&.theme-header{
|
||||||
|
background-color: #{map-get($colors, 'dark')} !important;
|
||||||
|
color: #{map-get($colors, primary-alt)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.card-body{
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.card-hover{
|
||||||
|
&:hover {
|
||||||
|
box-shadow: map-get($shadows, 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Button base */
|
||||||
|
.btn {
|
||||||
|
all: unset;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0.45rem 0.9rem;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 600;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
transition:
|
||||||
|
background-color 0.25s ease,
|
||||||
|
color 0.25s ease,
|
||||||
|
box-shadow 0.25s ease,
|
||||||
|
transform 0.1s ease;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
|
line-height: 1.2;
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
outline: 2px solid transparent;
|
||||||
|
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: translateY(1px);
|
||||||
|
box-shadow: 0 0 6px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: 0.6;
|
||||||
|
cursor: not-allowed;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flat variant
|
||||||
|
&.flat {
|
||||||
|
box-shadow: none;
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Background color variants
|
||||||
|
&.primary {
|
||||||
|
background-color: map-get($colors, primary);
|
||||||
|
color: map-get($colors, white);
|
||||||
|
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
background-color: darken(map-get($colors, primary), 7%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.secondary {
|
||||||
|
background-color: map-get($colors, secondary);
|
||||||
|
color: map-get($colors, white);
|
||||||
|
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
background-color: darken(map-get($colors, secondary), 7%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.danger {
|
||||||
|
background-color: map-get($colors, danger);
|
||||||
|
color: map-get($colors, white);
|
||||||
|
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
background-color: darken(map-get($colors, danger), 7%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Filled buttons */
|
||||||
|
@each $name, $color in $colors {
|
||||||
|
.btn-#{$name} {
|
||||||
|
background-color: $color;
|
||||||
|
color: if(lightness($color) > 60%, #212529, #fff);
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: darken($color, 8%);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
box-shadow: 0 0 0 3px rgba($color, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: 0.6;
|
||||||
|
cursor: not-allowed;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Outline buttons */
|
||||||
|
@each $name, $color in $colors {
|
||||||
|
.btn-outline-#{$name} {
|
||||||
|
background-color: transparent;
|
||||||
|
border: 2px solid $color;
|
||||||
|
color: $color;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $color;
|
||||||
|
color: if(lightness($color) > 60%, #212529, #fff);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
box-shadow: 0 0 0 3px rgba($color, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: 0.6;
|
||||||
|
cursor: not-allowed;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ghost buttons */
|
||||||
|
@each $name, $color in $colors {
|
||||||
|
.btn-ghost-#{$name} {
|
||||||
|
background-color: transparent;
|
||||||
|
color: $color;
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba($color, 0.1);
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
box-shadow: 0 0 0 3px rgba($color, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: 0.6;
|
||||||
|
cursor: not-allowed;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Borders
|
||||||
|
@each $key, $width in $border-widths {
|
||||||
|
.border-#{$key} {
|
||||||
|
border: #{$width} solid currentColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.border {
|
||||||
|
border: 1px solid currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-top { border-top: 1px solid currentColor; }
|
||||||
|
.border-bottom { border-bottom: 1px solid currentColor; }
|
||||||
|
.border-left { border-left: 1px solid currentColor; }
|
||||||
|
.border-right { border-right: 1px solid currentColor; }
|
||||||
|
|
||||||
|
// Border radius
|
||||||
|
@each $key, $radius in $border-radius-sizes {
|
||||||
|
.rounded-#{$key} {
|
||||||
|
border-radius: $radius;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.rounded { border-radius: 0.25rem; } // default
|
||||||
|
.rounded-top { border-top-left-radius: 0.25rem; border-top-right-radius: 0.25rem; }
|
||||||
|
.rounded-bottom{ border-bottom-left-radius: 0.25rem; border-bottom-right-radius: 0.25rem; }
|
||||||
|
.rounded-left { border-top-left-radius: 0.25rem; border-bottom-left-radius: 0.25rem; }
|
||||||
|
.rounded-right { border-top-right-radius: 0.25rem; border-bottom-right-radius: 0.25rem; }
|
||||||
|
|
||||||
|
|
||||||
|
// Margin utilities for all directions
|
||||||
|
@for $i from 0 through length($spacing-scale) - 1 {
|
||||||
|
$value: nth($spacing-scale, $i + 1);
|
||||||
|
|
||||||
|
.ms-#{$i} { margin-left: $value; }
|
||||||
|
.me-#{$i} { margin-right: $value; }
|
||||||
|
.mt-#{$i} { margin-top: $value; }
|
||||||
|
.mb-#{$i} { margin-bottom: $value; }
|
||||||
|
|
||||||
|
.mx-#{$i} { margin-left: $value; margin-right: $value; }
|
||||||
|
.my-#{$i} { margin-top: $value; margin-bottom: $value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Padding utilities for all directions
|
||||||
|
@for $i from 0 through length($spacing-scale) - 1 {
|
||||||
|
$value: nth($spacing-scale, $i + 1);
|
||||||
|
|
||||||
|
.ps-#{$i} { padding-left: $value; }
|
||||||
|
.pe-#{$i} { padding-right: $value; }
|
||||||
|
.pt-#{$i} { padding-top: $value; }
|
||||||
|
.pb-#{$i} { padding-bottom: $value; }
|
||||||
|
|
||||||
|
.px-#{$i} { padding-left: $value; padding-right: $value; }
|
||||||
|
.py-#{$i} { padding-top: $value; padding-bottom: $value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Responsive Margin and Padding
|
||||||
|
@each $breakpoint, $breakpoint-width in $breakpoints {
|
||||||
|
@media (min-width: $breakpoint-width) {
|
||||||
|
@for $i from 0 through length($spacing-scale) - 1 {
|
||||||
|
$value: nth($spacing-scale, $i + 1);
|
||||||
|
|
||||||
|
.#{$breakpoint}-ms-#{$i} { margin-left: $value; }
|
||||||
|
.#{$breakpoint}-me-#{$i} { margin-right: $value; }
|
||||||
|
.#{$breakpoint}-mt-#{$i} { margin-top: $value; }
|
||||||
|
.#{$breakpoint}-mb-#{$i} { margin-bottom: $value; }
|
||||||
|
|
||||||
|
.#{$breakpoint}-mx-#{$i} { margin-left: $value; margin-right: $value; }
|
||||||
|
.#{$breakpoint}-my-#{$i} { margin-top: $value; margin-bottom: $value; }
|
||||||
|
|
||||||
|
.#{$breakpoint}-ps-#{$i} { padding-left: $value; }
|
||||||
|
.#{$breakpoint}-pe-#{$i} { padding-right: $value; }
|
||||||
|
.#{$breakpoint}-pt-#{$i} { padding-top: $value; }
|
||||||
|
.#{$breakpoint}-pb-#{$i} { padding-bottom: $value; }
|
||||||
|
|
||||||
|
.#{$breakpoint}-px-#{$i} { padding-left: $value; padding-right: $value; }
|
||||||
|
.#{$breakpoint}-py-#{$i} { padding-top: $value; padding-bottom: $value; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Text alignment utilities
|
||||||
|
.text-left { text-align: left; }
|
||||||
|
.text-center { text-align: center; }
|
||||||
|
.text-right { text-align: right; }
|
||||||
|
|
||||||
|
// Text transformation utilities
|
||||||
|
.text-uppercase { text-transform: uppercase; }
|
||||||
|
.text-lowercase { text-transform: lowercase; }
|
||||||
|
.text-capitalize { text-transform: capitalize; }
|
||||||
|
|
||||||
|
// Font weight utilities
|
||||||
|
.font-weight-light { font-weight: 300; }
|
||||||
|
.font-weight-normal { font-weight: 400; }
|
||||||
|
.font-weight-bold { font-weight: 700; }
|
||||||
|
.font-weight-heavy { font-weight: 900; }
|
||||||
|
|
||||||
|
// Text decoration utilities
|
||||||
|
.text-underline { text-decoration: underline; }
|
||||||
|
.text-line-through { text-decoration: line-through; }
|
||||||
|
.text-no-decoration { text-decoration: none; }
|
||||||
|
|
||||||
|
// Image sizing utilities
|
||||||
|
.img-w-100 { width: 100%; }
|
||||||
|
.img-w-auto { width: auto; }
|
||||||
|
.img-w-50 { width: 50%; }
|
||||||
|
.img-w-75 { width: 75%; }
|
||||||
|
.img-w-25 { width: 25%; }
|
||||||
|
|
||||||
|
.img-h-100 { height: 100%; }
|
||||||
|
.img-h-auto { height: auto; }
|
||||||
|
.img-h-50 { height: 50%; }
|
||||||
|
.img-h-75 { height: 75%; }
|
||||||
|
|
||||||
|
.img-max-w-100 { max-width: 100%; }
|
||||||
|
.img-max-w-50 { max-width: 50%; }
|
||||||
|
.img-max-h-100 { max-height: 100%; }
|
||||||
|
.img-max-h-50 { max-height: 50%; }
|
||||||
|
|
||||||
|
.image-container{
|
||||||
|
position: relative;
|
||||||
|
max-width: 100%;
|
||||||
|
width:100%;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
img{
|
||||||
|
width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aspect ratio utilities (for common ratios)
|
||||||
|
.img-aspect-ratio-16-9 {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 0;
|
||||||
|
padding-bottom: 56.25%; // 16:9 aspect ratio
|
||||||
|
|
||||||
|
img{
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-aspect-ratio-4-3 {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 0;
|
||||||
|
padding-bottom: 75%; // 4:3 aspect ratio
|
||||||
|
|
||||||
|
img{
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-aspect-ratio-1-1 {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 0;
|
||||||
|
padding-bottom: 100%; // 1:1 aspect ratio (square)
|
||||||
|
|
||||||
|
img{
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Image border radius utilities
|
||||||
|
.img-rounded { border-radius: 0.25rem; }
|
||||||
|
.img-rounded-sm { border-radius: 0.125rem; }
|
||||||
|
.img-rounded-md { border-radius: 0.375rem; }
|
||||||
|
.img-rounded-lg { border-radius: 2rem; }
|
||||||
|
.img-rounded-full { border-radius: 50%; }
|
||||||
|
|
||||||
|
// Image border utilities
|
||||||
|
.img-border { border: 1px solid #ddd; }
|
||||||
|
.img-border-2 { border: 2px solid #ddd; }
|
||||||
|
.img-border-3 { border: 3px solid #ddd; }
|
||||||
|
.img-border-0 { border: none; }
|
||||||
|
|
||||||
|
// Image filters
|
||||||
|
.img-filter-blur {
|
||||||
|
filter: blur(4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-filter-grayscale {
|
||||||
|
filter: grayscale(100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-filter-brightness {
|
||||||
|
filter: brightness(1.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-filter-contrast {
|
||||||
|
filter: contrast(1.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-filter-sepia {
|
||||||
|
filter: sepia(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-filter-invert {
|
||||||
|
filter: invert(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-filter-saturate {
|
||||||
|
filter: saturate(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Image alignment utilities
|
||||||
|
.img-align-left { display: block; margin-right: auto; }
|
||||||
|
.img-align-right { display: block; margin-left: auto; }
|
||||||
|
.img-align-center { display: block; margin-left: auto; margin-right: auto; }
|
||||||
|
|
||||||
|
.img-align-start { align-self: flex-start; }
|
||||||
|
.img-align-end { align-self: flex-end; }
|
||||||
|
.img-align-center-flex { align-self: center; }
|
||||||
|
|
||||||
|
// Responsive images with max-width and auto height
|
||||||
|
.img-responsive {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Form Inputs */
|
||||||
|
.form-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.25rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-input,
|
||||||
|
select,
|
||||||
|
textarea,
|
||||||
|
input[type="text"],
|
||||||
|
input[type="email"],
|
||||||
|
input[type="password"],
|
||||||
|
input[type="number"] {
|
||||||
|
appearance: none;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.35rem 0.75rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-family: inherit;
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
box-shadow: none;
|
||||||
|
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
border: 1px solid;
|
||||||
|
outline: none;
|
||||||
|
border-color: map-get($colors, muted);
|
||||||
|
color: map-get($colors, secondary);
|
||||||
|
background-color: #fdfdfd;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: map-get($colors, primary);
|
||||||
|
box-shadow: 0 0 0 3px rgba(map-get($colors, primary), 0.2);
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
background-color: map-get($colors, light);
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::placeholder {
|
||||||
|
color: map-get($colors, gray);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sm-reverse{
|
||||||
|
@media (max-width: map-get($breakpoints, "md")) {
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.rel{
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-height{
|
||||||
|
height: calc(100vh - 52px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-wrap{
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-click{
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Alert */
|
||||||
|
.alert {
|
||||||
|
border-radius: #{map-get($border-radius-sizes, md)};
|
||||||
|
padding: #{map-get($spacing, "2")};
|
||||||
|
|
||||||
|
&.success {
|
||||||
|
background-color: lighten(map-get($colors, success), 25%);
|
||||||
|
color: #{map-get($colors, success)};
|
||||||
|
}
|
||||||
|
|
||||||
|
&.warning {
|
||||||
|
background-color: lighten(map-get($colors, warning), 25%);
|
||||||
|
color: #{map-get($colors, warning)};
|
||||||
|
}
|
||||||
|
|
||||||
|
&.danger {
|
||||||
|
background-color: lighten(map-get($colors, danger), 25%);
|
||||||
|
color: #{map-get($colors, danger)};
|
||||||
|
}
|
||||||
|
|
||||||
|
&.info {
|
||||||
|
background-color: lighten(map-get($colors, info), 25%);
|
||||||
|
color: #{map-get($colors, info)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Misc tools */
|
||||||
|
.spinner {
|
||||||
|
height: 1rem;
|
||||||
|
width: 1rem;
|
||||||
|
border: 2px solid #{map-get($colors, dark)};
|
||||||
|
border-left-color: transparent !important;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: inline-block;
|
||||||
|
animation: 1s linear infinite spinner;
|
||||||
|
|
||||||
|
&.primary {
|
||||||
|
border: 2px solid #{map-get($colors, primary)};
|
||||||
|
}
|
||||||
|
|
||||||
|
&.secondary {
|
||||||
|
border: 2px solid #{map-get($colors, secondary)};
|
||||||
|
}
|
||||||
|
|
||||||
|
&.accent {
|
||||||
|
border: 2px solid #{map-get($colors, accent)};
|
||||||
|
}
|
||||||
|
}
|
||||||
1
rss/css/theme.scss
Normal file
1
rss/css/theme.scss
Normal file
@@ -0,0 +1 @@
|
|||||||
|
@import 'variables';
|
||||||
9
rss/css/variables.css
Normal file
9
rss/css/variables.css
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
/* Grid system */
|
||||||
|
/* Breakpoints */
|
||||||
|
/* Display types */
|
||||||
|
/* Color palette */
|
||||||
|
/* Spacing scale */
|
||||||
|
/* Shadows (soft shadows) */
|
||||||
|
/* Flex utilities */
|
||||||
|
/* Button component variables */
|
||||||
|
/* Typography *//*# sourceMappingURL=variables.css.map */
|
||||||
1
rss/css/variables.css.map
Normal file
1
rss/css/variables.css.map
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"sources":["variables.scss"],"names":[],"mappings":"AAAA,gBAAA;AAIA,gBAAA;AAmBA,kBAAA;AAGA,kBAAA;AAoBA,kBAAA;AAGA,2BAAA;AAoBA,mBAAA;AAyBA,+BAAA;AAQA,eAAA","file":"variables.css"}
|
||||||
165
rss/css/variables.scss
Normal file
165
rss/css/variables.scss
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
/* Grid system */
|
||||||
|
$container-padding: 1rem;
|
||||||
|
$grid-columns: 12;
|
||||||
|
|
||||||
|
/* Breakpoints */
|
||||||
|
$breakpoints: (
|
||||||
|
sm: 576px,
|
||||||
|
md: 768px,
|
||||||
|
lg: 992px,
|
||||||
|
xl: 1200px,
|
||||||
|
xxl: 1400px,
|
||||||
|
xxxl: 1600px
|
||||||
|
);
|
||||||
|
|
||||||
|
$container-max-widths: (
|
||||||
|
sm: 540px,
|
||||||
|
md: 720px,
|
||||||
|
lg: 960px,
|
||||||
|
xl: 1140px,
|
||||||
|
xxl: 1320px,
|
||||||
|
xxxl: 1520px
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Display types */
|
||||||
|
$display-types: block, flex, inline, inline-block, inline-flex, grid, none;
|
||||||
|
|
||||||
|
/* Color palette */
|
||||||
|
$colors: (
|
||||||
|
primary: #0981b1,
|
||||||
|
primary-alt: #0981b1b6,
|
||||||
|
alt: #0981b1b6,
|
||||||
|
secondary: #333,
|
||||||
|
success: #34b97b,
|
||||||
|
warning: #ffc107,
|
||||||
|
danger: #dc3545,
|
||||||
|
info: #0dcaf0,
|
||||||
|
light: #e5e5e5,
|
||||||
|
dark: #212529,
|
||||||
|
white: #ffffff,
|
||||||
|
black: #000000,
|
||||||
|
muted: #C7C7C7,
|
||||||
|
accent-white: #f7f7f7,
|
||||||
|
accent: #0ed884,
|
||||||
|
transparent: transparent
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Spacing scale */
|
||||||
|
$spacing-scale: 0, 0.25rem, 0.5rem, 1rem, 1.5rem, 3rem;
|
||||||
|
|
||||||
|
/* Shadows (soft shadows) */
|
||||||
|
$shadows: (
|
||||||
|
1: 0 1px 3px rgba(0, 0, 0, 0.12),
|
||||||
|
2: 0 2px 6px rgba(0, 0, 0, 0.16),
|
||||||
|
3: 0 4px 10px rgba(0, 0, 0, 0.18),
|
||||||
|
4: 0 6px 15px rgba(0, 0, 0, 0.20),
|
||||||
|
5: 0 10px 24px rgba(0, 0, 0, 0.22)
|
||||||
|
);
|
||||||
|
|
||||||
|
$drop-shadows: (
|
||||||
|
1: 0 2px 4px rgba(0, 0, 0, 0.14),
|
||||||
|
2: 0 4px 8px rgba(0, 0, 0, 0.18),
|
||||||
|
3: 0 8px 16px rgba(0, 0, 0, 0.20),
|
||||||
|
4: 0 12px 24px rgba(0, 0, 0, 0.22),
|
||||||
|
5: 0 20px 40px rgba(0, 0, 0, 0.24)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Flex utilities */
|
||||||
|
$flex-directions: (
|
||||||
|
row: row,
|
||||||
|
row-reverse: row-reverse,
|
||||||
|
column: column,
|
||||||
|
column-reverse: column-reverse
|
||||||
|
);
|
||||||
|
|
||||||
|
$justify-content-values: (
|
||||||
|
start: flex-start,
|
||||||
|
end: flex-end,
|
||||||
|
center: center,
|
||||||
|
between: space-between,
|
||||||
|
around: space-around,
|
||||||
|
evenly: space-evenly
|
||||||
|
);
|
||||||
|
|
||||||
|
$align-items-values: (
|
||||||
|
start: flex-start,
|
||||||
|
end: flex-end,
|
||||||
|
center: center,
|
||||||
|
baseline: baseline,
|
||||||
|
stretch: stretch
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Button component variables */
|
||||||
|
$btn-padding-y: 0.375rem;
|
||||||
|
$btn-padding-x: 0.75rem;
|
||||||
|
$btn-font-size: 1rem;
|
||||||
|
$btn-border-radius: 0.25rem;
|
||||||
|
$btn-border-width: 1px;
|
||||||
|
$btn-hover-brightness: 0.9;
|
||||||
|
|
||||||
|
/* Typography */
|
||||||
|
$font-family-base: "Nunito", sans-serif;
|
||||||
|
$font-family-monospace: Menlo, Monaco, Consolas, 'Courier New', monospace;
|
||||||
|
|
||||||
|
$font-sizes: (
|
||||||
|
xs: 0.75rem,
|
||||||
|
sm: 0.875rem,
|
||||||
|
base: 1.1rem,
|
||||||
|
lg: 1.35rem,
|
||||||
|
xl: 1.8rem,
|
||||||
|
xxl: 2.2rem
|
||||||
|
);
|
||||||
|
|
||||||
|
$font-weights: (
|
||||||
|
light: 300,
|
||||||
|
normal: 400,
|
||||||
|
medium: 500,
|
||||||
|
semibold: 600,
|
||||||
|
bold: 700
|
||||||
|
);
|
||||||
|
|
||||||
|
$line-heights: (
|
||||||
|
tight: 1,
|
||||||
|
normal: 1.3,
|
||||||
|
heading: 1.5
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
$border-widths: (
|
||||||
|
0: 0,
|
||||||
|
1: 1px,
|
||||||
|
2: 2px,
|
||||||
|
3: 3px
|
||||||
|
);
|
||||||
|
|
||||||
|
$border-radius-sizes: (
|
||||||
|
none: 0,
|
||||||
|
sm: 0.125rem,
|
||||||
|
md: 0.25rem,
|
||||||
|
lg: 0.5rem,
|
||||||
|
xl: 1rem,
|
||||||
|
full: 9999px
|
||||||
|
);
|
||||||
|
|
||||||
|
$spacer: 1rem;
|
||||||
|
$spacing: (
|
||||||
|
"0": 0,
|
||||||
|
"1": $spacer * 0.25,
|
||||||
|
"2": $spacer * 0.5,
|
||||||
|
"3": $spacer,
|
||||||
|
"4": $spacer * 1.5,
|
||||||
|
"5": $spacer * 3
|
||||||
|
);
|
||||||
|
|
||||||
|
$gutters: (
|
||||||
|
0: 0,
|
||||||
|
1: map-get($spacing, "1"),
|
||||||
|
2: map-get($spacing, "2"),
|
||||||
|
3: map-get($spacing, "3"),
|
||||||
|
4: map-get($spacing, "4"),
|
||||||
|
5: map-get($spacing, "5")
|
||||||
|
);
|
||||||
0
rss/js/index.js
Normal file
0
rss/js/index.js
Normal file
76
rss/js/main.js
Normal file
76
rss/js/main.js
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
async function _post(formObj, target, func){
|
||||||
|
try{
|
||||||
|
const form = await createFormData(formObj, target, func)
|
||||||
|
const respJson = await fetch('/rss/php/handler.php', {
|
||||||
|
method: 'POST',
|
||||||
|
body: form
|
||||||
|
});
|
||||||
|
|
||||||
|
if(respJson){
|
||||||
|
return await(respJson.json());
|
||||||
|
}else{
|
||||||
|
return 'Error';
|
||||||
|
}
|
||||||
|
}catch(errno){
|
||||||
|
console.log('Post failed');
|
||||||
|
console.log(errno)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createFormData(data, target, func){
|
||||||
|
const formData = new FormData();
|
||||||
|
try{
|
||||||
|
for(const key in data){
|
||||||
|
if(data.hasOwnProperty(key)){
|
||||||
|
formData.append(key, data[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
formData.append('target', target);
|
||||||
|
formData.append('function', func)
|
||||||
|
}catch(errno){
|
||||||
|
console.log('Incorrect use of object');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return formData;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createEl(el, classArr = null, elText = null, dtSet = null){
|
||||||
|
const element = document.createElement(el);
|
||||||
|
if(elText){
|
||||||
|
element.appendChild(document.createTextNode(elText));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(classArr && classArr.length){
|
||||||
|
element.classList.add(...classArr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dtSet && Object.keys(dtSet).length){
|
||||||
|
for(const [data, value] of Object.entries(dtSet)){
|
||||||
|
element.dataset[data] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getRandomID(){
|
||||||
|
return Math.random().toString(36).replace('0.', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function generateAlert(type, text){
|
||||||
|
const alert = document.createElement('div');
|
||||||
|
alert.classList.add('alert');
|
||||||
|
alert.classList.add(type);
|
||||||
|
alert.appendChild(document.createTextNode(text));
|
||||||
|
return alert;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function removeAlert(){
|
||||||
|
const alerts = document.querySelectorAll('.alert');
|
||||||
|
if(alerts && alerts.length){
|
||||||
|
for(const alert of alerts){
|
||||||
|
alert.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
9
rss/json/pages/index.json
Normal file
9
rss/json/pages/index.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"title": "ECUSM",
|
||||||
|
"long_desc": "",
|
||||||
|
"short_desc": "",
|
||||||
|
"template": "",
|
||||||
|
"restricted": false,
|
||||||
|
"redirect_login": false,
|
||||||
|
"robots": "noindex, nofollow"
|
||||||
|
}
|
||||||
11
rss/php/autoload.php
Normal file
11
rss/php/autoload.php
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
spl_autoload_register(function ($class){
|
||||||
|
$class = str_replace('App\\', '', $class);
|
||||||
|
$class = str_replace('\\', '/', $class);
|
||||||
|
|
||||||
|
$file = $_SERVER['DOCUMENT_ROOT'] . '/rss/php/class/'.$class.'.php';
|
||||||
|
|
||||||
|
if(file_exists($file)){
|
||||||
|
require_once($file);
|
||||||
|
}
|
||||||
|
});
|
||||||
15
rss/php/class/Main.php
Normal file
15
rss/php/class/Main.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
namespace App;
|
||||||
|
require_once($_SERVER['DOCUMENT_ROOT'] . '/rss/php/autoload.php');
|
||||||
|
|
||||||
|
use PDO;
|
||||||
|
use PDOException;
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class Main extends Sys{
|
||||||
|
|
||||||
|
|
||||||
|
public function __construct(){
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
26
rss/php/class/Sys.php
Normal file
26
rss/php/class/Sys.php
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
namespace App;
|
||||||
|
require_once($_SERVER['DOCUMENT_ROOT'] . '/rss/php/autoload.php');
|
||||||
|
require_once($_SERVER['DOCUMENT_ROOT'] . '/rss/php/conf.php');
|
||||||
|
|
||||||
|
use PDO;
|
||||||
|
use PDOException;
|
||||||
|
use Exception;
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
|
class Sys{
|
||||||
|
protected $conn;
|
||||||
|
|
||||||
|
public function __construct(){
|
||||||
|
global $conn;
|
||||||
|
$this->conn = $conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function createResponse($status, $message = null, $info = null){
|
||||||
|
$resp = new stdClass();
|
||||||
|
$resp->status = $status;
|
||||||
|
$resp->message = $message;
|
||||||
|
$resp->info = $info;
|
||||||
|
return $resp;
|
||||||
|
}
|
||||||
|
}
|
||||||
36
rss/php/conf.php
Normal file
36
rss/php/conf.php
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
if(file_exists($_SERVER['DOCUMENT_ROOT'] . '/.env')){
|
||||||
|
$lines = file($_SERVER['DOCUMENT_ROOT'] . '/.env', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||||
|
|
||||||
|
if(isset($lines) && !empty($lines)){
|
||||||
|
foreach($lines as $line){
|
||||||
|
if(strpos(trim($line), '#') === 0){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
list($name, $value) = explode('=', $line, 2);
|
||||||
|
$name = trim($name);
|
||||||
|
$value = trim($value);
|
||||||
|
|
||||||
|
$value = trim($value, '"\'');
|
||||||
|
|
||||||
|
putenv("$name=$value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
|
$db_user = getenv("DB_USER");
|
||||||
|
$db_pass = getenv("DB_PASS");
|
||||||
|
$db_server = getenv("DB_SERVER");
|
||||||
|
$db_name = getenv("DB_NAME");
|
||||||
|
|
||||||
|
$conn = new PDO("mysql:host=$db_server;dbname=$db_name;charset=utf8mb4", $db_user, $db_pass);
|
||||||
|
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
|
}catch(PDOException $e){
|
||||||
|
var_dump($e);
|
||||||
|
echo json_encode('Connection exception');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
58
rss/php/handler.php
Normal file
58
rss/php/handler.php
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
require_once($_SERVER['DOCUMENT_ROOT'] . '/rss/php/autoload.php');
|
||||||
|
use App\Main;
|
||||||
|
|
||||||
|
$classList = array(
|
||||||
|
'Main' => Main::class,
|
||||||
|
);
|
||||||
|
|
||||||
|
session_start();
|
||||||
|
|
||||||
|
if(file_exists($_SERVER['DOCUMENT_ROOT'] . '/rss/php/conf.php')){
|
||||||
|
require_once($_SERVER['DOCUMENT_ROOT'] . '/rss/php/conf.php');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($_POST['function']) && !empty($_POST['function']) && isset($_POST['target']) && !empty($_POST['target'])){
|
||||||
|
$t_class = trim($_POST['target']);
|
||||||
|
$t_func = trim($_POST['function']);
|
||||||
|
if(array_key_exists($t_class, $classList) && class_exists($classList[$t_class])){
|
||||||
|
if(method_exists($classList[$t_class], $t_func)){
|
||||||
|
$_class = new $classList[$t_class];
|
||||||
|
|
||||||
|
if(count($_POST) > 2){
|
||||||
|
foreach($_POST as $prop => $val){
|
||||||
|
if(property_exists($classList[$t_class], $prop)){
|
||||||
|
$_class->$prop = $val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($_FILES) && !empty($_FILES)){
|
||||||
|
foreach($_FILES as $prop => $val){
|
||||||
|
if(property_exists($classList[$t_class], $prop)){
|
||||||
|
$_class->$prop = $val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $_class->$t_func();
|
||||||
|
if($response){
|
||||||
|
$msg = $response;
|
||||||
|
}else{
|
||||||
|
$msg = new stdClass();
|
||||||
|
$msg->status = 'fail';
|
||||||
|
$msg->message = $response;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
$msg = new stdClass();
|
||||||
|
$msg->status = 'fail';
|
||||||
|
$msg->message = 'Invalid function';
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
$msg = new stdClass();
|
||||||
|
$msg->status = 'fail';
|
||||||
|
$msg->message = 'Invalid class';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
die(json_encode($msg));
|
||||||
10
rss/php/includes/footer.php
Normal file
10
rss/php/includes/footer.php
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
global $pageInfo;
|
||||||
|
if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/rss/js/' . $pageInfo['template'] . '.js')) {
|
||||||
|
echo '<script src="/rss/js/' . $pageInfo['template'] . '.js"></script>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
|
||||||
|
</footer>
|
||||||
77
rss/php/includes/header.php
Normal file
77
rss/php/includes/header.php
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
<?php
|
||||||
|
$page = isset($_GET['page']) ? basename($_GET['page']) : 'index';
|
||||||
|
$jsonFile = $_SERVER['DOCUMENT_ROOT'] . "/rss/json/pages/{$page}.json";
|
||||||
|
$pageData = file_exists($jsonFile) ? json_decode(file_get_contents($jsonFile), true) : [
|
||||||
|
'title' => 'ECUSM',
|
||||||
|
'long_desc' => '',
|
||||||
|
'robots' => 'noindex, nofollow'
|
||||||
|
];
|
||||||
|
|
||||||
|
// Set default values
|
||||||
|
$siteUrl = 'http://ecusm.local';
|
||||||
|
$pageUrl = $page === 'index' ? $siteUrl . '/' : $siteUrl . '/' . $page . '/';
|
||||||
|
$title = $pageData['title'] ?? 'ECUSM';
|
||||||
|
$description = $pageData['long_desc'] ?? '';
|
||||||
|
$keywords = '';
|
||||||
|
$robots = $pageData['robots'] ?? 'noindex, nofollow';
|
||||||
|
$currentPage = $page === 'index' ? 'Home' : ucwords(str_replace('-', ' ', $page));
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<!-- Defaults -->
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>ECUSM | <?php echo htmlspecialchars($pageData['title'], ENT_QUOTES, 'UTF-8'); ?></title>
|
||||||
|
<meta name="description" content="<?php echo htmlspecialchars($description, ENT_QUOTES, 'UTF-8'); ?>">
|
||||||
|
<meta name="author" content="ECUSM">
|
||||||
|
<meta name="keywords" content="<?php echo htmlspecialchars($keywords, ENT_QUOTES, 'UTF-8'); ?>">
|
||||||
|
<meta name="robots" content="<?php echo htmlspecialchars($robots, ENT_QUOTES, 'UTF-8'); ?>">
|
||||||
|
<link rel="canonical" href="<?php echo htmlspecialchars($pageUrl, ENT_QUOTES, 'UTF-8'); ?>">
|
||||||
|
|
||||||
|
<!-- Open Graph -->
|
||||||
|
<meta property="og:title" content="<?php echo htmlspecialchars($title, ENT_QUOTES, 'UTF-8'); ?>">
|
||||||
|
<meta property="og:description" content="<?php echo htmlspecialchars($description, ENT_QUOTES, 'UTF-8'); ?>">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:url" content="<?php echo htmlspecialchars($pageUrl, ENT_QUOTES, 'UTF-8'); ?>">
|
||||||
|
<meta property="og:image" content="<?php echo $siteUrl; ?>/rss/img/image.png">
|
||||||
|
|
||||||
|
<!-- Twitter Card -->
|
||||||
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
|
<meta name="twitter:title" content="<?php echo htmlspecialchars($title, ENT_QUOTES, 'UTF-8'); ?>">
|
||||||
|
<meta name="twitter:description" content="<?php echo htmlspecialchars($description, ENT_QUOTES, 'UTF-8'); ?>">
|
||||||
|
<meta name="twitter:image" content="<?php echo $siteUrl; ?>/rss/img/image.png">
|
||||||
|
|
||||||
|
<!-- Favicon -->
|
||||||
|
<link rel="icon" href="/rss/img/favicon/favicon.ico" type="image/x-icon">
|
||||||
|
<link rel="apple-touch-icon" href="/rss/img/favicon/apple-touch-icon.png">
|
||||||
|
|
||||||
|
<!-- Stylesheets -->
|
||||||
|
<link rel="preload" href="/rss/css/main.css" as="style">
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/@mdi/font/css/materialdesignicons.min.css" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="/rss/css/main.css">
|
||||||
|
<link rel="stylesheet" href="/rss/css/theme.css">
|
||||||
|
|
||||||
|
<!-- JavaScript -->
|
||||||
|
<script src="/rss/js/main.js" defer></script>
|
||||||
|
|
||||||
|
<!-- Structured Data (JSON-LD) -->
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "WebPage",
|
||||||
|
"name": "<?php echo htmlspecialchars($title, ENT_QUOTES, 'UTF-8'); ?>",
|
||||||
|
"url": "<?php echo htmlspecialchars($pageUrl, ENT_QUOTES, 'UTF-8'); ?>",
|
||||||
|
"description": "<?php echo htmlspecialchars($description, ENT_QUOTES, 'UTF-8'); ?>",
|
||||||
|
"isPartOf": {
|
||||||
|
"@type": "WebSite",
|
||||||
|
"name": "ECUSM",
|
||||||
|
"url": "<?php echo $siteUrl; ?>/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
|
||||||
|
</header>
|
||||||
33
rss/php/pageHandler.php
Normal file
33
rss/php/pageHandler.php
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
require_once($_SERVER['DOCUMENT_ROOT'] . '/rss/php/autoload.php');
|
||||||
|
// require_once($_SERVER['DOCUMENT_ROOT'] . '/rss/php/conf.php');
|
||||||
|
$page = isset($_GET['page']) && !empty($_GET['page']) ? str_replace('.php', '', $_GET['page']) : 'index';
|
||||||
|
if($page == '404'){
|
||||||
|
http_response_code(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(file_exists($_SERVER['DOCUMENT_ROOT'] . '/rss/json/pages/' . $page . '.json')){
|
||||||
|
// Load page configuration
|
||||||
|
$jsonInfo = file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/rss/json/pages/' . $page .'.json');
|
||||||
|
$pageInfo = json_decode($jsonInfo, true);
|
||||||
|
|
||||||
|
}else{
|
||||||
|
http_response_code(404);
|
||||||
|
header('location:/404');
|
||||||
|
die('Not found');
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
function loadContents(){
|
||||||
|
global $pageInfo;
|
||||||
|
if(file_exists($_SERVER['DOCUMENT_ROOT'] . '/rss/php/templates/'.$pageInfo['template'].'.php')){
|
||||||
|
include($_SERVER['DOCUMENT_ROOT'] . '/rss/php/templates/'.$pageInfo['template'].'.php');
|
||||||
|
}else{
|
||||||
|
http_response_code(404);
|
||||||
|
header('location:/404');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
3
rss/php/templates/index.php
Normal file
3
rss/php/templates/index.php
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<main>
|
||||||
|
<!-- Login -->
|
||||||
|
</main>
|
||||||
Reference in New Issue
Block a user