progress today

This commit is contained in:
Luna D. 2024-05-07 19:33:56 +02:00
parent 0de3d98c82
commit f04666037c
No known key found for this signature in database
GPG key ID: 4B1C63448394F688
46 changed files with 672 additions and 321 deletions

View file

@ -32,7 +32,7 @@
@import "elements/form"; @import "elements/form";
@import "elements/heading"; @import "elements/heading";
@import "elements/input"; @import "elements/input";
@import "elements/interaction"; @import "elements/label";
@import "elements/layout"; @import "elements/layout";
@import "elements/list"; @import "elements/list";
@import "elements/media"; @import "elements/media";
@ -48,9 +48,11 @@
@import "views/footer"; @import "views/footer";
@import "views/header"; @import "views/header";
@import "views/image"; @import "views/image";
@import "views/interaction";
@import "views/markdown"; @import "views/markdown";
@import "views/metabar"; @import "views/metabar";
@import "views/pagination"; @import "views/pagination";
@import "views/staff"; @import "views/staff";
@import "views/statistics"; @import "views/statistics";
@import "views/tag"; @import "views/tag";
@import "views/user";

View file

@ -51,13 +51,16 @@ $font-family-monospace: "Droid Sans Mono", monospace;
--media-container-width: 225px; --media-container-width: 225px;
--media-tiny-container-width: 50px; --media-tiny-container-width: 50px;
--media-small-container-width: 125px; --media-small-container-width: 150px;
--media-medium-container-width: 250px; --media-medium-container-width: 250px;
--media-large-container-width: 500px; --media-large-container-width: 500px;
--media-full-container-width: 100%; --media-full-container-width: 100%;
--media-featured-width: 358px; --media-featured-width: 358px;
--media-header-height: 2rem; --media-header-height: 2rem;
--badge-small-size: 1.1rem;
--badge-normal-size: 2rem;
--number-badge-size: 0.6rem; --number-badge-size: 0.6rem;
--number-badge-padding: 0.1rem; --number-badge-padding: 0.1rem;
--number-badge-border: 2px; --number-badge-border: 2px;

View file

@ -8,11 +8,11 @@
.button--$(type).button--important { .button--$(type).button--important {
color: var(--text-color) !important; color: var(--text-color) !important;
background: var(--$(type)-color); background: var(--$(type)-color);
box-shadow: 0 -1px var(--$(type)-dark-color) inset;
} }
.button--$(type):hover { .button--$(type):hover, .button--$(type):active, .button--$(type).selected {
background: var(--$(type)-muted-color) !important; background: var(--$(type)-dark-color) !important;
border-radius: var(--border-radius-inner);
} }
.button__group--$(type) { .button__group--$(type) {
@ -28,6 +28,7 @@
@mixin animated-transition; @mixin animated-transition;
color: var(--text-color); color: var(--text-color);
background: var(--$(type)-color); background: var(--$(type)-color);
border-radius: var(--border-radius-inner);
} }
} }
@ -40,17 +41,18 @@
font-size: var(--font-size); font-size: var(--font-size);
background: var(--primary-dark-color); background: var(--primary-dark-color);
color: var(--text-color); color: var(--text-color);
border: 0;
border-radius: var(--border-radius-inner); border-radius: var(--border-radius-inner);
padding: 0 var(--padding-small); padding: 0 var(--padding-small);
overflow: hidden; overflow: hidden;
line-height: var(--button-height); line-height: var(--button-height);
align-items: center; align-items: center;
border-width: 0;
} }
.button:hover { .button:hover, .button:active {
@mixin animated-transition; @mixin animated-transition;
background: var(--primary-muted-color); background: var(--primary-dark-color);
border-radius: var(--border-radius-inner);
cursor: pointer; cursor: pointer;
} }
@ -70,7 +72,6 @@
.button--important { .button--important {
background: var(--primary-color); background: var(--primary-color);
box-shadow: 0 -1px var(--primary-dark-color) inset;
} }
.button__row { .button__row {
@ -85,7 +86,6 @@
.button__group, .button__group--single, .button__group--standalone { .button__group, .button__group--single, .button__group--standalone {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
border: 0;
border-radius: var(--border-radius-inner); border-radius: var(--border-radius-inner);
margin-right: var(--padding-normal); margin-right: var(--padding-normal);
background: var(--secondary-dark-color); background: var(--secondary-dark-color);
@ -126,6 +126,7 @@
.button__group--standalone a:hover { .button__group--standalone a:hover {
@mixin animated-transition; @mixin animated-transition;
background: var(--secondary-muted-color); background: var(--secondary-muted-color);
border-radius: var(--border-radius-inner);
} }
.button--borderless { .button--borderless {
@ -139,6 +140,7 @@
.block__header__buttons .button:hover { .block__header__buttons .button:hover {
background: var(--primary-muted-color); background: var(--primary-muted-color);
border-radius: var(--border-radius-inner);
} }
@mixin button-type primary; @mixin button-type primary;

View file

@ -67,6 +67,18 @@
justify-content: space-between; justify-content: space-between;
} }
.flex--small-gap {
gap: var(--padding-small);
}
.flex--normal-gap {
gap: var(--padding-normal);
}
.flex--large-gap {
gap: var(--padding-large);
}
.flex--start-bunched { .flex--start-bunched {
justify-content: flex-start; justify-content: flex-start;
} }

View file

@ -17,6 +17,36 @@ form .form--two-column > .field, form .form--two-column > li {
gap: var(--padding-normal); gap: var(--padding-normal);
} }
form .form--three-items {
display: grid;
grid: inherit;
grid-template-columns: 1 / -1;
gap: var(--padding-normal);
}
form .form--three-items > .field {
display: grid;
grid-template-columns: auto 1fr;
grid-template-rows: 1fr auto;
gap: var(--padding-normal);
}
form .form--three-items > .field > *:nth-child(1) {
grid-area: 1 / 1 / 2 / 2;
}
form .form--three-items > .field > *:nth-child(2) {
grid-area: 1 / 2 / 2 / 3;
}
form .form--three-items > .field > *:nth-child(3) {
grid-area: 2 / 1 / 3 / 3;
}
form .form--three-items select {
width: fit-content;
}
form .with-error { form .with-error {
display: block; display: block;
} }

View file

@ -0,0 +1,26 @@
@define-mixin label-type $type {
.label--$(type) {
background-color: var(--$(type)-color);
}
}
.label {
display: flex;
background: var(--primary-color);
padding: var(--padding-tiny) var(--padding-small);
border-radius: var(--border-radius-inner);
width: fit-content;
gap: var(--padding-tiny);
white-space: nowrap;
}
.label--block {
margin: var(--padding-small) 0;
}
@mixin label-type secondary;
@mixin label-type danger;
@mixin label-type warning;
@mixin label-type success;
@mixin label-type special;
@mixin label-type information;

View file

@ -0,0 +1,38 @@
/* An attempt to make stylesheets less broken on
* pre-2020 browsers like Chrome 67.
*
* Note: browsers newer than Chrome 84 will not need this.
*
* The main thing about those is that they don't support
* the "gap" property in flexboxes, so that has to be polyfilled
* with margin tags.
*/
@import "common/measurements";
@import "common/mixins";
@define-mixin legacy-flex-gap $classname, $size {
.$(classname) > * {
margin-bottom: $(size);
margin-right: $(size);
}
}
header > *, nav.header__secondary > * {
margin-left: var(--padding-large);
}
@mixin if-mobile {
header > * {
margin-left: var(--padding-normal);
}
}
@mixin legacy-flex-gap block__header__buttons, var(--padding-normal);
@mixin legacy-flex-gap block__header--js-tabbed, var(--padding-normal);
@mixin legacy-flex-gap field, var(--padding-normal);
@mixin legacy-flex-gap horizontal-list, var(--padding-normal);
@mixin legacy-flex-gap communication-edit__actions, var(--padding-normal);
@mixin legacy-flex-gap header__link--user, var(--padding-normal);
@mixin legacy-flex-gap tag-list, var(--padding-small);
@mixin legacy-flex-gap tagsinput, var(--padding-small);

View file

@ -4,7 +4,7 @@ $text-color: #e0e0e0;
$primary-color: #284371; $primary-color: #284371;
$secondary-color: #546c99; $secondary-color: #546c99;
$danger-color: #6d2a20; $danger-color: #6d2a20;
$warning-color: #715227; $warning-color: #6d421a;
$success-color: #25603e; $success-color: #25603e;
$information-color: #1c606a; $information-color: #1c606a;
$special-color: #65206e; $special-color: #65206e;

View file

@ -0,0 +1,92 @@
$background-color: #15121a;
$text-color: #e0e0e0;
$primary-color: #36274e;
$secondary-color: #785b99;
$danger-color: #6d2a20;
$warning-color: #715227;
$success-color: #25603e;
$information-color: #1c606a;
$special-color: #65206e;
$upvote-color: #5b9b26;
$downvote-color: #da3412;
$fave-color: #a18e27;
$comment-color: #b099dd;
$hide-color: #da3412;
$tag-default-color: #1b3c21;
$tag-error-color: #4f181d;
$tag-rating-color: #113456;
$tag-origin-color: #1d1858;
$tag-character-color: #193f47;
$tag-oc-color: #451f47;
$tag-species-color: #362118;
$tag-body-type-color: #393939;
$tag-content-fanmade-color: #622c4e;
$tag-content-official-color: #4b491c;
$tag-spoiler-color: #4f3811;
$spoiler-color: #0f0f0f;
@define-mixin tag-color $tagname, $color, $text-percentage: 35, $border-percentage: 15 {
--tag-$(tagname)-color: $(color);
--tag-$(tagname)-border-color: hsl(from $color h s calc(l + $border-percentage));
--tag-$(tagname)-text-color: hsl(from $color h s calc(l + $text-percentage));
}
@define-mixin type-color $type, $color {
--$(type)-color: $color;
--$(type)-border-color: hsl(from $color h calc(s - 20) calc(l + 10));
--$(type)-muted-color: hsl(from $color h calc(s - 10) calc(l - 7));
--$(type)-dark-color: hsl(from $color h calc(s - 30) calc(l - 11));
--$(type)-link-color: hsl(from $color h calc(s + 10) calc(l + 45));
}
:root {
--background-color: $background-color;
--text-color: $text-color;
--text-light-color: $text-color;
--link-color: hsl(from $primary-color h calc(s + 10) calc(l + 50));
--link-hover-color: $text-color;
--primary-color: $primary-color;
--primary-border-color: hsl(from $primary-color h calc(s - 20) calc(l + 5));
--primary-muted-color: hsl(from $primary-color h calc(s - 10) calc(l - 5));
--primary-dark-color: hsl(from $primary-color h calc(s - 15) calc(l - 9));
--primary-link-color: var(--link-color); /* for consistency */
--secondary-color: $secondary-color;
--secondary-border-color: hsl(from $secondary-color h s calc(l + 5));
--secondary-muted-color: hsl(from $secondary-color h s calc(l - 17));
--secondary-dark-color: hsl(from $secondary-color h calc(s - 5) calc(l - 25));
--secondary-link-color: hsl(from $secondary-color h s calc(l + 40));
--upvote-color: $upvote-color;
--downvote-color: $downvote-color;
--fave-color: $fave-color;
--comment-color: $comment-color;
--hide-color: $hide-color;
--spoiler-color: $spoiler-color;
--spoiler-revealed-color: hsl(from $spoiler-color h s calc(l + 20));
@mixin type-color success, $success-color;
@mixin type-color warning, $warning-color;
@mixin type-color danger, $danger-color;
@mixin type-color information, $information-color;
@mixin type-color special, $special-color;
@mixin tag-color default, $tag-default-color;
@mixin tag-color error, $tag-error-color, 37;
@mixin tag-color rating, $tag-rating-color, 37;
@mixin tag-color origin, $tag-origin-color, 42;
@mixin tag-color character, $tag-character-color;
@mixin tag-color oc, $tag-oc-color, 40;
@mixin tag-color species, $tag-species-color, 37;
@mixin tag-color body-type, $tag-body-type-color, 45, 12;
@mixin tag-color content-fanmade, $tag-content-fanmade-color, 40;
@mixin tag-color content-official, $tag-content-official-color;
@mixin tag-color spoiler, $tag-spoiler-color;
}

View file

@ -45,3 +45,101 @@
.communication__anonymous--label { .communication__anonymous--label {
padding: 0 var(--padding-small); padding: 0 var(--padding-small);
} }
.communication > .block__content:first-of-type {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.communication > .block__content:last-of-type {
background: var(--primary-muted-color);
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.communication__body {
display: block;
overflow: hidden;
}
.communication__body__text {
border-radius: var(--border-radius-inner);
word-wrap: break-word;
}
.communication__sender-name {
display: flex;
align-items: center;
gap: var(--padding-normal);
}
.communication__sender-block {
display: flex;
flex-direction: column;
background: var(--primary-muted-color);
border-radius: var(--border-radius-inner);
padding: var(--padding-small);
}
@mixin if-mobile {
.communication__body__text {
margin-top: var(--padding-normal);
}
.communication__sender-block {
flex-direction: row;
gap: var(--padding-normal);
align-items: center;
}
.communication__sender-block > .image-constrained {
min-height: var(--avatar-small-size);
min-width: var(--avatar-small-size);
}
}
.communication__interaction {
display: inline-block;
background: var(--secondary-muted-color);
color: var(--secondary-link-color) !important;
padding: var(--padding-tiny);
border-radius: var(--border-radius-inner);
margin-left: var(--padding-small);
}
.communication__interaction:first-child {
margin: 0;
}
.communication__info {
display: inline-block;
background: var(--information-muted-color);
padding: var(--padding-tiny);
border-radius: var(--border-radius-inner);
margin-left: var(--padding-small);
}
.communication__info > a {
color: var(--information-link-color);
}
.togglable-delete-form, .togglable-delete-form-link {
margin-top: var(--padding-small) !important;
}
.togglable-delete-form-link {
background: var(--danger-muted-color);
color: var(--danger-link-color) !important;
}
.owner-options {
margin-left: var(--padding-small);
}
@mixin if-mobile {
.communication__options > *:first-child {
display: flex;
flex-direction: column;
gap: var(--padding-small);
}
}

View file

@ -30,3 +30,7 @@
.spoiler-revealed a, .spoiler:hover a { .spoiler-revealed a, .spoiler:hover a {
color: var(--link-color); color: var(--link-color);
} }
.walloftext {
line-height: var(--readable-line-height);
}

View file

@ -4,6 +4,16 @@
} }
} }
.metabar__interactions {
display: block;
}
.metabar__interactions .comments_count {
background: 0;
border: 0;
position: static;
}
@mixin if-phone { @mixin if-phone {
.metabar__interactions { .metabar__interactions {
display: grid; display: grid;
@ -55,7 +65,25 @@
} }
.metabar__user-credit { .metabar__user-credit {
display: flex;
box-sizing: border-box; box-sizing: border-box;
gap: var(--padding-small);
}
.metabar__user-credit .image_uploader {
display: flex;
align-self: center;
align-items: center;
vertical-align: center;
gap: var(--padding-small);
}
/* For some bizarre reason the icon appears to have
* comically large gap on desktop */
@mixin if-desktop {
.image_uploader > .username-with-icon {
gap: 0;
}
} }
.metabar__mobile-info td { .metabar__mobile-info td {

View file

@ -12,7 +12,7 @@
font-size: 0.8rem !important; font-size: 0.8rem !important;
} }
.pagination a { .pagination a, .pagination span {
display: grid; display: grid;
grid-template-columns: auto; grid-template-columns: auto;
gap: var(--padding-tiny); gap: var(--padding-tiny);

35
assets/css/views/user.css Normal file
View file

@ -0,0 +1,35 @@
.badges {
display: grid;
grid-template-columns: repeat(6, var(--badge-small-size));
gap: var(--padding-small);
}
.badge {
width: var(--badge-small-size);
height: var(--badge-small-size);
}
.badge__overflow {
background: var(--information-color);
border-radius: var(--border-radius-inner);
text-align: center;
vertical-align: center;
line-height: calc(var(--badge-small-size) * 1.2);
width: calc(var(--badge-small-size) * 1.2);
height: calc(var(--badge-small-size) * 1.2);
font-size: calc(var(--font-size) * 0.8);
}
.username-with-icon {
display: inline-flex;
gap: var(--padding-tiny);
align-items: center;
}
.user-title {
display: flex;
flex-direction: row;
gap: var(--padding-small);
flex-wrap: wrap;
margin-top: var(--padding-small);
}

View file

@ -1,5 +1,5 @@
/** /**
* Fingerprints * Thanks uBlock for breaking our JS!
*/ */
// http://stackoverflow.com/a/34842797 // http://stackoverflow.com/a/34842797
@ -8,7 +8,7 @@ function hashCode(str) {
((prevHash << 5) - prevHash) + currVal.charCodeAt(0), 0) >>> 0; ((prevHash << 5) - prevHash) + currVal.charCodeAt(0), 0) >>> 0;
} }
function createFingerprint() { function createFp() {
const prints = [ const prints = [
navigator.userAgent, navigator.userAgent,
navigator.cpuClass, navigator.cpuClass,
@ -33,19 +33,19 @@ function createFingerprint() {
return hashCode(prints.join('')); return hashCode(prints.join(''));
} }
function setFingerprintCookie() { function setFpCookie() {
let fingerprint; let fp;
// The prepended 'c' acts as a crude versioning mechanism. // The prepended 'c' acts as a crude versioning mechanism.
try { try {
fingerprint = `c${createFingerprint()}`; fp = `c${createFp()}`;
} }
// If fingerprinting fails, use fakeprint "c1836832948" as a last resort. // If it fails, use fakeprint "c1836832948" as a last resort.
catch (err) { catch (err) {
fingerprint = 'c1836832948'; fp = 'c1836832948';
} }
document.cookie = `_ses=${fingerprint}; path=/; SameSite=Lax`; document.cookie = `_ses=${fp}; path=/; SameSite=Lax`;
} }
export { setFingerprintCookie }; export { setFpCookie };

View file

@ -14,7 +14,7 @@ import { setupBurgerMenu } from './burger';
import { bindCaptchaLinks } from './captcha'; import { bindCaptchaLinks } from './captcha';
import { setupComments } from './comment'; import { setupComments } from './comment';
import { setupDupeReports } from './duplicate_reports'; import { setupDupeReports } from './duplicate_reports';
import { setFingerprintCookie } from './fingerprint'; import { setFpCookie } from './fp';
import { setupGalleryEditing } from './galleries'; import { setupGalleryEditing } from './galleries';
import { initImagesClientside } from './imagesclientside'; import { initImagesClientside } from './imagesclientside';
import { bindImageTarget } from './image_expansion'; import { bindImageTarget } from './image_expansion';
@ -48,7 +48,7 @@ whenReady(() => {
initImagesClientside(); initImagesClientside();
setupComments(); setupComments();
setupDupeReports(); setupDupeReports();
setFingerprintCookie(); setFpCookie();
setupGalleryEditing(); setupGalleryEditing();
bindImageTarget(); bindImageTarget();
setupEvents(); setupEvents();

126
assets/package-lock.json generated
View file

@ -2682,29 +2682,6 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/execa": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz",
"integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==",
"dev": true,
"dependencies": {
"cross-spawn": "^7.0.3",
"get-stream": "^8.0.1",
"human-signals": "^5.0.0",
"is-stream": "^3.0.0",
"merge-stream": "^2.0.0",
"npm-run-path": "^5.1.0",
"onetime": "^6.0.0",
"signal-exit": "^4.1.0",
"strip-final-newline": "^3.0.0"
},
"engines": {
"node": ">=16.17"
},
"funding": {
"url": "https://github.com/sindresorhus/execa?sponsor=1"
}
},
"node_modules/fast-deep-equal": { "node_modules/fast-deep-equal": {
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@ -2861,18 +2838,6 @@
"node": "*" "node": "*"
} }
}, },
"node_modules/get-stream": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz",
"integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==",
"dev": true,
"engines": {
"node": ">=16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/glob": { "node_modules/glob": {
"version": "7.2.3", "version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
@ -3018,15 +2983,6 @@
"node": ">= 14" "node": ">= 14"
} }
}, },
"node_modules/human-signals": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz",
"integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==",
"dev": true,
"engines": {
"node": ">=16.17.0"
}
},
"node_modules/iconv-lite": { "node_modules/iconv-lite": {
"version": "0.6.3", "version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
@ -3132,18 +3088,6 @@
"resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
"integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ=="
}, },
"node_modules/is-stream": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
"integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
"dev": true,
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/isexe": { "node_modules/isexe": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@ -3846,33 +3790,6 @@
"resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz", "resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz",
"integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==" "integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg=="
}, },
"node_modules/npm-run-path": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz",
"integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==",
"dev": true,
"dependencies": {
"path-key": "^4.0.0"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/npm-run-path/node_modules/path-key": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
"integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
"dev": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/nwsapi": { "node_modules/nwsapi": {
"version": "2.2.9", "version": "2.2.9",
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.9.tgz", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.9.tgz",
@ -3886,21 +3803,6 @@
"wrappy": "1" "wrappy": "1"
} }
}, },
"node_modules/onetime": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
"integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
"dev": true,
"dependencies": {
"mimic-fn": "^4.0.0"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/optionator": { "node_modules/optionator": {
"version": "0.9.4", "version": "0.9.4",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
@ -4210,17 +4112,6 @@
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"dev": true "dev": true
}, },
"node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
"dependencies": {
"picomatch": "^2.2.1"
},
"engines": {
"node": ">=8.10.0"
}
},
"node_modules/redent": { "node_modules/redent": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
@ -4393,18 +4284,6 @@
"integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
"dev": true "dev": true
}, },
"node_modules/signal-exit": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"dev": true,
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/slash": { "node_modules/slash": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
@ -5254,6 +5133,11 @@
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
}, },
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"node_modules/yocto-queue": { "node_modules/yocto-queue": {
"version": "0.1.0", "version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",

View file

@ -353,7 +353,10 @@ defmodule Philomena.Users.User do
:show_sidebar_and_watched_images :show_sidebar_and_watched_images
]) ])
|> TagList.propagate_tag_list(:watched_tag_list, :watched_tag_ids) |> TagList.propagate_tag_list(:watched_tag_list, :watched_tag_ids)
|> validate_inclusion(:theme, ~W(default dark red)) |> validate_inclusion(
:theme,
~W(dark-blue dark-red dark-green dark-purple dark-pink dark-yellow dark-cyan dark-grey light-blue light-red light-green light-purple light-pink light-yellow light-cyan light-grey)
)
|> validate_inclusion(:images_per_page, 1..50) |> validate_inclusion(:images_per_page, 1..50)
|> validate_inclusion(:comments_per_page, 1..100) |> validate_inclusion(:comments_per_page, 1..100)
|> validate_inclusion(:scale_large_images, ["false", "partscaled", "true"]) |> validate_inclusion(:scale_large_images, ["false", "partscaled", "true"])

View file

@ -56,10 +56,18 @@ defmodule PhilomenaWeb.SettingController do
) )
end end
defp determine_theme(%{"theme" => "light", "light_theme" => name} = attrs) when name != nil,
do: Map.replace(attrs, "theme", name)
defp determine_theme(%{"dark_theme" => name} = attrs) when name != nil,
do: Map.replace(attrs, "theme", name)
defp determine_theme(attrs), do: Map.replace(attrs, "theme", "dark-blue")
defp maybe_update_user(conn, nil, _user_params), do: {:ok, conn} defp maybe_update_user(conn, nil, _user_params), do: {:ok, conn}
defp maybe_update_user(conn, user, user_params) do defp maybe_update_user(conn, user, user_params) do
case Users.update_settings(user, user_params) do case Users.update_settings(user, determine_theme(user_params)) do
{:ok, _user} -> {:ok, _user} ->
{:ok, conn} {:ok, conn}

View file

@ -70,12 +70,12 @@ defmodule PhilomenaWeb.ContentSecurityPolicyPlug do
defp cdn_uri, do: Application.get_env(:philomena, :cdn_host) |> to_uri() defp cdn_uri, do: Application.get_env(:philomena, :cdn_host) |> to_uri()
defp camo_uri, do: Application.get_env(:philomena, :camo_host) |> to_uri() defp camo_uri, do: Application.get_env(:philomena, :camo_host) |> to_uri()
defp default_script_src, do: vite_hmr?(do: "'self' localhost:5173", else: "'self'") defp default_script_src, do: vite_hmr?(do: "*", else: "'self'")
defp default_connect_src, defp default_connect_src,
do: vite_hmr?(do: "'self' localhost:5173 ws://localhost:5173", else: "'self'") do: vite_hmr?(do: "*", else: "'self'")
defp default_style_src, do: vite_hmr?(do: "'self' 'unsafe-inline'", else: "'self'") defp default_style_src, do: vite_hmr?(do: "*", else: "'self'")
defp to_uri(host) when host in [nil, ""], do: "" defp to_uri(host) when host in [nil, ""], do: ""
defp to_uri(host), do: URI.to_string(%URI{scheme: "https", host: host}) defp to_uri(host), do: URI.to_string(%URI{scheme: "https", host: host})

View file

@ -4,14 +4,7 @@ p
article.block.communication article.block.communication
.block__content.flex.flex--no-wrap .block__content.flex.flex--no-wrap
.flex__fixed.spacing--right = render PhilomenaWeb.CommunicationView, "_body.html", object: @report, body: @body, conn: @conn
= render PhilomenaWeb.UserAttributionView, "_anon_user_avatar.html", object: @report, conn: @conn
.flex__grow.communication__body
span.communication__body__sender-name = render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @report, awards: true, conn: @conn
br
= render PhilomenaWeb.UserAttributionView, "_anon_user_title.html", object: @report, conn: @conn
.communication__body__text
=<> @body
.block__content.communication__options .block__content.communication__options
.flex.flex--wrap.flex--spaced-out .flex.flex--wrap.flex--spaced-out

View file

@ -22,33 +22,7 @@ article.block.communication id="comment_#{@comment.id}"
= submit "Delete", class: "button" = submit "Delete", class: "button"
.block__content.flex.flex--no-wrap class=communication_body_class(@comment) .block__content.flex.flex--no-wrap class=communication_body_class(@comment)
.flex__fixed.spacing--right = render PhilomenaWeb.CommunicationView, "_body.html", object: @comment, body: @body, conn: @conn, name: "comment"
= render PhilomenaWeb.UserAttributionView, "_anon_user_avatar.html", object: @comment, conn: @conn
.flex__grow.communication__body
span.communication__body__sender-name = render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @comment, awards: true, conn: @conn
br
= render PhilomenaWeb.UserAttributionView, "_anon_user_title.html", object: @comment, conn: @conn
.communication__body__text
= if @comment.hidden_from_users do
strong.comment_deleted
' Deletion reason:
=<> @comment.deletion_reason
= if can?(@conn, :hide, @comment) and not is_nil(@comment.deleted_by) do
| (
= @comment.deleted_by.name
| )
= if can?(@conn, :hide, @comment) do
= if @comment.destroyed_content do
br
strong.comment_deleted>
| This comment's contents have been destroyed.
- else
br
=<> @body
- else
=<> @body
.block__content.communication__options .block__content.communication__options
.flex.flex--wrap.flex--spaced-out .flex.flex--wrap.flex--spaced-out

View file

@ -1,37 +1,6 @@
article.block.communication id="comment_#{@comment.id}" article.block.communication id="comment_#{@comment.id}"
.block__content.flex.flex--no-wrap class=communication_body_class(@comment) .block__content.flex.flex--no-wrap class=communication_body_class(@comment)
.flex__fixed.spacing--right = render PhilomenaWeb.CommunicationView, "_body.html", object: @comment, image: @comment.image, body: @body, conn: @conn, name: "comment"
.post-image-container
= render PhilomenaWeb.ImageView, "_image_container.html", image: @comment.image, size: :thumb_tiny, conn: @conn
.flex__grow.communication__body
span.communication__body__sender-name = render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @comment, awards: true, conn: @conn
br
= render PhilomenaWeb.UserAttributionView, "_anon_user_title.html", object: @comment, conn: @conn
.communication__body__text
= if @comment.hidden_from_users do
strong.comment_deleted
' Deletion reason:
=<> @comment.deletion_reason
= if can?(@conn, :hide, @comment) and not is_nil(@comment.deleted_by) do
| (
= @comment.deleted_by.name
| )
= if can?(@conn, :hide, @comment) do
= if @comment.destroyed_content do
br
strong.comment_deleted>
| This comment's contents have been destroyed.
- else
br
=<> @body
- else
=<> @body
.block__content.communication__options .block__content.communication__options
.flex.flex--wrap.flex--spaced-out .flex.flex--wrap.flex--spaced-out

View file

@ -0,0 +1,60 @@
- anon = is_nil(assigns[:noanon]) or @noanon == false
- avatar = cond do
- not is_nil(assigns[:image]) ->
.post-image-container
= render PhilomenaWeb.ImageView, "_image_container.html", image: @image, size: :thumb_tiny, conn: @conn
- anon ->
= render PhilomenaWeb.UserAttributionView, "_anon_user_avatar.html", object: @object, conn: @conn
- true ->
= render PhilomenaWeb.UserAttributionView, "_user_avatar.html", object: @object, conn: @conn, class: "avatar--small"
- username = if anon do
= render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @object, awards: true, conn: @conn
- else
= render PhilomenaWeb.UserAttributionView, "_user.html", object: @object, badges: true, conn: @conn
- title = if anon do
= render PhilomenaWeb.UserAttributionView, "_anon_user_title.html", object: @object, conn: @conn
- else
= render PhilomenaWeb.UserAttributionView, "_user_title.html", object: @object, conn: @conn
- contents = if Map.has_key?(@object, :hidden_from_users) and @object.hidden_from_users == true do
strong.comment_deleted
' Deletion reason:
=<> @object.deletion_reason
= if can?(@conn, :hide, @object) and not is_nil(@object.deleted_by) do
| (
= @object.deleted_by.name
| )
= if can?(@conn, :hide, @object) do
= if @object.destroyed_content do
br
strong.comment_deleted>
| This #{@name}'s contents have been destroyed.
- else
br
=<> @body
- else
=<> @body
.flex.flex__grow.hidden--mobile
.flex.flex__fixed.spacing--right
= avatar
.flex__grow.communication__body
.communication__sender-block
span.communication__sender-name
= username
= title
.communication__body__text
= contents
.flex.flex__column.flex__grow.hidden--desktop
.communication__sender-block
= avatar
.flex__column.flex--small-gap
span.communication__sender-name
= username
= title
.communication__body.communication__body__text
= contents

View file

@ -9,7 +9,7 @@ html lang="en"
=> @status => @status
| - Philomena | - Philomena
link rel="stylesheet" href=stylesheet_path(@conn, nil) link rel="stylesheet" href=stylesheet_path(@conn, nil)
link rel="stylesheet" href=dark_stylesheet_path(@conn) media="(prefers-color-scheme: dark)" link rel="stylesheet" href=light_stylesheet_path(@conn) media="(prefers-color-scheme: light)"
link rel="icon" href="/favicon.ico" type="image/x-icon" link rel="icon" href="/favicon.ico" type="image/x-icon"
link rel="icon" href="/favicon.svg" type="image/svg+xml" link rel="icon" href="/favicon.svg" type="image/svg+xml"

View file

@ -61,7 +61,6 @@
a href="#{pretty_url(@image, true, true)}" title="Download (no tags in filename)" a href="#{pretty_url(@image, true, true)}" title="Download (no tags in filename)"
i.fa.fa-download i.fa.fa-download
.metabar.metabar__user-credit.hidden--phone.layout--centered#extrameta .metabar.metabar__user-credit.hidden--phone.layout--centered#extrameta
div
' Uploaded ' Uploaded
=> pretty_time(@image.created_at) => pretty_time(@image.created_at)
= render PhilomenaWeb.ImageView, "_uploader.html", assigns = render PhilomenaWeb.ImageView, "_uploader.html", assigns

View file

@ -14,7 +14,7 @@ elixir:
.block__header.page__header .block__header.page__header
=> header => header
.block.block--borderless.flex__row.flex--spaced-out .block.block--borderless.flex__row.flex--spaced-out.flex--wrap
= if @images.total_pages > 1 do = if @images.total_pages > 1 do
.button__group--standalone .button__group--standalone
.page__pagination = pagination .page__pagination = pagination
@ -41,17 +41,15 @@ elixir:
- image -> - image ->
= render PhilomenaWeb.ImageView, "_image_box.html", image: image, link: image_url.(image), size: assigns[:size] || :thumb, conn: @conn = render PhilomenaWeb.ImageView, "_image_box.html", image: image, link: image_url.(image), size: assigns[:size] || :thumb, conn: @conn
.block.block--borderless.block--spaced-top.flex__row br
.block.block--borderless.flex__row.flex--normal-gap.flex--wrap
.button__group--standalone .button__group--standalone
.page__pagination = pagination .page__pagination = pagination
span.page__info
= info
.flex__spacer
.page__info.button__group--standalone .page__info.button__group--standalone
a href="/settings/edit" title="Display Settings" a href="/settings/edit" title="Display Settings"
i.fa.fa-cog i.fa.fa-cog
span.hidden--mobile<> span.hidden--mobile<>
' Display Settings ' Display Settings
span.page__info
= info

View file

@ -13,7 +13,7 @@ html lang="en"
link rel="stylesheet" href="/css/application.css" link rel="stylesheet" href="/css/application.css"
link rel="stylesheet" href=stylesheet_path(@conn, @current_user) link rel="stylesheet" href=stylesheet_path(@conn, @current_user)
= if is_nil(@current_user) do = if is_nil(@current_user) do
link rel="stylesheet" href=dark_stylesheet_path(@conn) media="(prefers-color-scheme: dark)" link rel="stylesheet" href=light_stylesheet_path(@conn) media="(prefers-color-scheme: light)"
link rel="icon" href="/favicon.ico" type="image/x-icon" link rel="icon" href="/favicon.ico" type="image/x-icon"
link rel="icon" href="/favicon.svg" type="image/svg+xml" link rel="icon" href="/favicon.svg" type="image/svg+xml"
meta name="generator" content="philomena" meta name="generator" content="philomena"

View file

@ -7,7 +7,7 @@ html lang="en"
title Two Factor Authentication - Derpibooru title Two Factor Authentication - Derpibooru
link rel="stylesheet" href=stylesheet_path(@conn, nil) link rel="stylesheet" href=stylesheet_path(@conn, nil)
link rel="stylesheet" href=dark_stylesheet_path(@conn) media="(prefers-color-scheme: dark)" link rel="stylesheet" href=light_stylesheet_path(@conn) media="(prefers-color-scheme: light)"
link rel="icon" href="/favicon.ico" type="image/x-icon" link rel="icon" href="/favicon.ico" type="image/x-icon"
link rel="icon" href="/favicon.svg" type="image/svg+xml" link rel="icon" href="/favicon.svg" type="image/svg+xml"

View file

@ -14,18 +14,7 @@ article.block.communication
' Approve ' Approve
.block__content.flex.flex--no-wrap .block__content.flex.flex--no-wrap
.flex__fixed.spacing--right = render PhilomenaWeb.CommunicationView, "_body.html", object: %{user: @message.from}, noanon: true, body: @body, conn: @conn, name: "message"
= render PhilomenaWeb.UserAttributionView, "_user_avatar.html", object: %{user: @message.from}, conn: @conn, class: "avatar--small"
.flex__grow.communication__body
span.communication__body__sender-name = render PhilomenaWeb.UserAttributionView, "_user.html", object: %{user: @message.from}, badges: true, conn: @conn
br
= render PhilomenaWeb.UserAttributionView, "_user_title.html", object: %{user: @message.from}, conn: @conn
.communication__body__text
= @body
.block__content.communication__options .block__content.communication__options
.flex.flex--wrap.flex--spaced-out .flex.flex--wrap.flex--spaced-out

View file

@ -40,11 +40,11 @@
nav.pagination.hidden--desktop nav.pagination.hidden--desktop
= if first_page?(@page) do = if first_page?(@page) do
span span.with-icon
i.fa.fa-backward> i.fa.fa-backward>
' First ' First
.separator--vertical.separator--secondary .separator--vertical.separator--secondary
span span.with-icon
i.fa.fa-chevron-left> i.fa.fa-chevron-left>
' Prev ' Prev
.separator--vertical.separator--secondary .separator--vertical.separator--secondary
@ -52,12 +52,14 @@
= link to: first_page_path(@page, @route, params), class: "with-icon" do = link to: first_page_path(@page, @route, params), class: "with-icon" do
i.fa.fa-backward> i.fa.fa-backward>
' First ' First
.separator--vertical.separator--secondary
= link to: prev_page_path(@page, @route, params), class: "js-prev with-icon" do = link to: prev_page_path(@page, @route, params), class: "js-prev with-icon" do
i.fa.fa-chevron-left> i.fa.fa-chevron-left>
' Prev ' Prev
.separator--vertical.separator--secondary
.dropdown .dropdown
a.page-current.pagination__dropdown a.with-icon.page-current.pagination__dropdown
=> @page.page_number => @page.page_number
i.fa.fa-caret-down i.fa.fa-caret-down
@ -80,11 +82,11 @@
= if last_page?(@page) do = if last_page?(@page) do
.separator--vertical.separator--secondary .separator--vertical.separator--secondary
span span.with-icon
' Next ' Next
i.fa.fa-chevron-right i.fa.fa-chevron-right
.separator--vertical.separator--secondary .separator--vertical.separator--secondary
span span.with-icon
' Last ' Last
i.fa.fa-fast-forward i.fa.fa-fast-forward
- else - else

View file

@ -22,33 +22,7 @@ article.block.communication id="post_#{@post.id}"
= submit "Delete", class: "button" = submit "Delete", class: "button"
.block__content.flex.flex--no-wrap class=communication_body_class(@post) .block__content.flex.flex--no-wrap class=communication_body_class(@post)
.flex__fixed.spacing--right = render PhilomenaWeb.CommunicationView, "_body.html", object: @post, body: @body, conn: @conn, name: "post"
= render PhilomenaWeb.UserAttributionView, "_anon_user_avatar.html", object: @post, conn: @conn
.flex__grow.communication__body
span.communication__body__sender-name = render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @post, awards: true, conn: @conn
br
= render PhilomenaWeb.UserAttributionView, "_anon_user_title.html", object: @post, conn: @conn
.communication__body__text
= if @post.hidden_from_users do
strong.comment_deleted
' Deletion reason:
=> @post.deletion_reason
= if can?(@conn, :hide, @post) and not is_nil(@post.deleted_by) do
| (
= @post.deleted_by.name
| )
= if can?(@conn, :hide, @post) do
= if @post.destroyed_content do
br
strong.comment_deleted>
| This post's contents have been destroyed.
- else
br
=<> @body
- else
=<> @body
.block__content.communication__options .block__content.communication__options
.flex.flex--wrap.flex--spaced-out .flex.flex--wrap.flex--spaced-out

View file

@ -2,6 +2,8 @@
= cond do = cond do
- @user.description not in [nil, ""] -> - @user.description not in [nil, ""] ->
= @about_me = @about_me
- true ->
| No description provided.
= if can?(@conn, :edit_description, @user) do = if can?(@conn, :edit_description, @user) do
= if @user.description not in [nil, ""] do = if @user.description not in [nil, ""] do

View file

@ -1,6 +1,6 @@
.badges .badges
- awards = award_order(@awards) - awards = award_order(@awards)
- {awards, overflow} = Enum.split(awards, 10) - {awards, overflow} = Enum.split(awards, 5)
= for award <- awards do = for award <- awards do
- title = [award_title(award), award.label] |> Enum.join(" - ") - title = [award_title(award), award.label] |> Enum.join(" - ")
@ -8,11 +8,6 @@
= badge_image(award.badge, alt: title, title: title, width: "18", height: "18") = badge_image(award.badge, alt: title, title: title, width: "18", height: "18")
= if Enum.any?(overflow) do = if Enum.any?(overflow) do
.dropdown span.badge__overflow
i.fa.fa-caret-down | +
.dropdown__content.block__header = Enum.count(overflow)
.badges.flex--column
= for award <- overflow do
- title = [award_title(award), award.label] |> Enum.join(" - ")
.badge
= badge_image(award.badge, alt: title, title: title, width: "18", height: "18")

View file

@ -56,21 +56,25 @@ h1 Content Settings
' Do not share this URL with anyone, it may allow an attacker to compromise your account. ' Do not share this URL with anyone, it may allow an attacker to compromise your account.
.block__tab.hidden.flex.flex--maybe-wrap data-tab="display" .block__tab.hidden.flex.flex--maybe-wrap data-tab="display"
div .form--three-items
.field .field
=> label f, :use_centered_layout => label f, :use_centered_layout
.with-error
=> checkbox f, :use_centered_layout, class: "checkbox" => checkbox f, :use_centered_layout, class: "checkbox"
.fieldlabel: i Align content to the center of the page - try this option out if you browse the site on a tablet or a fairly wide screen. .fieldlabel: i Align content to the center of the page - try this option out if you browse the site on a tablet or a fairly wide screen.
.field .field
=> label f, :show_sidebar_and_watched_images => label f, :show_sidebar_and_watched_images
.with-error
=> checkbox f, :show_sidebar_and_watched_images, class: "checkbox" => checkbox f, :show_sidebar_and_watched_images, class: "checkbox"
.fieldlabel: i Show the sidebar and new watched images on the homepage (the default) or hide it. .fieldlabel: i Show the sidebar and new watched images on the homepage (the default) or hide it.
.field .field
=> label f, :hide_vote_counts => label f, :hide_vote_counts
.with-error
=> checkbox f, :hide_vote_counts, class: "checkbox" => checkbox f, :hide_vote_counts, class: "checkbox"
.fieldlabel: i Hide upvote and downvote counts on images, showing only the overall score .fieldlabel: i Hide upvote and downvote counts on images, showing only the overall score
.field .field
=> label f, :images_per_page => label f, :images_per_page
.with-error
=> number_input f, :images_per_page, min: 1, max: 50, step: 1, class: "input" => number_input f, :images_per_page, min: 1, max: 50, step: 1, class: "input"
= error_tag f, :images_per_page = error_tag f, :images_per_page
.fieldlabel .fieldlabel
@ -78,12 +82,26 @@ h1 Content Settings
' This is the number of images per page that are displayed on image listings and searches, up to a maximum of 50. ' This is the number of images per page that are displayed on image listings and searches, up to a maximum of 50.
' For 1080p monitors, try 24. ' For 1080p monitors, try 24.
.field .field
=> label f, :theme label Theme
=> select f, :theme, theme_options(@conn), class: "input" select.input#js-theme-selector name="user[theme]" id="user_theme"
= error_tag f, :theme option value="dark" Dark
option value="light" Light
.fieldlabel: i General appearance of the theme
.field#js-theme-dark
label Theme color
.with-error
=> select f, :dark_theme, theme_options(@conn), class: "input"
= error_tag f, :dark_theme
.fieldlabel: i Color of the theme, don't forget to save settings to apply the theme
.field.hidden#js-theme-light
label Theme color
.with-error
=> select f, :light_theme, light_theme_options(@conn), class: "input"
= error_tag f, :light_theme
.fieldlabel: i Preview themes by selecting one from the dropdown. Saving sets the currently selected theme. .fieldlabel: i Preview themes by selecting one from the dropdown. Saving sets the currently selected theme.
.field .field
=> label f, :scale_large_images => label f, :scale_large_images
.with-error
=> select f, :scale_large_images, scale_options(), class: "input" => select f, :scale_large_images, scale_options(), class: "input"
= error_tag f, :scale_large_images = error_tag f, :scale_large_images

View file

@ -1,6 +1,9 @@
= cond do = cond do
- not is_nil(@object.user) and not anonymous?(@object) -> - not is_nil(@object.user) and not anonymous?(@object) ->
strong<> strong.username-with-icon<>
- icon = user_icon(@object.user)
= if icon do
i class="fa #{icon}"
= link(@object.user.name, to: Routes.profile_path(@conn, :show, @object.user)) = link(@object.user.name, to: Routes.profile_path(@conn, :show, @object.user))
= if assigns[:awards] do = if assigns[:awards] do
= render PhilomenaWeb.ProfileView, "_awards.html", awards: @object.user.awards = render PhilomenaWeb.ProfileView, "_awards.html", awards: @object.user.awards

View file

@ -1,6 +1,7 @@
= if !!@object.user and !anonymous?(@object) do = if !!@object.user and !anonymous?(@object) do
.user-title
= for {class, label} <- user_labels(@object) do = for {class, label} <- user_labels(@object) do
= if assigns[:large] do = if assigns[:large] do
.label.label--block class=class = label .label class=class = label
- else - else
.label.label--block.label--small class=class = label .label.label--small class=class = label

View file

@ -1,5 +1,8 @@
= if !!@object.user do = if !!@object.user do
strong<> strong<>
- icon = user_icon(@object.user)
= if icon do
i class="fa #{icon}">
= link(@object.user.name, to: Routes.profile_path(@conn, :show, @object.user)) = link(@object.user.name, to: Routes.profile_path(@conn, :show, @object.user))
= if assigns[:awards] do = if assigns[:awards] do
= render PhilomenaWeb.ProfileView, "_awards.html", awards: @object.user.awards = render PhilomenaWeb.ProfileView, "_awards.html", awards: @object.user.awards

View file

@ -1,5 +1,6 @@
= for {class, label} <- user_labels(@object) do .user-title
= for {class, label} <- user_labels(@object) do
= if assigns[:large] do = if assigns[:large] do
.label.label--block class=class = label .label class=class = label
- else - else
.label.label--block.label--small class=class = label .label.label--small class=class = label

View file

@ -46,7 +46,9 @@ defmodule PhilomenaWeb.Admin.UserView do
def description("moderator", "Tag"), do: "Manage tag details" def description("moderator", "Tag"), do: "Manage tag details"
def description("admin", "Tag"), do: "Alias tags" def description("admin", "Tag"), do: "Alias tags"
def description("batch_update", "Tag"), do: "Update tags in batches (do not issue to staff members)"
def description("batch_update", "Tag"),
do: "Update tags in batches (do not issue to staff members)"
def description("moderator", "User"), do: "Manage users and wipe votes" def description("moderator", "User"), do: "Manage users and wipe votes"
def description("admin", "Role"), do: "Manage permissions" def description("admin", "Role"), do: "Manage permissions"

View file

@ -0,0 +1,3 @@
defmodule PhilomenaWeb.CommunicationView do
use PhilomenaWeb, :view
end

View file

@ -4,7 +4,7 @@ defmodule PhilomenaWeb.ErrorView do
import PhilomenaWeb.LayoutView, import PhilomenaWeb.LayoutView,
only: [ only: [
stylesheet_path: 2, stylesheet_path: 2,
dark_stylesheet_path: 1, light_stylesheet_path: 1,
viewport_meta_tag: 1 viewport_meta_tag: 1
] ]

View file

@ -69,17 +69,32 @@ defmodule PhilomenaWeb.LayoutView do
Config.get(:footer) Config.get(:footer)
end end
# def stylesheet_path(conn, %{theme: "dark"}), def stylesheet_path(conn, %{theme: theme})
# do: Routes.static_path(conn, "/css/dark.css") when theme in [
"dark-blue",
# def stylesheet_path(conn, %{theme: "red"}), "dark-red",
# do: Routes.static_path(conn, "/css/red.css") "dark-green",
"dark-purple",
"dark-pink",
"dark-yellow",
"dark-cyan",
"dark-grey",
"light-blue",
"light-red",
"light-green",
"light-purple",
"light-pink",
"light-yellow",
"light-cyan",
"light-grey"
],
do: Routes.static_path(conn, "/css/#{theme}.css")
def stylesheet_path(conn, _user), def stylesheet_path(conn, _user),
do: Routes.static_path(conn, "/css/dark-blue.css") do: Routes.static_path(conn, "/css/dark-blue.css")
def dark_stylesheet_path(conn), def light_stylesheet_path(conn),
do: Routes.static_path(conn, "/css/dark-blue.css") do: Routes.static_path(conn, "/css/light-blue.css")
def theme_name(%{theme: theme}), do: theme def theme_name(%{theme: theme}), do: theme
def theme_name(_user), do: "default" def theme_name(_user), do: "default"

View file

@ -4,12 +4,90 @@ defmodule PhilomenaWeb.SettingView do
def theme_options(conn) do def theme_options(conn) do
[ [
[ [
key: "Default", key: "Blue (default)",
value: "default", value: "dark-blue",
data: [theme_path: Routes.static_path(conn, "/css/default.css")] data: [theme_path: Routes.static_path(conn, "/css/dark-blue.css")]
], ],
[key: "Dark", value: "dark", data: [theme_path: Routes.static_path(conn, "/css/dark.css")]], [
[key: "Red", value: "red", data: [theme_path: Routes.static_path(conn, "/css/red.css")]] key: "Red",
value: "dark-red",
data: [theme_path: Routes.static_path(conn, "/css/dark-red.css")]
],
[
key: "Green",
value: "dark-green",
data: [theme_path: Routes.static_path(conn, "/css/dark-green.css")]
],
[
key: "Purple",
value: "dark-purple",
data: [theme_path: Routes.static_path(conn, "/css/dark-purple.css")]
],
[
key: "Pink",
value: "dark-pink",
data: [theme_path: Routes.static_path(conn, "/css/dark-pink.css")]
],
[
key: "Yellow",
value: "dark-yellow",
data: [theme_path: Routes.static_path(conn, "/css/dark-yellow.css")]
],
[
key: "Cyan",
value: "dark-cyan",
data: [theme_path: Routes.static_path(conn, "/css/dark-cyan.css")]
],
[
key: "Grey",
value: "dark-grey",
data: [theme_path: Routes.static_path(conn, "/css/dark-grey.css")]
]
]
end
def light_theme_options(conn) do
[
[
key: "Blue (default)",
value: "light-blue",
data: [theme_path: Routes.static_path(conn, "/css/light-blue.css")]
],
[
key: "Red",
value: "light-red",
data: [theme_path: Routes.static_path(conn, "/css/light-red.css")]
],
[
key: "Green",
value: "light-green",
data: [theme_path: Routes.static_path(conn, "/css/light-green.css")]
],
[
key: "Purple",
value: "light-purple",
data: [theme_path: Routes.static_path(conn, "/css/light-purple.css")]
],
[
key: "Pink",
value: "light-pink",
data: [theme_path: Routes.static_path(conn, "/css/light-pink.css")]
],
[
key: "Yellow",
value: "light-yellow",
data: [theme_path: Routes.static_path(conn, "/css/light-yellow.css")]
],
[
key: "Cyan",
value: "light-cyan",
data: [theme_path: Routes.static_path(conn, "/css/light-cyan.css")]
],
[
key: "Grey",
value: "light-grey",
data: [theme_path: Routes.static_path(conn, "/css/light-grey.css")]
]
] ]
end end

View file

@ -81,6 +81,13 @@ defmodule PhilomenaWeb.UserAttributionView do
"data:image/svg+xml;base64," <> Base.encode64(svg) "data:image/svg+xml;base64," <> Base.encode64(svg)
end end
def user_icon(%{secondary_role: sr}) when sr in ["Site Developer", "Devops"], do: "fa-screwdriver-wrench"
def user_icon(%{secondary_role: sr}) when sr in ["Public Relations"], do: "fa-bullhorn"
def user_icon(%{hide_default_role: true}), do: nil
def user_icon(%{role: role}) when role in ["admin", "moderator"], do: "fa-gavel"
def user_icon(%{role: "assistant"}), do: "fa-handshake-angle"
def user_icon(_), do: nil
def user_labels(%{user: user}) do def user_labels(%{user: user}) do
[] []
|> personal_title(user) |> personal_title(user)