Clean up styles, fix and improve the blog post card layout
This commit is contained in:
parent
a7f2d527dc
commit
830c34855c
|
@ -3,6 +3,8 @@
|
||||||
// Modules.
|
// Modules.
|
||||||
@use 'transitions';
|
@use 'transitions';
|
||||||
@use 'lists';
|
@use 'lists';
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
|
@ -85,32 +87,34 @@ body {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
@layer base {
|
||||||
|
h1, h2, h3, h4, h5, h6,
|
||||||
|
.text-h1, .text-h2, .text-h3, .text-h4, .text-h5, .text-h6 {
|
||||||
@apply font-serif;
|
@apply font-serif;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1, .text-h1 {
|
||||||
font-size: 2.5rem;
|
font-size: 2.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2, .text-h2 {
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h3, .text-h3 {
|
||||||
font-size: 1.75rem;
|
font-size: 1.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
h4 {
|
h4, .text-h4 {
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
h5 {
|
h5, .text-h5 {
|
||||||
font-size: 1.25rem;
|
font-size: 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
h6 {
|
h6, .text-h6 {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,275 +147,30 @@ center {
|
||||||
@apply mb-4;
|
@apply mb-4;
|
||||||
}
|
}
|
||||||
|
|
||||||
:is(h1, h2, h3, h4, h5, h6):not(:last-child) {
|
:is(h1, h2, h3, h4, h5, h6) {
|
||||||
|
a {
|
||||||
|
@apply text-inherit no-underline transition-all;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: indianred;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
@apply mb-2;
|
@apply mb-2;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
:is(ul, ol):not(:last-child) {
|
:is(ul, ol):not(:last-child) {
|
||||||
@apply mb-4;
|
@apply mb-4;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
iconify-icon {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Entry point (Vue mount).
|
|
||||||
#ender-app {
|
|
||||||
flex: 1 0 auto;
|
|
||||||
image-rendering: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper classes that don't exist in Bootstrap.
|
|
||||||
.overlay {
|
|
||||||
grid-area: 1 / 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pass-through {
|
|
||||||
pointer-events: none;
|
|
||||||
|
|
||||||
> * {
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ruby {
|
|
||||||
ruby-position: under;
|
|
||||||
|
|
||||||
ruby {
|
|
||||||
ruby-position: over;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rt {
|
|
||||||
ruby-align: space-around;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.font-small {
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.transition-ease {
|
|
||||||
@extend %transition;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Query-overridable classes.
|
|
||||||
.dimensions {
|
|
||||||
width: 100%;
|
|
||||||
min-height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.accent-background {
|
|
||||||
background-color: rgb(0 0 0 / 50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.accent-overlay-background {
|
|
||||||
background-color: rgb(0 0 0 / 90%);
|
|
||||||
}
|
|
||||||
|
|
||||||
@responsive {
|
|
||||||
.accent-text {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-dark {
|
|
||||||
@apply text-inherit no-underline transition-all;
|
|
||||||
|
|
||||||
color: cornflowerblue;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: royalblue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fade-mask {
|
|
||||||
mask-image: linear-gradient(to bottom, rgb(0 0 0 / 0%), rgb(0 0 0 / 100%) 5%, rgb(0 0 0 / 100%) 95%, rgb(0 0 0 / 0%));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog {
|
|
||||||
display: grid;
|
|
||||||
|
|
||||||
min-width: 240px;
|
|
||||||
max-width: 640px;
|
|
||||||
|
|
||||||
background-color: rgb(25 20 40 / 95%);
|
|
||||||
box-shadow: rgb(81 75 89 / 50%) 7px 7px 2em;
|
|
||||||
border-radius: 16px !important;
|
|
||||||
|
|
||||||
> div.background {
|
|
||||||
background-image: url('~/assets/images/textures/aero.png');
|
|
||||||
background-attachment: scroll;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-size: cover;
|
|
||||||
background-blend-mode: lighten;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
opacity: 0.2;
|
|
||||||
|
|
||||||
box-shadow: azure 0 0 20rem;
|
|
||||||
filter: blur(5px);
|
|
||||||
}
|
|
||||||
|
|
||||||
> div.content > img.icon-badge {
|
|
||||||
position: fixed;
|
|
||||||
margin-top: -20px;
|
|
||||||
margin-left: -20px;
|
|
||||||
transform: rotate(-25deg);
|
|
||||||
width: 60px;
|
|
||||||
height: 60px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
%transition {
|
|
||||||
transition: 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.parallax {
|
|
||||||
transition: all 0.6942s ease-in;
|
|
||||||
}
|
|
||||||
|
|
||||||
.accent-gradient {
|
|
||||||
background: radial-gradient(
|
|
||||||
circle at left,
|
|
||||||
rgb(255 255 255 / 80%),
|
|
||||||
rgb(255 255 255 / 75%),
|
|
||||||
rgb(255 255 255 / 0%)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
.accent-text-shadow {
|
|
||||||
text-shadow: black 2px 3px 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:where(html.light) {
|
|
||||||
body {
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.accent-background {
|
|
||||||
background-color: rgb(255 255 255 / 80%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.accent-overlay-background {
|
|
||||||
background-color: rgb(255 255 255 / 90%);
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
@apply no-underline transition-all;
|
|
||||||
|
|
||||||
color: royalblue;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: darkblue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.accent-text {
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.accent-gradient {
|
|
||||||
background: radial-gradient(
|
|
||||||
circle at left,
|
|
||||||
rgb(0 0 0 / 95%),
|
|
||||||
rgb(0 0 0 / 80%),
|
|
||||||
rgb(0 0 0 / 0%)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
.accent-text-shadow {
|
|
||||||
text-shadow: white 1px 2px 3px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.post {
|
|
||||||
scroll-snap-type: y mandatory;
|
|
||||||
scroll-snap-stop: normal;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: '';
|
|
||||||
scroll-snap-align: start;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-box {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
padding: 0.6942rem 0.6942rem 3rem;
|
|
||||||
|
|
||||||
border: 2px solid rgb(153 153 255 / 60%);
|
|
||||||
background-color: rgb(45 7 110 / 10%);
|
|
||||||
|
|
||||||
transition: 0.3s ease;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
border-color: rgb(153 153 255 / 100%);
|
|
||||||
background-color: rgb(45 7 110 / 30%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-pocket {
|
|
||||||
background-color: rgb(153 153 255 / 10%);
|
|
||||||
|
|
||||||
border-left: 1px solid rgb(153 153 255 / 60%);
|
|
||||||
border-top: 1px solid rgb(153 153 255 / 60%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&-thumb {
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
> img {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
max-height: 280px;
|
|
||||||
object-fit: cover;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-tags {
|
|
||||||
> span {
|
|
||||||
padding: 0.35em 0.65em;
|
|
||||||
font-size: 0.85em;
|
|
||||||
|
|
||||||
background-color: rgb(153 153 255 / 10%);
|
|
||||||
|
|
||||||
border: 1px solid rgb(153 153 255 / 60%);
|
|
||||||
border-radius: 1rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-preamble {
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: center;
|
|
||||||
background-size: cover;
|
|
||||||
background-attachment: fixed;
|
|
||||||
|
|
||||||
scroll-snap-align: end;
|
|
||||||
|
|
||||||
iconify-icon {
|
|
||||||
filter: drop-shadow(1px 2px 3px rgb(0 0 0 / 100%));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-content {
|
|
||||||
scroll-snap-align: start;
|
|
||||||
|
|
||||||
:is(p, li) {
|
|
||||||
a {
|
|
||||||
@apply text-inherit no-underline transition-all;
|
|
||||||
|
|
||||||
color: cornflowerblue;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: royalblue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
:where(p, li) {
|
||||||
code {
|
code {
|
||||||
|
&:hover {
|
||||||
|
background-color: rgb(138 71 245 / 20%);
|
||||||
|
}
|
||||||
|
|
||||||
padding: 0.25em;
|
padding: 0.25em;
|
||||||
|
|
||||||
border-radius: 0.5em;
|
border-radius: 0.5em;
|
||||||
|
@ -420,29 +179,11 @@ rt {
|
||||||
background-color: rgb(83 35 162 / 10%);
|
background-color: rgb(83 35 162 / 10%);
|
||||||
|
|
||||||
transition: 0.3s ease;
|
transition: 0.3s ease;
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: rgb(138 71 245 / 20%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:is(h1, h2, h3, h4, h5, h6) {
|
|
||||||
font-family: Alexandria, sans-serif;
|
|
||||||
font-weight: 700;
|
|
||||||
|
|
||||||
a {
|
|
||||||
@apply text-inherit no-underline transition-all;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: indianred;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
max-width: 100%;
|
@apply max-w-full max-h-[400px];
|
||||||
max-height: 400px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
blockquote {
|
blockquote {
|
||||||
|
@ -528,6 +269,246 @@ rt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Entry point (Vue mount).
|
||||||
|
#ender-app {
|
||||||
|
flex: 1 0 auto;
|
||||||
|
image-rendering: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper classes that don't exist in Bootstrap.
|
||||||
|
.overlay {
|
||||||
|
grid-area: 1 / 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pass-through {
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ruby {
|
||||||
|
ruby-position: under;
|
||||||
|
|
||||||
|
ruby {
|
||||||
|
ruby-position: over;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rt {
|
||||||
|
ruby-align: space-around;
|
||||||
|
}
|
||||||
|
|
||||||
|
.font-small {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query-overridable classes.
|
||||||
|
.dimensions {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer utilities {
|
||||||
|
.accent-background {
|
||||||
|
background-color: rgb(0 0 0 / 50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.accent-overlay-background {
|
||||||
|
background-color: rgb(0 0 0 / 90%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.accent-text {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accent-text-shadow {
|
||||||
|
text-shadow: black 2px 3px 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drop-shadow,
|
||||||
|
.accent-drop-shadow {
|
||||||
|
filter: drop-shadow(1px 2px 3px black);
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-dark {
|
||||||
|
@apply text-inherit no-underline transition-all;
|
||||||
|
|
||||||
|
color: cornflowerblue;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: royalblue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.accent-fade {
|
||||||
|
background: linear-gradient(
|
||||||
|
to top,
|
||||||
|
black,
|
||||||
|
rgb(0 0 0 / 50%) 75%,
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-mask {
|
||||||
|
mask-image: linear-gradient(to bottom, transparent, black 3%, black 97%, transparent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog {
|
||||||
|
display: grid;
|
||||||
|
|
||||||
|
min-width: 240px;
|
||||||
|
max-width: 640px;
|
||||||
|
|
||||||
|
background-color: rgb(25 20 40 / 95%);
|
||||||
|
box-shadow: rgb(81 75 89 / 50%) 7px 7px 2em;
|
||||||
|
border-radius: 16px !important;
|
||||||
|
|
||||||
|
> div.background {
|
||||||
|
background-image: url('~/assets/images/textures/aero.png');
|
||||||
|
background-attachment: scroll;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: cover;
|
||||||
|
background-blend-mode: lighten;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
opacity: 0.2;
|
||||||
|
|
||||||
|
box-shadow: azure 0 0 20rem;
|
||||||
|
filter: blur(5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
> div.content > img.icon-badge {
|
||||||
|
position: fixed;
|
||||||
|
margin-top: -20px;
|
||||||
|
margin-left: -20px;
|
||||||
|
transform: rotate(-25deg);
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.accent-gradient {
|
||||||
|
background: radial-gradient(
|
||||||
|
circle at left,
|
||||||
|
rgb(255 255 255 / 80%),
|
||||||
|
rgb(255 255 255 / 75%),
|
||||||
|
rgb(255 255 255 / 0%)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.post {
|
||||||
|
scroll-snap-type: y mandatory;
|
||||||
|
scroll-snap-stop: normal;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
scroll-snap-align: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-box {
|
||||||
|
border-color: rgb(153 153 255 / 60%);
|
||||||
|
background-color: rgb(45 7 110 / 10%);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: rgb(153 153 255 / 100%);
|
||||||
|
background-color: rgb(45 7 110 / 30%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-pocket {
|
||||||
|
background-color: rgb(153 153 255 / 10%);
|
||||||
|
border-left-color: rgb(153 153 255 / 60%);
|
||||||
|
border-top-color: rgb(153 153 255 / 60%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-tag {
|
||||||
|
background-color: rgb(153 153 255 / 10%);
|
||||||
|
border-color: rgb(153 153 255 / 60%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:where(html.light) {
|
||||||
|
body {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accent-background {
|
||||||
|
background-color: rgb(255 255 255 / 90%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.accent-overlay-background {
|
||||||
|
background-color: rgb(255 255 255 / 90%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.accent-drop-shadow {
|
||||||
|
filter: drop-shadow(1px 2px 3px white);
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
@apply no-underline transition-all;
|
||||||
|
|
||||||
|
color: royalblue;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: darkblue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.accent-text {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accent-gradient {
|
||||||
|
background: radial-gradient(
|
||||||
|
circle at left,
|
||||||
|
rgb(0 0 0 / 95%),
|
||||||
|
rgb(0 0 0 / 80%),
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.accent-text-shadow {
|
||||||
|
text-shadow: white 1px 2px 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accent-fade {
|
||||||
|
background: linear-gradient(
|
||||||
|
to top,
|
||||||
|
white,
|
||||||
|
rgb(255 255 255 / 50%) 75%,
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.post {
|
||||||
|
&-box {
|
||||||
|
border-color: rgb(123 123 255 / 1000%);
|
||||||
|
background-color: rgb(45 7 110 / 20%);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: rgb(123 123 255 / 80%);
|
||||||
|
background-color: rgb(45 7 110 / 10%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-pocket {
|
||||||
|
background-color: rgb(123 123 255 / 10%);
|
||||||
|
border-left-color: rgb(123 123 255 / 80%);
|
||||||
|
border-top-color: rgb(123 123 255 / 80%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-tag {
|
||||||
|
background-color: rgb(123 123 255 / 10%);
|
||||||
|
border-color: rgb(123 123 255 / 80%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Dynamic classes.
|
// Dynamic classes.
|
||||||
@screen lm {
|
@screen lm {
|
||||||
.dimensions {
|
.dimensions {
|
||||||
|
@ -542,13 +523,14 @@ rt {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ender-app {
|
#ender-app {
|
||||||
height: 100%;
|
height: 100dvh;
|
||||||
|
|
||||||
scrollbar-gutter: stable;
|
scrollbar-gutter: stable;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dimensions {
|
.dimensions {
|
||||||
width: 90%;
|
width: 90%;
|
||||||
|
|
||||||
min-height: fit-content;
|
min-height: fit-content;
|
||||||
max-height: 90%;
|
max-height: 90%;
|
||||||
}
|
}
|
||||||
|
@ -567,42 +549,6 @@ rt {
|
||||||
html {
|
html {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.post {
|
|
||||||
&-box {
|
|
||||||
padding-bottom: 0.6942rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-thumb {
|
|
||||||
min-width: 352px;
|
|
||||||
max-height: 198px;
|
|
||||||
|
|
||||||
> img {
|
|
||||||
max-width: 352px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-title {
|
|
||||||
display: -webkit-box;
|
|
||||||
|
|
||||||
-webkit-line-clamp: 2;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-description {
|
|
||||||
display: -webkit-box;
|
|
||||||
|
|
||||||
-webkit-line-clamp: 4;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@screen lg {
|
@screen lg {
|
||||||
|
|
|
@ -10,3 +10,23 @@
|
||||||
filter: blur(1em);
|
filter: blur(1em);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.transition {
|
||||||
|
&-ease {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-portal {
|
||||||
|
transition: all 0.6942s ease-in;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
&-twitter:hover {
|
||||||
|
transform: translateZ(0) scale(1.1) rotate(-10deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-back:hover {
|
||||||
|
transform: translateZ(0) scale(0.9);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,43 +0,0 @@
|
||||||
<script setup lang="ts">
|
|
||||||
import type { PropType } from 'vue'
|
|
||||||
|
|
||||||
type ModeOptions = 'in-out' | 'out-in' | 'default' | undefined
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
fallback: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
appear: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
mode: {
|
|
||||||
type: String as PropType<ModeOptions>,
|
|
||||||
default: 'out-in',
|
|
||||||
},
|
|
||||||
enter: {
|
|
||||||
type: String,
|
|
||||||
default: 'animate__fadeIn',
|
|
||||||
},
|
|
||||||
leave: {
|
|
||||||
type: String,
|
|
||||||
default: 'animate__fadeOut',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<ClientOnly>
|
|
||||||
<template #fallback>{{ props.fallback }}</template>
|
|
||||||
|
|
||||||
<Transition
|
|
||||||
:appear="props.appear"
|
|
||||||
:mode="props.mode"
|
|
||||||
:enter-active-class="`animate__animated ${props.enter}`"
|
|
||||||
:leave-active-class="`animate__animated ${props.leave}`"
|
|
||||||
>
|
|
||||||
<slot />
|
|
||||||
</Transition>
|
|
||||||
</ClientOnly>
|
|
||||||
</template>
|
|
|
@ -1,58 +0,0 @@
|
||||||
<script setup lang="ts">
|
|
||||||
import type { IconifyRenderMode } from 'iconify-icon'
|
|
||||||
import type { PropType } from 'vue'
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
name: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
color: {
|
|
||||||
type: String,
|
|
||||||
default: 'white',
|
|
||||||
},
|
|
||||||
mode: {
|
|
||||||
type: String as PropType<IconifyRenderMode>,
|
|
||||||
default: 'svg',
|
|
||||||
},
|
|
||||||
inline: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
width: {
|
|
||||||
type: String,
|
|
||||||
default: '1em',
|
|
||||||
},
|
|
||||||
height: {
|
|
||||||
type: String,
|
|
||||||
default: '1em',
|
|
||||||
},
|
|
||||||
flip: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
rotate: {
|
|
||||||
type: [String, Number],
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<iconify-icon
|
|
||||||
class="icon"
|
|
||||||
:icon="props.name"
|
|
||||||
:mode="props.mode"
|
|
||||||
:inline="props.inline"
|
|
||||||
:width="props.width"
|
|
||||||
:height="props.height"
|
|
||||||
:flip="props.flip"
|
|
||||||
:rotate="props.rotate"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.icon {
|
|
||||||
color: v-bind(color);
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -44,7 +44,7 @@ if (data.value) {
|
||||||
|
|
||||||
// Generate the article's Open Graph image.
|
// Generate the article's Open Graph image.
|
||||||
defineOgImageComponent(
|
defineOgImageComponent(
|
||||||
'OgImage',
|
'OgThumbnail',
|
||||||
{
|
{
|
||||||
title: data.value.title,
|
title: data.value.title,
|
||||||
description: data.value.description,
|
description: data.value.description,
|
||||||
|
@ -59,55 +59,55 @@ if (data.value) {
|
||||||
)
|
)
|
||||||
|
|
||||||
// Hydrate the rendered items.
|
// Hydrate the rendered items.
|
||||||
// onMounted(() => {
|
onMounted(() => {
|
||||||
// document.querySelectorAll('pre').forEach((pre) => {
|
document.querySelectorAll('pre').forEach((pre) => {
|
||||||
// const icon = document.createElement('iconify-icon')
|
const icon = document.createElement('iconify-icon')
|
||||||
//
|
|
||||||
// icon.setAttribute('icon', 'mdi:content-copy')
|
icon.setAttribute('icon', 'mdi:content-copy')
|
||||||
// icon.setAttribute('inline', 'true')
|
icon.setAttribute('inline', 'true')
|
||||||
//
|
|
||||||
// icon.classList.add('button')
|
icon.classList.add('button')
|
||||||
//
|
|
||||||
// pre.appendChild(icon)
|
pre.appendChild(icon)
|
||||||
// })
|
})
|
||||||
//
|
|
||||||
// document
|
document
|
||||||
// .querySelectorAll('code:not(pre *), pre > iconify-icon.button')
|
.querySelectorAll('code:not(pre *), pre > iconify-icon.button')
|
||||||
// .forEach((code) => {
|
.forEach((code) => {
|
||||||
// if (code instanceof HTMLElement) {
|
if (code instanceof HTMLElement) {
|
||||||
// code.onclick = () => {
|
code.onclick = () => {
|
||||||
// const area = document.createElement('textarea')
|
const area = document.createElement('textarea')
|
||||||
//
|
|
||||||
// area.textContent =
|
area.textContent =
|
||||||
// code.nodeName && code.nodeName.toLowerCase() === 'code'
|
code.nodeName && code.nodeName.toLowerCase() === 'code'
|
||||||
// ? code.textContent
|
? code.textContent
|
||||||
// : code.parentElement!.textContent
|
: code.parentElement!.textContent
|
||||||
//
|
|
||||||
// // It's necessary to create the textarea element every time you copy to get access to the select() method.
|
// It's necessary to create the textarea element every time you copy to get access to the select() method.
|
||||||
// area.setSelectionRange(0, 99999) // An iOS gotcha.
|
area.setSelectionRange(0, 99999) // An iOS gotcha.
|
||||||
// area.select()
|
area.select()
|
||||||
//
|
|
||||||
// // Copy the text inside the textarea.
|
// Copy the text inside the textarea.
|
||||||
// navigator.clipboard.writeText(area.value)
|
navigator.clipboard.writeText(area.value)
|
||||||
//
|
|
||||||
// // TODO: Alert the user text has been successfully copied.
|
// TODO: Alert the user text has been successfully copied.
|
||||||
//
|
|
||||||
// // Remove the textarea element.
|
// Remove the textarea element.
|
||||||
// area.remove()
|
area.remove()
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// })
|
})
|
||||||
// })
|
})
|
||||||
//
|
|
||||||
// onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
// document.querySelectorAll('code').forEach((code) => {
|
document.querySelectorAll('code').forEach((code) => {
|
||||||
// code.onclick = null
|
code.onclick = null
|
||||||
// })
|
})
|
||||||
//
|
|
||||||
// document.querySelectorAll('pre').forEach((pre) => {
|
document.querySelectorAll('pre').forEach((pre) => {
|
||||||
// pre.querySelector('.clipboard')?.remove()
|
pre.querySelector('.clipboard')?.remove()
|
||||||
// })
|
})
|
||||||
// })
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
useHead({
|
useHead({
|
||||||
|
@ -140,26 +140,48 @@ useHead({
|
||||||
</div>
|
</div>
|
||||||
<article
|
<article
|
||||||
v-else-if="status === 'success' && data"
|
v-else-if="status === 'success' && data"
|
||||||
class="flex-grow post fade-mask-sm flex flex-col gap-4 overflow-x-hidden overflow-y-auto sm:py-4 sm:pe-4"
|
class="flex-grow post snap-normal fade-mask-sm flex flex-col gap-4 overflow-x-hidden overflow-y-auto sm:py-4 sm:pe-4"
|
||||||
>
|
>
|
||||||
|
<div class="grid-thumbnail grid max-w-[768px] snap-end">
|
||||||
|
<img
|
||||||
|
draggable="false"
|
||||||
|
:src="thumbnail!"
|
||||||
|
alt="Thumbnail"
|
||||||
|
class="grid-thumbnail-image object-cover object-center rounded-xl aspect-[16/9] select-none"
|
||||||
|
/>
|
||||||
|
<NuxtLink to="/blog" class="grid-thumbnail-start button-back p-2">
|
||||||
|
<iconify-icon
|
||||||
|
icon="icon-park-solid:back"
|
||||||
|
width="2em"
|
||||||
|
height="2em"
|
||||||
|
class="drop-shadow text-pink-200"
|
||||||
|
/>
|
||||||
|
</NuxtLink>
|
||||||
|
<NuxtLink
|
||||||
|
class="grid-thumbnail-end button-twitter p-2"
|
||||||
|
:href="`https://twitter.com/share?url=${config.url}/blog/${slug}&text=${data.title}&hashtags=${data.tags.slice(0, 3).join(',').replace(/ /g, '')}`"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<iconify-icon
|
||||||
|
icon="logos:twitter"
|
||||||
|
width="2em"
|
||||||
|
height="2em"
|
||||||
|
class="drop-shadow"
|
||||||
|
/>
|
||||||
|
</NuxtLink>
|
||||||
<div
|
<div
|
||||||
class="relative flex flex-col justify-end items-start w-full min-h-[400px] rounded-xl accent-text-shadow post-preamble"
|
class="grid-thumbnail-title accent-fade w-full rounded-b-lg p-2 mt-16"
|
||||||
:style="{ backgroundImage: 'url(' + thumbnail + ')' }"
|
|
||||||
>
|
>
|
||||||
<div class="p-2">
|
<h3 class="mb-1">{{ data.title }}</h3>
|
||||||
<h3>{{ data.title }}</h3>
|
|
||||||
<div class="flex flex-row flex-wrap gap-x-2 gap-y-0">
|
<div class="flex flex-row flex-wrap gap-x-2 gap-y-0">
|
||||||
<div class="flex flex-row items-center gap-2">
|
<small class="flex flex-row items-center gap-1 whitespace-nowrap">
|
||||||
<iconify-icon icon="mdi:calendar" />
|
<iconify-icon icon="mdi:calendar" inline />
|
||||||
<small class="whitespace-nowrap">
|
|
||||||
<strong>
|
<strong>
|
||||||
{{ formatDate(data.created, 'LLLL do, y – HH:mm') }}
|
{{ formatDate(data.created, 'HH:mm • LLLL do, y') }}
|
||||||
</strong>
|
</strong>
|
||||||
</small>
|
</small>
|
||||||
</div>
|
<small class="flex flex-row items-center gap-1 whitespace-nowrap">
|
||||||
<div class="flex flex-row items-center gap-2">
|
<iconify-icon icon="mdi:clock-outline" inline />
|
||||||
<iconify-icon icon="mdi:clock-outline" />
|
|
||||||
<small class="whitespace-nowrap">
|
|
||||||
<strong>
|
<strong>
|
||||||
{{ data!.readingTime.text.split(' ')[0] + ' minutes to read' }}
|
{{ data!.readingTime.text.split(' ')[0] + ' minutes to read' }}
|
||||||
</strong>
|
</strong>
|
||||||
|
@ -167,29 +189,44 @@ useHead({
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<NuxtLink
|
<section class="page snap-start">
|
||||||
to="/blog"
|
|
||||||
class="absolute top-0 left-0 p-2 text-inherit no-underline"
|
|
||||||
>
|
|
||||||
<iconify-icon
|
|
||||||
icon="icon-park-solid:back"
|
|
||||||
width="2em"
|
|
||||||
height="2em"
|
|
||||||
style="color: lavender"
|
|
||||||
/>
|
|
||||||
</NuxtLink>
|
|
||||||
<NuxtLink
|
|
||||||
:href="`https://twitter.com/share?url=${config.url}/blog/${slug}&text=${data.title}&hashtags=${data.tags.slice(0, 3).join(',').replace(/ /g, '')}`"
|
|
||||||
target="_blank"
|
|
||||||
class="absolute top-0 right-0 p-2"
|
|
||||||
>
|
|
||||||
<iconify-icon icon="logos:twitter" width="2em" height="2em" />
|
|
||||||
</NuxtLink>
|
|
||||||
</div>
|
|
||||||
<div class="post-content">
|
|
||||||
<hr class="accent-text accent-gradient border-0 h-px" />
|
|
||||||
<ContentRenderer :value="data" />
|
<ContentRenderer :value="data" />
|
||||||
</div>
|
</section>
|
||||||
</article>
|
</article>
|
||||||
<NotFound v-else />
|
<NotFound v-else />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.grid-thumbnail {
|
||||||
|
&-image {
|
||||||
|
grid-column: 1;
|
||||||
|
grid-row: 1;
|
||||||
|
|
||||||
|
place-self: start center;
|
||||||
|
|
||||||
|
max-width: clamp(1px, 100%, 768px);
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-title {
|
||||||
|
grid-column: 1;
|
||||||
|
grid-row: 1;
|
||||||
|
|
||||||
|
place-self: end center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-start {
|
||||||
|
grid-column: 1;
|
||||||
|
grid-row: 1;
|
||||||
|
|
||||||
|
place-self: start start;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-end {
|
||||||
|
grid-column: 1;
|
||||||
|
grid-row: 1;
|
||||||
|
|
||||||
|
place-self: start end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -64,9 +64,8 @@ useHead({
|
||||||
class="text-inherit hover:text-inherit no-underline"
|
class="text-inherit hover:text-inherit no-underline"
|
||||||
>
|
>
|
||||||
<article
|
<article
|
||||||
class="post-box flex flex-col md:flex-row gap-4 rounded-xl h-full"
|
class="post-box relative flex flex-col md:flex-row gap-4 p-2 border-2 rounded-xl transition-ease"
|
||||||
>
|
>
|
||||||
<div class="post-thumb">
|
|
||||||
<img
|
<img
|
||||||
draggable="false"
|
draggable="false"
|
||||||
:src="
|
:src="
|
||||||
|
@ -74,33 +73,39 @@ useHead({
|
||||||
`/images/blog/thumbnails/${post._path!.split('/').at(-1)}.png`
|
`/images/blog/thumbnails/${post._path!.split('/').at(-1)}.png`
|
||||||
"
|
"
|
||||||
:alt="post.title"
|
:alt="post.title"
|
||||||
class="rounded-xl"
|
class="md:flex-grow-[2] md:basis-0 xl:flex-grow-1 object-cover object-center aspect-[16/9] w-fit md:w-0 xl:w-fit h-full max-h-[300px] rounded-xl"
|
||||||
/>
|
/>
|
||||||
</div>
|
<div class="md:flex-grow-[3] md:basis-0 xl:flex-grow-1 w-full">
|
||||||
<div class="w-full">
|
<h3 class="post-title md:line-clamp-2 md:overflow-ellipsis">
|
||||||
<h3 class="post-title">{{ post.title }}</h3>
|
{{ post.title }}
|
||||||
<p class="post-description mb-0">{{ post.description }}</p>
|
</h3>
|
||||||
|
<p
|
||||||
|
class="post-description mb-0 md:line-clamp-4 md:overflow-ellipsis"
|
||||||
|
>
|
||||||
|
{{ post.description }}
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="post-tags flex flex-row flex-wrap gap-2 py-2">
|
<div class="flex flex-row flex-wrap gap-2 py-2">
|
||||||
<span
|
<small
|
||||||
v-for="(tag, index) in post.tags.slice(0, 3)"
|
v-for="(tag, index) in post.tags.slice(0, 3)"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="whitespace-nowrap"
|
class="post-tag px-2 py-1 rounded-xl border whitespace-nowrap"
|
||||||
>
|
>
|
||||||
{{ tag }}
|
{{ tag }}
|
||||||
</span>
|
</small>
|
||||||
<span v-if="post.tags.length > 3" class="whitespace-nowrap">
|
<small
|
||||||
|
v-if="post.tags.length > 3"
|
||||||
|
class="post-tag px-2 py-1 rounded-xl border whitespace-nowrap"
|
||||||
|
>
|
||||||
{{ post.tags.length - 3 }} more
|
{{ post.tags.length - 3 }} more
|
||||||
</span>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="accent-text accent-gradient border-0 h-px" />
|
|
||||||
|
|
||||||
<div class="post-details py-2">
|
<div class="post-details py-2">
|
||||||
<div class="flex flex-row items-center gap-2">
|
<div class="flex flex-row items-center gap-2">
|
||||||
<iconify-icon icon="mdi:calendar" />
|
<iconify-icon icon="mdi:calendar" />
|
||||||
<small class="whitespace-nowrap">
|
<small class="whitespace-nowrap">
|
||||||
{{ formatDate(post.created, 'LLLL do, y – HH:mm') }}
|
{{ formatDate(post.created, 'HH:mm • LLLL do, y') }}
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
@ -109,14 +114,14 @@ useHead({
|
||||||
>
|
>
|
||||||
<iconify-icon icon="mdi:pencil" />
|
<iconify-icon icon="mdi:pencil" />
|
||||||
<small class="whitespace-nowrap">
|
<small class="whitespace-nowrap">
|
||||||
{{ formatDate(post.updated, 'LLLL do, y – HH:mm') }}
|
{{ formatDate(post.updated, 'HH:mm • LLLL do, y') }}
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="post-pocket absolute bottom-0 right-0 uppercase rounded-tl-xl flex flex-row items-center gap-2 p-2"
|
class="post-pocket border-l border-t absolute bottom-0 right-0 uppercase rounded-tl-xl flex flex-row items-center gap-2 p-2"
|
||||||
>
|
>
|
||||||
<iconify-icon icon="mdi:clock-outline" />
|
<iconify-icon icon="mdi:clock-outline" />
|
||||||
<small class="whitespace-nowrap font-mono font-small">
|
<small class="whitespace-nowrap font-mono font-small">
|
||||||
|
|
Loading…
Reference in New Issue