diff --git a/assets/scss/comments.scss b/assets/scss/comments.scss new file mode 100644 index 000000000..39ac01297 --- /dev/null +++ b/assets/scss/comments.scss @@ -0,0 +1,159 @@ +// @import "comments/source-sans"; +@import "comments/theme"; +@import "comments/colours"; + +// The root web component tag +comentario-comments { + + // Default theme properties (light) + @include theme-props(); + + // Dark theme properties, selected automatically with the dark mode, but only when no theme is explicitly set + @media (prefers-color-scheme: dark) { + html[data-theme=dark] & { + @include theme-props(dark); + } + } + + // Dark theme properties selected explicitly with [theme="dark"] on the element + html[data-theme=dark] & { + @include theme-props(dark); + } +} + +.comentario-root { + position: relative; + padding: 0; + width: 100%; + font-family: inherit; + font-size: 15px; + line-height: 1.5; + color: var(--cmntr-color); + + @import "comments/common"; + @import "comments/animations"; + @import "comments/button"; + @import "comments/table"; + @import "comments/input"; + @import "comments/badge"; + @import "comments/dialog"; + @import "comments/footer"; + @import "comments/comment-editor"; + @import "comments/comment-card"; + @import "comments/placeholders"; + @import "comments/sort-bar"; + @import "comments/toolbar"; + + .comentario-backdrop { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + z-index: 10; + background-color: rgba(var(--cmntr-bg), 60%); + backdrop-filter: blur(3px); + } + + .comentario-message-box { + width: 100%; + margin-top: 1rem; + margin-bottom: 1rem; + border-radius: 4px; + background-color: var(--cmntr-success-bg); + color: var(--cmntr-success-color); + + &.comentario-error { + background-color: var(--cmntr-danger-bg); + color: var(--cmntr-danger-color); + } + + .comentario-message-box-body { + padding: 1rem; + text-align: center; + } + + code { + pre { + padding: 12px; + font-family: 'DejaVu Sans Mono', 'Noto Mono', monospace; + } + } + } + + .comentario-page-moderation-notice { + width: 100%; + padding-top: 16px; + padding-bottom: 16px; + text-align: center; + color: var(--cmntr-warning-color); + } + + &.comentario-root-font { + * {font-family: 'Source Sans Pro', sans-serif;} + } + + @each $i, $c in $colourise-map { + + // Generate colouring classes for the left border + .comentario-border-#{$i} { + border-left: 2px solid #{$c} !important; + } + + // Generate background colouring classes + .comentario-bg-#{$i} { + background-color: #{$c} !important; + } + } + + // Anonymous (unregistered) is a special case + .comentario-border-anonymous { + border-left: 2px dashed var(--cmntr-muted-color) !important; + } + .comentario-bg-anonymous { + background-color: var(--cmntr-muted-color) !important; + background-image: url("data:image/svg+xml,%3Csvg height='800' width='800' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60.671 60.671' xml:space='preserve'%3E%3Cellipse style='fill:%23ffffff' cx='30.336' cy='12.097' rx='11.997' ry='12.097'/%3E%3Cpath style='fill:%23ffffff' d='M35.64 30.079H25.031c-7.021 0-12.714 5.739-12.714 12.821v17.771h36.037V42.9c0-7.082-5.693-12.821-12.714-12.821z'/%3E%3C/svg%3E%0A") !important; + background-repeat: no-repeat !important; + background-size: 80% !important; + background-position: bottom !important; + } + + // Deleted user is another special case + .comentario-border-deleted { + border-left: 2px dotted var(--cmntr-deleted-bg) !important; + } + .comentario-bg-deleted { + background-color: var(--cmntr-deleted-bg) !important; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='1em' viewBox='0 0 384 512'%3E%3Cpath style='fill:%23ffffff' d='M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-size: 50% !important; + background-position: center !important; + } +} + + +// Custom: overflow correction. +.comentario-card-expand-body { + // Set the width to anything to trigger the box to be slimmed down. + width: 80%; // Value is arbitrary? +} + +.comentario-card-body { + // Handle overflow. + overflow: auto; +} + +// Custom: align error box background with danger alert. +.comentario-root .comentario-message-box.comentario-error { + html[data-theme="light"] & { + background-color: #f8d7da; + } + html[data-theme="dark"] & { + background-color: #2c0b0e; + } +} + +// Fix `code` color. +.comentario-error code { + color: inherit; +} diff --git a/assets/scss/comments/_animations.scss b/assets/scss/comments/_animations.scss new file mode 100644 index 000000000..fe839ea79 --- /dev/null +++ b/assets/scss/comments/_animations.scss @@ -0,0 +1,78 @@ +@import "colours"; + +$animation-duration: 250ms; + +// Fade in-out + +.comentario-fade-in { + animation: comentario-fade-in-animation $animation-duration ease-in-out forwards 1; +} + +.comentario-fade-out { + animation: comentario-fade-out-animation $animation-duration ease-in-out forwards 1; +} + +@keyframes comentario-fade-in-animation { + from {opacity: 0;} + to {opacity: 1;} +} + +@keyframes comentario-fade-out-animation { + from {opacity: 1;} + to {opacity: 0;} +} + +// Expand-collapse + +.comentario-expand { + animation: comentario-expand-animation $animation-duration ease-in-out forwards 1; +} + +.comentario-collapse { + animation: comentario-collapse-animation $animation-duration ease-in-out forwards 1; +} + +@keyframes comentario-expand-animation { + from { + opacity: 0; + transform: translateY(-100%); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes comentario-collapse-animation { + from { + opacity: 1; + transform: translateY(0); + } + to { + opacity: 0; + transform: translateY(-100%); + } +} + +// Background blinks + +.comentario-bg-highlight { + animation: comentario-bg-highlight-animation 5s ease forwards 1; +} + +.comentario-bg-blink { + animation: comentario-bg-blink-animation 2s ease forwards 1; +} + +@keyframes comentario-bg-highlight-animation { + 0% { background-color: transparent; } + 10% { background-color: var(--cmntr-bg-highlight); } + 50% { background-color: var(--cmntr-bg-highlight); } + 100% { background-color: transparent; } +} + +@keyframes comentario-bg-blink-animation { + 0% { background-color: transparent; } + 50% { background-color: var(--cmntr-bg-blink); } + 100% { background-color: transparent; } +} diff --git a/assets/scss/comments/_badge.scss b/assets/scss/comments/_badge.scss new file mode 100644 index 000000000..a87b565a9 --- /dev/null +++ b/assets/scss/comments/_badge.scss @@ -0,0 +1,20 @@ +@import "colours"; + +.comentario-badge { + display: inline-block; + font-size: 9px; + margin-left: 8px; + padding: 2px 6px 2px 6px; + border-radius: 100px; + line-height: 17px; + text-transform: uppercase; + color: $white; +} + +.comentario-badge-moderator { + background: $green-5; +} + +.comentario-badge-pending { + background: $yellow-6; +} diff --git a/assets/scss/comments/_button.scss b/assets/scss/comments/_button.scss new file mode 100644 index 000000000..e41075a94 --- /dev/null +++ b/assets/scss/comments/_button.scss @@ -0,0 +1,94 @@ +@import "colours"; +@import "mixins"; + +.comentario-btn { + // Vars + --cmntr-btn-color: var(--cmntr-link-color); + --cmntr-btn-bg: transparent; + --cmntr-btn-hover-color: var(--cmntr-link-hover-color); + --cmntr-btn-hover-bg: transparent; + --cmntr-btn-active-color: var(--cmntr-link-hover-color); + --cmntr-btn-active-bg: transparent; + + color: var(--cmntr-btn-color); + background-color: var(--cmntr-btn-bg); + + display: inline-flex; + justify-content: center; + align-items: center; + text-align: center; + cursor: pointer; + line-height: 20px; + padding: 6px 12px; + border: 1px solid transparent; + border-radius: 0.15rem; + margin: 5px; + transition: color 0.4s, background-color 0.4s; + white-space: nowrap; + + &:not(:disabled) { + &:hover, &:focus, &:active { + color: var(--cmntr-btn-hover-color); + background-color: var(--cmntr-btn-hover-bg); + opacity: 1; + } + } + + &:disabled { + cursor: not-allowed !important; + opacity: 0.3 !important; + } + + &:not(.comentario-btn-link):not(.comentario-btn-tool).comentario-btn-active { + color: var(--cmntr-btn-active-color); + background-color: var(--cmntr-btn-active-bg); + @include btn-active-shadow(); + } + + &:not(.comentario-btn-link):not(.comentario-btn-tool):not(.comentario-btn-active) { + @include btn-shadow(); + } + + &.comentario-btn-link.comentario-btn-active { + font-weight: bold; + } +} + +.comentario-btn-sm { + font-size: 12px; + line-height: 16px; + padding: 3px 6px; + margin: 2.5px; +} + +.comentario-submit-icon { + font-size: 20px; +} + +@mixin make-btn($name, $color, $bg-color) { + .comentario-btn-#{$name} { + --cmntr-btn-color: #{$color}; + --cmntr-btn-bg: #{$bg-color}; + --cmntr-btn-hover-color: #{$color}; + --cmntr-btn-hover-bg: #{lighten($bg-color, 15%)}; + --cmntr-btn-active-color: #{$color}; + --cmntr-btn-active-bg: #{darken($bg-color, 15%)}; + } +} + +@include make-btn("primary", $white, $primary); +@include make-btn("secondary", $white, $secondary); +@include make-btn("dark", $white, $dark); +@include make-btn("danger", $white, $red-8); +@include make-btn("facebook", $white, #1877f2); +@include make-btn("github", $white, $black); +@include make-btn("gitlab", $white, #fc6d26); +@include make-btn("google", $white, #4285f4); +@include make-btn("twitter", $white, #1da1f2); +@include make-btn("sso", $white, #7275ab); + +.comentario-oauth-buttons { + display: flex; + justify-content: center; + flex-wrap: wrap; +} diff --git a/assets/scss/comments/_colours.scss b/assets/scss/comments/_colours.scss new file mode 100644 index 000000000..3c018c912 --- /dev/null +++ b/assets/scss/comments/_colours.scss @@ -0,0 +1,230 @@ +//---------------------------------------------------------------------------------------------------------------------- +// Base palette +//---------------------------------------------------------------------------------------------------------------------- + +$white: #ffffff; +$black: #000000; +$primary: #4950d8; +$secondary: adjust-color($primary, $saturation: -25%, $lightness: +16%); +$dark: #212529; +$cta: #ec8100; + +// Grays +$gray-0: #f8f9fa; +$gray-1: #f1f3f5; +$gray-2: #e9ecef; +$gray-3: #dee2e6; +$gray-4: #ced4da; +$gray-5: #adb5bd; +$gray-6: #868e96; +$gray-7: #565c63; +$gray-8: #343a40; +$gray-9: #212529; + +// Reds +$red-0: #fff5f5; +$red-1: #ffe3e3; +$red-2: #ffc9c9; +$red-3: #ffa8a8; +$red-4: #ff8787; +$red-5: #ff6b6b; +$red-6: #fa5252; +$red-7: #f03e3e; +$red-8: #e03131; +$red-9: #c92a2a; + +// Pinks +$pink-0: #fff0f6; +$pink-1: #ffdeeb; +$pink-2: #fcc2d7; +$pink-3: #faa2c1; +$pink-4: #f783ac; +$pink-5: #f06595; +$pink-6: #e64980; +$pink-7: #d6336c; +$pink-8: #c2255c; +$pink-9: #a61e4d; + +// Grapes +$grape-0: #f8f0fc; +$grape-1: #f3d9fa; +$grape-2: #eebefa; +$grape-3: #e599f7; +$grape-4: #da77f2; +$grape-5: #cc5de8; +$grape-6: #be4bdb; +$grape-7: #ae3ec9; +$grape-8: #9c36b5; +$grape-9: #862e9c; + +// Violets +$violet-0: #f3f0ff; +$violet-1: #e5dbff; +$violet-2: #d0bfff; +$violet-3: #b197fc; +$violet-4: #9775fa; +$violet-5: #845ef7; +$violet-6: #7950f2; +$violet-7: #7048e8; +$violet-8: #6741d9; +$violet-9: #5f3dc4; + +// Indigo's +$indigo-0: #edf2ff; +$indigo-1: #dbe4ff; +$indigo-2: #bac8ff; +$indigo-3: #91a7ff; +$indigo-4: #748ffc; +$indigo-5: #5c7cfa; +$indigo-6: #4c6ef5; +$indigo-7: #4263eb; +$indigo-8: #3b5bdb; +$indigo-9: #364fc7; + +// Blues +$blue-0: #e8e9ff; +$blue-1: #d1d3ff; +$blue-2: #a6aaff; +$blue-3: #8b91fc; +$blue-4: #7c82f7; +$blue-5: #686fe8; +$blue-6: #5b62e5; +$blue-7: $primary; +$blue-8: #1922c2; +$blue-9: #181fab; + +// Cyans +$cyan-0: #e3fafc; +$cyan-1: #c5f6fa; +$cyan-2: #99e9f2; +$cyan-3: #66d9e8; +$cyan-4: #3bc9db; +$cyan-5: #22b8cf; +$cyan-6: #15aabf; +$cyan-7: #1098ad; +$cyan-8: #0c8599; +$cyan-9: #0b7285; + +// Teals +$teal-0: #e6fcf5; +$teal-1: #c3fae8; +$teal-2: #96f2d7; +$teal-3: #63e6be; +$teal-4: #38d9a9; +$teal-5: #20c997; +$teal-6: #12b886; +$teal-7: #0ca678; +$teal-8: #099268; +$teal-9: #087f5b; + +// Greens +$green-0: #ebfbee; +$green-1: #d3f9d8; +$green-2: #b2f2bb; +$green-3: #8ce99a; +$green-4: #69db7c; +$green-5: #51cf66; +$green-6: #40c057; +$green-7: #37b24d; +$green-8: #2f9e44; +$green-9: #2b8a3e; + +// Limes +$lime-0: #f4fce3; +$lime-1: #e9fac8; +$lime-2: #d8f5a2; +$lime-3: #c0eb75; +$lime-4: #a9e34b; +$lime-5: #94d82d; +$lime-6: #82c91e; +$lime-7: #74b816; +$lime-8: #66a80f; +$lime-9: #5c940d; + +// Yellows +$yellow-0: #fff9db; +$yellow-1: #fff8c5; +$yellow-2: #ffec99; +$yellow-3: #ffe066; +$yellow-4: #ffd43b; +$yellow-5: #fcc419; +$yellow-6: #fab005; +$yellow-7: #f59f00; +$yellow-8: #f08c00; +$yellow-9: #e67700; + +// Oranges +$orange-0: #fff4e6; +$orange-1: #ffe8cc; +$orange-2: #ffd8a8; +$orange-3: #ffc078; +$orange-4: #ffa94d; +$orange-5: #ff922b; +$orange-6: #fd7e14; +$orange-7: #f76707; +$orange-8: #e8590c; +$orange-9: #d9480f; + +// frontend/scss/shared +$colourise-map: ( + "0": #ff6b6b, + "1": #fa5252, + "2": #f03e3e, + "3": #e03131, + "4": #c92a2a, + "5": #f06595, + "6": #e64980, + "7": #d6336c, + "8": #c2255c, + "9": #a61e4d, + "10": #cc5de8, + "11": #be4bdb, + "12": #ae3ec9, + "13": #9c36b5, + "14": #862e9c, + "15": #845ef7, + "16": #7950f2, + "17": #7048e8, + "18": #6741d9, + "19": #5f3dc4, + "20": #5c7cfa, + "21": #4c6ef5, + "22": #4263eb, + "23": #3b5bdb, + "24": #364fc7, + "25": #686fe8, + "26": #5b62e5, + "27": #4950d8, + "28": #1922c2, + "29": #181fab, + "30": #22b8cf, + "31": #15aabf, + "32": #1098ad, + "33": #0c8599, + "34": #0b7285, + "35": #20c997, + "36": #12b886, + "37": #0ca678, + "38": #099268, + "39": #087f5b, + "40": #51cf66, + "41": #40c057, + "42": #37b24d, + "43": #2f9e44, + "44": #2b8a3e, + "45": #94d82d, + "46": #82c91e, + "47": #74b816, + "48": #66a80f, + "49": #5c940d, + "50": #fcc419, + "51": #fab005, + "52": #f59f00, + "53": #f08c00, + "54": #e67700, + "55": #ff922b, + "56": #fd7e14, + "57": #f76707, + "58": #e8590c, + "59": #d9480f, +) diff --git a/assets/scss/comments/_comment-card.scss b/assets/scss/comments/_comment-card.scss new file mode 100644 index 000000000..1659d2075 --- /dev/null +++ b/assets/scss/comments/_comment-card.scss @@ -0,0 +1,164 @@ +@import "colours"; +@import "mixins"; + +.comentario-card { + display: flex; + margin-top: 16px; + border-top: 1px solid var(--cmntr-card-border); + + // Replaces the .comentario-card-expand-toggler in a card that has no children + .comentario-card-expand-spacer { + flex: 0 0 12px; + } + + // Clickable toggler on the left side of a card that has children + .comentario-card-expand-toggler { + flex: 0 0 12px; + cursor: pointer; + transition: border-left-width 0.1s linear; + + z-index: 2; // Custom: Place toggler above the overlapping padding region. + + &:hover:not(.comentario-collapsed) { + border-left-width: 4px !important; + } + + &.comentario-collapsed { + border-left-style: dotted !important; + } + } + + // Content of the card, taking up the remaining space right of the spacer or toggler + .comentario-card-expand-body { + flex: 1 1 100%; + + // Hide the content of the card when there's an editor inside it (immediate child only, not nested ones) + &.comentario-editor-inserted > .comentario-card-self { + display: none; + } + } + + .comentario-card-self { + padding-top: 12px; + + // Custom: extra padding so that highlight looks more spacy and less choked. + margin-left: -10px; + padding-left: 10px; + + // Add some breather space to the right. + padding-right: 6px; + } + + .comentario-card-children { + &.comentario-card-children-unnest { + margin-left: -12px; // To compensate for the spacer/toggler width + } + } + + .comentario-card-header { + display: flex; + width: 100%; + flex-wrap: wrap; + align-items: start; + margin-bottom: 6px; + } + + .comentario-name-container { + display: flex; + flex: 1 1; + flex-direction: column; + justify-content: start; + margin-bottom: 6px; + } + + .comentario-name-wrap { + display: flex; + flex-wrap: wrap; + } + + .comentario-name { + font-weight: bold; + font-size: 14px; + color: var(--cmntr-color) !important; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .comentario-subtitle { + color: var(--cmntr-muted-color); + font-size: 12px; + + a { + color: var(--cmntr-muted-color); + } + } + + .comentario-score { + display: inline; + color: var(--cmntr-score-color); + font-weight: 700; + transition: color 0.2s; + } + + .comentario-upvoted { + color: var(--cmntr-score-up-color); + } + + .comentario-downvoted { + color: var(--cmntr-score-down-color); + } + + .comentario-is-sticky { + color: var(--cmntr-sticky-color) !important; + } + + .comentario-card-body { + @include comment-text(); + } + + .comentario-moderation-notice { + width: 100%; + padding-top: 8px; + padding-bottom: 8px; + text-align: center; + color: var(--cmntr-warning-color); + } +} + +.comentario-deleted { + opacity: 0.33; + filter: grayscale(0.8); +} + +.comentario-pending { + background-color: var(--cmntr-pending-bg); + border: var(--cmntr-pending-border) dashed 1px; +} + +.comentario-rejected { + background-color: var(--cmntr-rejected-bg); +} + +.comentario-avatar { + width: 32px; + height: 32px; + border-radius: 50%; + display: flex; + justify-content: center; + align-items: center; + color: var(--cmntr-bg); + font-size: 20px; + margin-right: 10px; + border: 0 transparent; +} + +.comentario-avatar-img { + width: 32px; + height: 32px; + border-radius: 50%; + display: flex; + justify-content: center; + align-items: center; + margin-right: 10px; +} diff --git a/assets/scss/comments/_comment-editor.scss b/assets/scss/comments/_comment-editor.scss new file mode 100644 index 000000000..20ecc04d4 --- /dev/null +++ b/assets/scss/comments/_comment-editor.scss @@ -0,0 +1,25 @@ +@import "colours"; +@import "mixins"; + +.comentario-comment-editor { + width: 100%; + display: flex; + flex-direction: column; + + .comentario-comment-editor-footer { + display: flex; + flex-wrap: wrap; + justify-content: end; + align-items: center; + margin-top: 12px; + } + + .comentario-comment-editor-preview { + min-height: 130px; // Consistent with the min-height of a textarea + padding: 8px; + border: 1px solid $violet-2; + border-radius: 3px; + + @include comment-text(); + } +} diff --git a/assets/scss/comments/_common.scss b/assets/scss/comments/_common.scss new file mode 100644 index 000000000..2ac607530 --- /dev/null +++ b/assets/scss/comments/_common.scss @@ -0,0 +1,133 @@ +@import "colours"; + +*, ::after, ::before { + box-sizing: border-box; +} + +a { + color: var(--cmntr-link-color); + outline: none; + text-decoration: none; + cursor: pointer; + + &:not(.comentario-btn){ + &:hover, &:focus { + color: var(--cmntr-link-hover-color); + } + } +} + +blockquote { + margin: 0 0 0 8px; + padding: 0 0 0 5px; + border-left: 2px solid $gray-5; + color: var(--cmntr-muted-color); +} + +.comentario-icon { + display: inline-block; + width: 1em; + height: 1em; + vertical-align: -0.125em; +} + +.comentario-add-comment-host { + display: flex; + justify-content: center; + align-items: center; + align-content: center; + background-color: var(--cmntr-bg); + font-size: 15px; + + // Only show border and such when there's no editor inserted + &:not(.comentario-editor-inserted) { + min-height: 130px; + border: 1px solid $gray-2; + border-radius: 3px; + cursor: text; + + .comentario-add-comment-placeholder { + display: block; + color: var(--cmntr-input-ph-color); + } + } + + // Placeholder saying "Add a comment", only visible without the editor inserted + .comentario-add-comment-placeholder { + display: none; + } +} + +// Margins + +.comentario-ms-1 { + margin-left: 0.25em !important; +} + +.comentario-ms-2 { + margin-left: 0.5em !important; +} + +.comentario-me-1 { + margin-right: 0.25em !important; +} + +// Padding + +.comentario-py-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; +} + +// Font weight + +.comentario-fw-bold { + font-weight: bold !important; +} + +// Font size + +.comentario-small { + font-size: 85%; +} + +// Utilities + +.comentario-hidden { + display: none !important; +} + +.comentario-disabled { + opacity: 0.75; +} + +.comentario-text-center { + text-align: center !important; +} + +.comentario-flex { + display: flex !important; +} + +.comentario-flex-wrap { + flex-wrap: wrap !important; +} + +.comentario-flex-50 { + flex: 1 1 50%; +} + +// Colourising + +.comentario-text-muted { + color: var(--cmntr-muted-color) !important; +} +.comentario-text-success { + color: var(--cmntr-success-color) !important; +} +.comentario-text-danger { + color: var(--cmntr-danger-color) !important; +} +.comentario-text-warning { + color: var(--cmntr-warning-color) !important; +} diff --git a/assets/scss/comments/_dialog.scss b/assets/scss/comments/_dialog.scss new file mode 100644 index 000000000..b0661ba1b --- /dev/null +++ b/assets/scss/comments/_dialog.scss @@ -0,0 +1,114 @@ +@import "colours"; + +.comentario-dialog { + position: absolute; + z-index: 100; + + display: flex; + flex-direction: column; + width: 90%; + max-width: 500px; + min-height: 100px; + background-color: var(--cmntr-bg-shade); + border: 1px solid var(--cmntr-dlg-border); + box-shadow: 0 0 20px rgba(153, 153, 153, 0.5); + + hr { + border: none; + background: var(--cmntr-muted-color); + height: 1px; + margin: 12px 0; + } + + .comentario-dialog-header { + position: relative; + display: flex; + align-items: center; + background-color: var(--cmntr-dlg-header-bg); + padding: 6px 16px; + line-height: 24px; + font-weight: bold; + + .comentario-dialog-btn-close { + --cmntr-btn-color: var(--cmntr-muted-color); + + position: absolute; + top: 0; + right: 0; + z-index: 2; + border: 0; + padding: 2px; + + .comentario-icon { + width: 1.5em; + height: 1.5em; + } + } + } + + .comentario-dialog-body { + padding: 16px; + overflow: hidden; + } + + .comentario-dialog-centered { + color: var(--cmntr-muted-color); + text-align: center; + margin: 8px 0; + } + + // Arrow + + .comentario-dialog-arrow, + .comentario-dialog-arrow::before { + position: absolute; + z-index: 101; + width: 12px; + height: 12px; + background-color: var(--cmntr-bg-shade); // Match colour with the dialog body by default + border: 1px solid transparent; + } + + .comentario-dialog-arrow { + visibility: hidden; + } + + .comentario-dialog-arrow::before { + visibility: visible; + content: ''; + transform: rotate(45deg); + } + + &[data-popper-placement^='top'] > .comentario-dialog-arrow { + bottom: -6px; + &::before { + border-right-color: var(--cmntr-dlg-border); + border-bottom-color: var(--cmntr-dlg-border); + } + } + + &[data-popper-placement^='bottom'] > .comentario-dialog-arrow { + top: -7px; + &::before { + background-color: var(--cmntr-dlg-header-bg); // Match colour with the dialog header when the arrow is on the top + border-left-color: var(--cmntr-dlg-border); + border-top-color: var(--cmntr-dlg-border); + } + } + + &[data-popper-placement^='left'] > .comentario-dialog-arrow { + right: -6px; + &::before { + border-right-color: var(--cmntr-dlg-border); + border-top-color: var(--cmntr-dlg-border); + } + } + + &[data-popper-placement^='right'] > .comentario-dialog-arrow { + left: -7px; + &::before { + border-left-color: var(--cmntr-dlg-border); + border-bottom-color: var(--cmntr-dlg-border); + } + } +} diff --git a/assets/scss/comments/_footer.scss b/assets/scss/comments/_footer.scss new file mode 100644 index 000000000..b26fc3169 --- /dev/null +++ b/assets/scss/comments/_footer.scss @@ -0,0 +1,11 @@ +@import "colours"; + +.comentario-footer { + display: flex; + justify-content: end; + margin: 12px 0; + padding-right: 12px; + font-size: 13px; + line-height: 24px; + color: var(--cmntr-muted-color); +} diff --git a/assets/scss/comments/_input.scss b/assets/scss/comments/_input.scss new file mode 100644 index 000000000..e7b7c4913 --- /dev/null +++ b/assets/scss/comments/_input.scss @@ -0,0 +1,234 @@ +@import "colours"; + +textarea, +input[type=text], +input[type=email], +input[type=url], +input[type=password] { + background-color: var(--cmntr-input-bg); + border: 1px solid rgba(50, 50, 93, .1); + border-radius: 3px; + color: var(--cmntr-input-color); + + // Draw a red border around invalid controls that have been touched (blurred; gets added programmatically) + &.comentario-touched:invalid { + border: 1px solid $red-7; + } + + &::placeholder { + color: var(--cmntr-input-ph-color); + } + + &:disabled { + color: var(--cmntr-input-disabled-color); + } +} + +textarea { + display: inline-block; + white-space: pre-wrap; + padding: 8px; + outline: none; + overflow: auto; + min-height: 130px; + width: 100%; + transition: all 0.2s; + + &::placeholder { + font-size: 18px; + display: flex; + line-height: 110px; + justify-content: center; + align-items: center; + text-align: center; + } + + &:focus { + outline: none; + border-color: $blue-2; + outline: 0; + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.075), 0 0 0 0.25rem transparentize($blue-6, 0.75); + } +} + +.comentario-checkbox-group { + margin-left: 8px; + margin-right: 8px; + + .comentario-checkbox-container { + display: block; + } +} + +.comentario-checkbox-container { + display: inline-block; + min-height: 22px; + padding-left: 24px; + margin-bottom: 2px; + + input { + float: left; + margin-left: -24px; + width: 20px; + height: 20px; + vertical-align: top; + background: #fff no-repeat center; + background-size: contain; + border: 1px solid rgba(0,0,0,.25); + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + + &:checked { + background-color: $primary; + border-color: $primary; + } + &:disabled { + pointer-events: none; + filter: none; + opacity: 0.5; + } + &[disabled], + &:disabled { + ~ label { + cursor: default; + opacity: 0.5; + } + } + + } + + input[type="checkbox"] { + border-radius: 5px; + + &:checked { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/%3e%3c/svg%3e"); + } + } + + label { + color: var(--cmntr-label-color); + font-size: 13px; + } +} + +.comentario-input-group { + flex: 1 1 100%; + display: flex; + align-items: stretch; + box-shadow: 0 1px 3px rgba(50, 50, 93, .15), 0 1px 0 rgba(0, 0, 0, .02); + border-radius: 4px; + background-color: var(--cmntr-bg); + margin: 8px; + + .comentario-input { + flex-grow: 1; + height: 40px; + background-color: var(--cmntr-bg); + border: none; + outline: none; + padding: 5px 5px 5px 10px; + + &::placeholder { + color: var(--cmntr-input-ph-color); + } + } + + .comentario-btn { + box-shadow: none; + margin: 0; + } +} + +.comentario-form-text { + margin: 2px 8px; + font-size: 13px; + color: var(--cmntr-muted-color); +} + +.comentario-round-check { + input[type="radio"], + input[type="checkbox"] { + display: none; + } + + input[type="radio"] + label, + input[type="checkbox"] + label { + display: block; + position: relative; + padding-left: 35px; + margin-bottom: 5px; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + } + + input[type="radio"] + label:last-child, + input[type="checkbox"] + label:last-child { + margin-bottom: 0; + } + + input[type="radio"] + label:before, + input[type="checkbox"] + label:before { + content: ''; + display: block; + width: 13px; + height: 13px; + margin-top: 2px; + background: $gray-0; + border: 1px solid $gray-3; + border-radius: 3px; + position: absolute; + left: 0; + top: 0; + transition: all .15s; + } + + input[type="radio"]:disabled + label:before, + input[type="checkbox"]:disabled + label:before { + background: $gray-0; + border: 1px solid $gray-4; + opacity: 0.4; + } + + input[type="radio"]:checked + label:before, + input[type="checkbox"]:checked + label:before { + background: $blue-6; + border: 1px solid $blue-6; + } + + input[type="radio"] + label:after, + input[type="checkbox"] + label:after { + position: absolute; + left: -7px; + top: 4px; + content: ''; + display: inline-block; + width: 3px; + height: 7px; + transform: rotate(45deg); + margin-left: 12px; + margin-right: 12px; + border: solid transparent; + border-width: 0 2px 2px 0; + } + + input[type="radio"]:disabled + label:after, + input[type="checkbox"]:disabled + label:after { + border: solid transparent; + border-width: 0 2px 2px 0; + } + + input[type="radio"]:checked + label:after, + input[type="checkbox"]:checked + label:after { + border: solid $gray-0; + border-width: 0 2px 2px 0; + } + + .pitch { + font-size: 14px; + color: #a5a5a5; + line-height: 20px !important; + } +} diff --git a/assets/scss/comments/_mixins.scss b/assets/scss/comments/_mixins.scss new file mode 100644 index 000000000..44505f1b2 --- /dev/null +++ b/assets/scss/comments/_mixins.scss @@ -0,0 +1,57 @@ +@import "colours"; + +@mixin btn-shadow { + box-shadow: 0 0.25rem 0.375rem rgba(50, 50, 93, .11), 0 0.0625rem 0.1875rem rgba(0, 0, 0, .08); +} + +@mixin btn-active-shadow { + box-shadow: inset 0 0.25rem 0.375rem rgba(50, 50, 93, .11), inset 0.0625rem 0.1875rem rgba(0, 0, 0, .08); +} + +@mixin media-breakpoint-up-sm { + @media (min-width: 576px) { + @content; + } +} + +// Styling for correct rendering of comment text +@mixin comment-text { + p { + margin-top: 6px; + margin-bottom: 6px; + } + + // Do not allow Markdown-inserted images to be wider than the card + img { + max-width: 100%; + } + + // Properly style inserted tables + table { + margin-bottom: 12px; + vertical-align: top; + border-color: var(--cmntr-table-border); + caption-side: bottom; + border-collapse: collapse; + + tbody > tr:nth-of-type(odd) > * { + background-color: rgba(var(--cmntr-color), .05); + } + + td, th { + padding: 6px 9px; + border: 1px solid var(--cmntr-table-border); + } + } + + code { + font-family: monospace; + font-size: 13px; + white-space: pre; + } + + pre { + padding: 6px; + background-color: var(--cmntr-bg-shade); + } +} diff --git a/assets/scss/comments/_placeholders.scss b/assets/scss/comments/_placeholders.scss new file mode 100644 index 000000000..8ba426711 --- /dev/null +++ b/assets/scss/comments/_placeholders.scss @@ -0,0 +1,61 @@ +@import "colours"; + +.comentario-ph-button { + display: inline-block; + width: 75px; + height: 32px; + margin: 5px; +} + +.comentario-ph-profile-bar { + height: 60px; + margin-top: -16px; // To offset the real, empty profile bar + padding-top: 0.5rem; + padding-bottom: 0.5rem; + text-align: right; +} + +.comentario-ph-add-comment-host { + height: 130px; + border-radius: 3px; + margin-bottom: 30px; +} + +.comentario-ph-comment-card { + height: 120px; + margin-top: 16px; + padding-left: 12px; + border-top: 1px solid $gray-1; + border-left: 2px solid $gray-4; + + .comentario-ph-card-header { + height: 32px; + margin-top: 6px; + margin-bottom: 12px; + border-radius: 3px; + } + + .comentario-ph-card-text { + height: 12px; + margin-bottom: 6px; + border-radius: 1.5px; + } +} + +.comentario-ph-bg { + background-color: var(--cmntr-placeholder-bg); + opacity: .5; + mask-image: linear-gradient( + 130deg, + var(--cmntr-placeholder-mask) 40%, + rgba(0, 0, 0, .2) 50%, + var(--cmntr-placeholder-mask) 60%); + mask-size: 200% 100%; + animation: comentario-ph-bg 2s linear infinite; +} + +@keyframes comentario-ph-bg { + to { + mask-position: -200% 0%; + } +} diff --git a/assets/scss/comments/_sort-bar.scss b/assets/scss/comments/_sort-bar.scss new file mode 100644 index 000000000..12974395e --- /dev/null +++ b/assets/scss/comments/_sort-bar.scss @@ -0,0 +1,29 @@ +@import "colours"; + +.comentario-sort-bar { + + // Clearfix + &::after { + display: block; + clear: both; + content: ""; + } + + .comentario-sort-buttons { + float: right; + } + + .comentario-btn { + + // The down caret icon + .comentario-icon { + width: 8px; + height: 8px; + transition: transform 0.2s; + } + + &.comentario-sort-asc .comentario-icon { + transform: rotate(180deg); + } + } +} diff --git a/assets/scss/comments/_source-sans.scss b/assets/scss/comments/_source-sans.scss new file mode 100644 index 000000000..6dff83349 --- /dev/null +++ b/assets/scss/comments/_source-sans.scss @@ -0,0 +1,209 @@ +/* cyrillic-ext */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-display: swap; + font-weight: 300; + src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url([[[.CdnPrefix]]]/en/fonts/source-sans-300-cyrillic-ext.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} + +/* cyrillic */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-display: swap; + font-weight: 300; + src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url([[[.CdnPrefix]]]/en/fonts/source-sans-300-cyrillic.woff2) format('woff2'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} + +/* greek-ext */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-display: swap; + font-weight: 300; + src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url([[[.CdnPrefix]]]/en/fonts/source-sans-300-greek-ext.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} + +/* greek */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-display: swap; + font-weight: 300; + src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url([[[.CdnPrefix]]]/en/fonts/source-sans-300-greek.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} + +/* vietnamese */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-display: swap; + font-weight: 300; + src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url([[[.CdnPrefix]]]/en/fonts/source-sans-300-vietnamese.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; +} + +/* latin-ext */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-display: swap; + font-weight: 300; + src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url([[[.CdnPrefix]]]/en/fonts/source-sans-300-latin-ext.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} + +/* latin */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-display: swap; + font-weight: 300; + src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url([[[.CdnPrefix]]]/en/fonts/source-sans-300-latin.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + +/* cyrillic-ext */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-display: swap; + font-weight: 400; + src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url([[[.CdnPrefix]]]/en/fonts/source-sans-400-cyrillic-ext.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} + +/* cyrillic */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-display: swap; + font-weight: 400; + src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url([[[.CdnPrefix]]]/en/fonts/source-sans-400-cyrillic.woff2) format('woff2'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} + +/* greek-ext */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-display: swap; + font-weight: 400; + src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url([[[.CdnPrefix]]]/en/fonts/source-sans-400-greek-ext.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} + +/* greek */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-display: swap; + font-weight: 400; + src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url([[[.CdnPrefix]]]/en/fonts/source-sans-400-greek.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} + +/* vietnamese */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-display: swap; + font-weight: 400; + src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url([[[.CdnPrefix]]]/en/fonts/source-sans-400-vietnamese.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; +} + +/* latin-ext */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-display: swap; + font-weight: 400; + src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url([[[.CdnPrefix]]]/en/fonts/source-sans-400-latin-ext.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} + +/* latin */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-display: swap; + font-weight: 400; + src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url([[[.CdnPrefix]]]/en/fonts/source-sans-400-latin.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + +/* cyrillic-ext */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-display: swap; + font-weight: 700; + src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url([[[.CdnPrefix]]]/en/fonts/source-sans-700-cyrillic-ext.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} + +/* cyrillic */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-display: swap; + font-weight: 700; + src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url([[[.CdnPrefix]]]/en/fonts/source-sans-700-cyrillic.woff2) format('woff2'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} + +/* greek-ext */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-display: swap; + font-weight: 700; + src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url([[[.CdnPrefix]]]/en/fonts/source-sans-700-greek-ext.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} + +/* greek */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-display: swap; + font-weight: 700; + src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url([[[.CdnPrefix]]]/en/fonts/source-sans-700-greek.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} + +/* vietnamese */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-display: swap; + font-weight: 700; + src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url([[[.CdnPrefix]]]/en/fonts/source-sans-700-vietnamese.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; +} + +/* latin-ext */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-display: swap; + font-weight: 700; + src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url([[[.CdnPrefix]]]/en/fonts/source-sans-700-latin-ext.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} + +/* latin */ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-display: swap; + font-weight: 700; + src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url([[[.CdnPrefix]]]/en/fonts/source-sans-700-latin.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/assets/scss/comments/_table.scss b/assets/scss/comments/_table.scss new file mode 100644 index 000000000..31c571f69 --- /dev/null +++ b/assets/scss/comments/_table.scss @@ -0,0 +1,18 @@ +@import "colours"; + +.comentario-table-container { + max-width: 100%; + overflow-x: auto; +} + +.comentario-table { + tr { + &:not(:last-child) { + border-bottom: 1px solid transparentize($gray-6, 0.5); + } + td { + padding: 4px 8px; + } + } +} + diff --git a/assets/scss/comments/_theme.scss b/assets/scss/comments/_theme.scss new file mode 100644 index 000000000..cd663d2c0 --- /dev/null +++ b/assets/scss/comments/_theme.scss @@ -0,0 +1,80 @@ +@import "colours"; + +@mixin theme-props($theme: light) { + // Light theme properties + @if $theme == light { + --cmntr-bg: #{$white}; + --cmntr-bg-shade: #{$gray-1}; + --cmntr-bg-highlight: #{$indigo-2}; + --cmntr-bg-blink: #{$yellow-3}; + --cmntr-danger-bg: #{$red-1}; + --cmntr-deleted-bg: #{$pink-2}; + --cmntr-dlg-header-bg: #{$gray-3}; + --cmntr-input-bg: #{$white}; + --cmntr-pending-bg: #{$gray-2}; + --cmntr-placeholder-bg: #{$gray-3}; + --cmntr-placeholder-mask: #{$gray-9}; + --cmntr-rejected-bg: #{$yellow-1}; + --cmntr-success-bg: #{$green-1}; + --cmntr-warning-bg: #{$yellow-1}; + + --cmntr-color: #{$gray-8}; + --cmntr-danger-color: #{$red-7}; + --cmntr-input-color: #{$gray-7}; + --cmntr-input-ph-color: #{$gray-5}; + --cmntr-input-disabled-color: #{$gray-6}; + --cmntr-label-color: #{$gray-7}; + --cmntr-link-color: #{$blue-9}; + --cmntr-link-hover-color: #{$blue-6}; + --cmntr-muted-color: #{$gray-6}; + --cmntr-score-color: #{$gray-4}; + --cmntr-score-up-color: #{$green-6}; + --cmntr-score-down-color: #{$orange-6}; + --cmntr-sticky-color: #{$yellow-4}; + --cmntr-success-color: #{$green-7}; + --cmntr-warning-color: #{$yellow-7}; + + --cmntr-card-border: #{$gray-1}; + --cmntr-dlg-border: #{$gray-5}; + --cmntr-pending-border: #{$yellow-6}; + --cmntr-table-border: #{$gray-3}; + + // Dark theme properties + } @else { + color-scheme: dark; + --cmntr-bg: #{$gray-9}; + --cmntr-bg-shade: #{$gray-8}; + --cmntr-bg-highlight: #{$indigo-7}; + --cmntr-bg-blink: #{$yellow-6}; + --cmntr-danger-bg: #{$red-9}; + --cmntr-deleted-bg: #{$pink-5}; + --cmntr-dlg-header-bg: #{$gray-6}; + --cmntr-input-bg: #{$gray-9}; + --cmntr-pending-bg: #{$gray-7}; + --cmntr-placeholder-bg: #{$gray-6}; + --cmntr-rejected-bg: #{$yellow-8}; + --cmntr-success-bg: #{$green-8}; + --cmntr-warning-bg: #{$yellow-8}; + + --cmntr-color: #{$gray-1}; + --cmntr-danger-color: #{$red-2}; + --cmntr-input-color: #{$gray-2}; + --cmntr-input-ph-color: #{$gray-4}; + --cmntr-input-disabled-color: #{$gray-3}; + --cmntr-label-color: #{$gray-2}; + --cmntr-link-color: #{$blue-3}; + --cmntr-link-hover-color: #{$blue-6}; + --cmntr-muted-color: #{$gray-3}; + --cmntr-score-color: #{$gray-5}; + --cmntr-score-up-color: #{$green-3}; + --cmntr-score-down-color: #{$orange-3}; + --cmntr-sticky-color: #{$yellow-5}; + --cmntr-success-color: #{$green-2}; + --cmntr-warning-color: #{$yellow-2}; + + --cmntr-card-border: #{$gray-8}; + --cmntr-dlg-border: #{$gray-4}; + --cmntr-pending-border: #{$yellow-3}; + --cmntr-table-border: #{$gray-6}; + } +} diff --git a/assets/scss/comments/_toolbar.scss b/assets/scss/comments/_toolbar.scss new file mode 100644 index 000000000..c4afb17c6 --- /dev/null +++ b/assets/scss/comments/_toolbar.scss @@ -0,0 +1,40 @@ +@import "colours"; + +.comentario-toolbar { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + + .comentario-toolbar-section { + display: flex; + align-items: center; + } + + .comentario-btn-tool { + --cmntr-btn-color: var(--cmntr-muted-color); + + margin: 0; + padding: 0; + width: 32px; + height: 32px; + opacity: 0.5; + + &.comentario-btn-lg { + width: 40px; + height: 40px; + + .comentario-icon { + width: 1.25em; + height: 1.25em; + } + } + } + + &.comentario-disabled { + background-color: var(--cmntr-bg-shade); + + .comentario-btn-tool { + pointer-events: none; + } + } +} diff --git a/content/content.11tydata.js b/content/content.11tydata.js index 15dfb2211..7360cbf01 100644 --- a/content/content.11tydata.js +++ b/content/content.11tydata.js @@ -10,7 +10,7 @@ module.exports = { permalink: data => (data.draft && !process.env.BUILD_DRAFTS ? false : data.permalink), hasPostedDate: data => { const file = data.page.inputPath.split('/').pop(); - return !!(file.match(/^\d+-\d+-\d+/) || data.date); + return !!(file.match(/^\d+-\d+-\d+/)); }, hasUpdatedDate: _ => true, date: data => { diff --git a/content/pages/postlike/privacy-policy.md b/content/pages/postlike/privacy-policy.md index d965137a5..b6b1661d7 100644 --- a/content/pages/postlike/privacy-policy.md +++ b/content/pages/postlike/privacy-policy.md @@ -19,29 +19,28 @@ related: We collect the following personal data: * **Technical Data**: IP address, Browser type, Device type, Referrer data. - * This is collected by Cloudflare Pages, Cloudflare Web Analytics, {# Disqus, #} and jsDelivr. + * This is collected by Cloudflare Pages, Cloudflare Web Analytics, and jsDelivr. * {{ site.title }} will only access such data in aggregate forms, and thus won't (be able to) link this data back to you. * This data is provided automatically by your browser when you load a web page. A VPN may be used to suppress or hide such data. * **Cookies** - * This is data associated with you (based on your browser activity) and may be used by third-party services to track you. - * Used by Cloudflare Pages^[Cloudflare Pages may use cookies to combat spam and malicious activity. See their [cookie policy](https://www.cloudflare.com/cookie-policy/).]{# , Disqus, #} and SoundCloud embeds. + * This is data associated with you due to activities such as login/commenting. + * Used by Cloudflare Pages^[Cloudflare Pages may use cookies to combat spam and malicious activity. See their [cookie policy](https://www.cloudflare.com/cookie-policy/).], our commenting system, and SoundCloud embeds. * Cloudflare *Analytics* and jsDelivr claim they don't use cookies. ([Cloudflare](https://www.cloudflare.com/web-analytics/#:~:text=Cloudflare%20Web%20Analytics%20does%20not,the%20purpose%20of%20displaying%20analytics.); [jsDelivr](https://www.jsdelivr.com/terms/privacy-policy-jsdelivr-net#:~:text=We%20do%20not%20use%20cookies)) * **Identity Data**: Name, Email address. - * In the [Contact Form][contact-form], these are **optional** fields. You have the discretion to *not* fill in those fields. - {# * In Disqus guest commenting, these are **mandatory** fields #} + * In the [Contact Form][contact-form] and Commenting Forms, these are **optional** fields. You have the discretion to *not* fill in those fields. ## Data Usage We use personal data for the following purposes: -- **Technical Data**: To optimise website experience. To draw insights on readers and to improve the site. +- **Technical Data**: To optimise website experience. To draw insights from readers and to improve the site. - **Identity Data**: For contact and communication purposes. To personalise responses to comments. Third-party services may have other clauses, especially for cookies. Please refer to their [privacy policies](#third-party). ## Data Sharing -We do not share your personal data with third-parties. Any personal data collected by third-parties were obtained when you load the page, when use a third-party account, or when you voluntarily submit your identity data. +We do not share your personal data with third-parties. ## Data Protection, Retention, and Rights @@ -49,6 +48,7 @@ Whilst personal data helps us improve the site, such data does not reside with u Data entered into the contact form is retained up to 30 days by FormCarry, according to custom configuration. +For the commenting system, any data such as comments and user information will be retained indefinitely; but you may [submit a request][contact-form] to have your account deleted or your comments removed. ## Changes to the Privacy Policy @@ -70,17 +70,14 @@ For your reference, here is a collection of third-party services we use and thei | FormCarry | Forms | ✓ | ✓[^fc1] | | | {% endtable %} -{# | Disqus[^disqus] | Comments | ✓ | ✓[^dq1] | ✓ | [Link][pdqs] | #} [pghp]: https://docs.github.com/en/pages/getting-started-with-github-pages/about-github-pages#data-collection [pjsd]: https://www.jsdelivr.com/terms/privacy-policy-jsdelivr-net [cclf]: https://www.cloudflare.com/cookie-policy/ [pclf]: https://www.cloudflare.com/privacypolicy -{# [pdqs]: https://help.disqus.com/en/articles/1717103-disqus-privacy-policy #} [pscl]: https://soundcloud.com/pages/privacy [^u]: Third-party data collection as of writing. Their policies may have updated since. -{# [^dq1]: Applicable if commenting or logged in. #} [^sc1]: Applicable if logged in. [^fc1]: Applicable if filled in. @@ -88,9 +85,6 @@ For your reference, here is a collection of third-party services we use and thei - SoundCloud embeds are only loaded on relevant pages (music pages, home page, etc.). - FormCarry only applies to pages containing forms (e.g. the contact form). -{# - Disqus will only be loaded on posts which allow comments, and when the page is scrolled down far enough. #} -{# [^disqus]: Free tier. Supposedly comes with advertising. #} - ## Contact If you have any questions or concerns about our privacy policy, please [contact us][contact-form]. diff --git a/content/posts/infosec/automating-boolean-sqli/2024-08-10-automating-boolean-sql-injection-with-python.md b/content/posts/infosec/automating-boolean-sqli/2024-08-10-automating-boolean-sql-injection-with-python.md index 9696dee1a..90ae4f33d 100644 --- a/content/posts/infosec/automating-boolean-sqli/2024-08-10-automating-boolean-sql-injection-with-python.md +++ b/content/posts/infosec/automating-boolean-sqli/2024-08-10-automating-boolean-sql-injection-with-python.md @@ -15,7 +15,7 @@ preamble: | *This is meant as an introductory post on Boolean-Based SQLi and automation with Python; with ideas, tricks, and tips gleaned from developing [a custom SQLi script](https://github.com/TrebledJ/bsqli.py). More experienced scripters or pentesters may find the middle sections more informative.* --- -When performing a penetration test, we occasionally come across SQL injection (SQLi) vulnerabilities. One particular class of SQLi is particularly tedious to manually exploit — Boolean-Based SQLi. +When performing a penetration test, we occasionally come across SQL injection (SQLi) vulnerabilities. One particular class of SQLi is particularly tedious to exploit — Boolean-Based SQLi. Tedious, heavily-repetitive tasks often present themselves as nice opportunities for automation. In this post, we’ll review Boolean-Based SQL Injection, and explore how to automate it with Python by starting with a basic script, optimising, applying multithreading, and more. We'll mainly focus on high-level approaches towards automation and keep our code snippets short. diff --git a/partials/_data/csp.js b/partials/_data/csp.js index a94fcf6c4..445cc9795 100644 --- a/partials/_data/csp.js +++ b/partials/_data/csp.js @@ -28,6 +28,7 @@ module.exports = compileCsp( // unsafe-inline. .add(...(process.env.ENVIRONMENT === 'fast' ? ["'unsafe-inline'"] : [])) // .add('*.disqus.com', '*.disquscdn.com') + .add('comments.trebledj.me') .add('code.jquery.com', 'cdn.jsdelivr.net') .add('gist.github.com') .add('static.cloudflareinsights.com'), @@ -35,21 +36,26 @@ module.exports = compileCsp( .add("'unsafe-inline'") // .add(`'unsafe-hashes'`) // .add('*.disquscdn.com') + .add('comments.trebledj.me') .add('cdn.jsdelivr.net') .add('cdnjs.cloudflare.com') .add('github.githubassets.com'), tag('font') .add('data:') + .add('comments.trebledj.me') .add('cdn.jsdelivr.net') .add('cdnjs.cloudflare.com'), tag('img') - .add('data:'), + .add('data:') + .add('comments.trebledj.me'), // .add('c.disquscdn.com'), // .add('*') tag('frame') // .add('disqus.com') .add('*.soundcloud.com'), tag('connect') + .add('comments.trebledj.me') + .add('wss://comments.trebledj.me') .add('cloudflareinsights.com') .add('formcarry.com') // contact form , diff --git a/partials/_data/site.js b/partials/_data/site.js index 044771350..87bf5b76e 100644 --- a/partials/_data/site.js +++ b/partials/_data/site.js @@ -89,11 +89,11 @@ module.exports = function () { scope: 'local', // Possible values: 'session', 'local', ''. // bgColor: 'primary', // Any Bootstrap `bg-` values. // fgColor: 'black', // Any Bootstrap `text-` values. - icon: 'fas fa-droplet', + icon: 'fas fa-comments', icon_style: '--fa-animation-delay: 5s; --fa-animation-duration: 3s', /* eslint-disable max-len */ content: multiline(` - [***I'm now a Certified Offensive Waterblower!***](/posts/im-a-certified-offensive-waterblower){.text-warning} + Comments are back! Privacy-focused, without ads, bloatware, and trackers. `), /* eslint-enable max-len */ hash() { diff --git a/partials/_includes/head.html b/partials/_includes/head.html index 05d3676c7..c3133bbad 100644 --- a/partials/_includes/head.html +++ b/partials/_includes/head.html @@ -38,5 +38,9 @@ {% endfor %} {% endif %} + {% if comments %} + + {% endif %} + \ No newline at end of file diff --git a/partials/_includes/layouts/post-default.njk b/partials/_includes/layouts/post-default.njk index bf8880499..992048381 100644 --- a/partials/_includes/layouts/post-default.njk +++ b/partials/_includes/layouts/post-default.njk @@ -49,7 +49,7 @@ LMK if you know a better (less hacky) way of doing this. {% include "post/related.html" %} {% if comments %}
-
+
{% include "post/comments.html" %}
{% endif %} diff --git a/partials/_includes/post/comments.html b/partials/_includes/post/comments.html index da4e56f97..93f98d5fe 100644 --- a/partials/_includes/post/comments.html +++ b/partials/_includes/post/comments.html @@ -1,12 +1,5 @@ -{% if site.environment == 'production' %} - {#
- {% include "utilities/disqus.html" %} - #} -

Commenting has vanished into a blackhole and shall return some time in the future (or past?)! Time paradoxes not guaranteed. If you have any feedback or suggestions, please direct your subspace frequencies to the contact form. Thanks!

-{% else %} - {# Never enable Disqus comments in non-prod. It'll mess with their identifier machinery. #} -

Comments have been disabled in non-production.

-{% endif %} \ No newline at end of file +{#

Commenting has vanished into a blackhole and shall return some time in the future or past! Time paradoxes not guaranteed. If you have any feedback or suggestions, please direct your subspace frequencies to the contact form. Thanks!

#} +

Comments are back! Privacy-focused, without ads, bloatware, and trackers. Be one of the first to contribute to the discussion — I'd love to hear your thoughts.

+ + \ No newline at end of file diff --git a/partials/_includes/sidebars/toc-sidebar.html b/partials/_includes/sidebars/toc-sidebar.html index c5298c8b2..4617fdb9d 100644 --- a/partials/_includes/sidebars/toc-sidebar.html +++ b/partials/_includes/sidebars/toc-sidebar.html @@ -14,11 +14,11 @@ {% endif %} {# Comments #} - {# {% if comments %} + {% if comments %} - {% endif %} #} + {% endif %}
\ No newline at end of file diff --git a/partials/_includes/utilities/metadata.html b/partials/_includes/utilities/metadata.html index e1018a2e5..874d0b208 100644 --- a/partials/_includes/utilities/metadata.html +++ b/partials/_includes/utilities/metadata.html @@ -3,12 +3,12 @@ {% set isArticle = page.url.startsWith("/posts/") and layout.startsWith("layouts/post-") %} {% if title %} - +{# #} {% set safeTitle = title | stripBetweenTags(['sup', 'sub']) | striptags %} - +{# #} {% endif %} {% if excerpt %} - +{# #} {% set safeExcerpt = excerpt | mdInline | safe | striptags %} {% endif %} @@ -30,7 +30,7 @@ {# Compatibility #} - + {# Meta: Keywords #} {# List a bunch of keywords which make sense for this page. #}