diff --git a/components/Book/Sidenote.tsx b/components/Book/Sidenote.tsx index 12c810b..301a16f 100644 --- a/components/Book/Sidenote.tsx +++ b/components/Book/Sidenote.tsx @@ -1,5 +1,6 @@ "use client"; +import "./expanding-side-img.scss" import React, { ReactNode, createContext, useRef, useCallback, useMemo } from "react"; import Image from "@/components/Image"; @@ -134,23 +135,23 @@ export const ExpandingSideImg = ({src, alt, retina, caption, children}: { className={retina ? " retina" : ""} />
- {caption &&
{caption}
} + {caption &&

{caption}

} {children &&
{children}
}
- {alt - {(caption || children) && -
- {caption &&
{caption}
} - {children &&
{children}
} -
- } + {alt + {(caption || children) && +
+ {caption &&
{caption}
} + {children &&
{children}
} +
+ }
diff --git a/components/Book/expanding-side-img.scss b/components/Book/expanding-side-img.scss new file mode 100644 index 0000000..de3032b --- /dev/null +++ b/components/Book/expanding-side-img.scss @@ -0,0 +1,240 @@ +@use "../../styles/variables" as *; + +@keyframes show-icon { + 0% { opacity: 0; } + 25% { opacity: 1; } + 50% { opacity: 0; } + 75% { opacity: 1; } + 100% { opacity: 0.7; } +} + +div.expanding-side-img-container { + div.expanding-side-img { + margin: 0; + position: absolute; + width: $aside-width; + transform: translateX(calc(-100% - $gap)); + + .caption { + padding-top: 0px; + } + + .caption p { + font-weight: 400; + } + } + + img { + margin: 0; + border-radius: 8px; + } + + div.overlay { + visibility: hidden; + + position: fixed; + top: 50%; + left: 50%; + width: 10vw; + height: 10vh; + transition: width 0.2s, height 0.2s; + transform: translate(-50%, -50%); + + text-align: center; + z-index: 100; + + display: flex; + justify-content: center; + align-items: center; + + .figure { + display: inline-block; + width: auto; + position: relative; + margin: auto; + margin-top: 0; + margin-bottom: 0; + overflow: hidden; + + &:has(.children) img { + max-height: 98vh; + } + + img { + width: auto; + height: auto; + max-width: 98vw; + max-height: 85vh; + } + + &:hover .caption-overlay:has(.children)::after { + animation: show-icon 2s ease both; + } + + .caption-overlay { + .children { + padding: 0 16px; + width: 100%; + text-align: left; + } + + .caption p { + padding: 0 16px 0 16px; + font-weight: 800; + } + + &:has(.children) { + position: absolute; + bottom: 0; + max-height: 32px; + overflow: hidden; + + background-color: #fff9; + text-overflow: unset; + transition: background-color 0.5s ease, max-height 0.5s ease; + + &::after { + content: ""; + position: absolute; + top: auto; + bottom: 0; + left: 0; + width: 32px; + height: 32px; + opacity: 0; + + background-color: rgb(80 80 80 / 70%); + background-image: url("/icons/eye.svg"); + background-repeat: no-repeat; + background-position: center; + background-size: 18px; + + border-radius: 4px; + } + + &:hover { + background-color: #fffd; + padding: 16px 16px 0 16px; + max-height: 100vh; + + &::after { + opacity: 0 !important; + } + } + } + } + } + } +} + +@media ( min-width: 681px ) { + div.expanding-side-img-container { + &:has(:hover) .overlay { + width: 100vw; + height: 100vh; + background-color: #dddd; + visibility: visible; + pointer-events: none; + + .caption-overlay:not(:has(.children)) { + visibility: visible; + position: fixed; + bottom: 0; + left: 0; + width: 100vw; + padding: 12px; + background-color: #333a; + color: white; + display: flex; + align-content: center; + justify-content: center; + } + } + + &:has(:hover) .figure { + opacity: 1; + pointer-events: auto; + } + } + .expanding-side-img img, .overlay .figure img { + border: 1px solid #bbb; + } + + div.expanding-side-img { + transform-origin: top left; + max-width: $aside-width; + padding: 0; + object-fit: contain; + + img { + border-radius: 5px; + } + + &::after { + content: ""; + position: absolute; + top: 0; + right: 0; + width: 32px; + height: 32px; + + background-color: rgb(80 80 80 / 70%); + background-image: url("/icons/magnifying-glass.svg"); + background-repeat: no-repeat; + background-position: center; + background-size: 18px; + + border-radius: 4px; + } + + .caption-cont { + .caption { + padding-top: 12px; + + } + + .children { + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + } + } + } +} + + +@media print, ( max-width: 680px ) { + div.expanding-side-img-container { + max-width: 100vw; + height: auto; + overflow: clip; + + .overlay { + display: none !important; + } + + .expanding-side-img { + img { + width: 100% + } + &:has(.caption) { + text-align: center; + + &::after { + display: none; + } + + img { + margin-bottom: 0; + } + + .caption, .children { + font-weight: 400 !important; + padding: 8px 0 16px 0; + } + } + } + } +} diff --git a/components/MdxContent.tsx b/components/MdxContent.tsx index c5b94c0..508c766 100644 --- a/components/MdxContent.tsx +++ b/components/MdxContent.tsx @@ -33,6 +33,23 @@ export const MdxContent = ({content, chapterId, bookId, t, env, allAnswers}: { env?: Record; allAnswers?: AnswersInBook; }) => { + React.useEffect(() => { + const resize = (img: HTMLImageElement) => { + // Set only maxHeight to avoid overriding maxWidth set to images in side columns + img.style.maxHeight = `${img.naturalHeight / 2}px`; + }; + + const images = document.querySelectorAll("img.retina"); + images.forEach(img => { + if (img.complete) { + resize(img); + } + else { + img.addEventListener("load", () => resize(img), {once: true}); + } + }); + }, []); + if (!content) { return; } diff --git a/styles/globals.scss b/styles/globals.scss index b379e40..0b0fbbd 100644 --- a/styles/globals.scss +++ b/styles/globals.scss @@ -1,4 +1,5 @@ @use "./colors" as *; +@use "./variables" as *; @use "quiz/quiz" as quiz; /*@use "admin/admin" as admin; */ @use "content-index/content-index" as *; @@ -80,7 +81,7 @@ $gap: var(--gap); } @media ( min-width: 681px ) { - [data-float-aside] + p, [data-float-aside] + div, div.float-aside, div.expanding-side-img { + [data-float-aside] + p, [data-float-aside] + div, div.float-aside { margin: 0 !important; position: absolute; width: $aside-width; @@ -109,187 +110,15 @@ $gap: var(--gap); ) !important; margin-right: auto; } - - div.expanding-side-img { - transform-origin: top left; - max-width: $aside-width; - padding: 0; - object-fit: contain; - - img { - border-radius: 5px; - } - - img.retina { - zoom: 0.5; - } - - &::after { - content: ""; - position: absolute; - top: 8px; - right: 0; - width: 32px; - height: 32px; - - background-color: rgb(80 80 80 / 70%); - background-image: url("/icons/magnifying-glass.svg"); - background-repeat: no-repeat; - background-position: center; - background-size: 18px; - - border-radius: 4px; - } - - .caption-cont .children { - display: -webkit-box; - -webkit-line-clamp: 2; // number of lines - -webkit-box-orient: vertical; - overflow: hidden; - text-overflow: ellipsis; - } - } -} - -div.expanding-side-img-container div.overlay { - visibility: hidden; - - position: fixed; - top: 50% !important; - left: 50% !important; - width: 10vw; - height: 10vh; - transition: width 0.2s, height 0.2s; - transform: translate(-50%, -50%); - - text-align: center; - z-index: 100; - - inset: 0; - display: flex; - justify-content: center; - align-items: center; - - .figure { - display: inline-block; - width: auto; - position: relative; - margin: auto; - margin-top: 0 !important; - margin-bottom: 0 !important; - overflow: hidden; - } - - img { - width: auto; - height: auto; - display: block; - margin: 0 !important; - border: 1px solid gray; - } - - .caption-cont:has(.no-children) { - visibility: hidden; - } - - .children { - padding: 0 16px; - width: 100%; - } - - .caption.with-children { - padding: 0px 16px 0 16px; - font-weight: 800 !important; - } - - .figure .caption-cont::after { - content: ""; - position: absolute; - top: auto; - bottom: 0px; - left: 0; - width: 32px; - height: 32px; - - background-color: rgb(80 80 80 / 70%); - background-image: url("/icons/eye.svg"); - background-repeat: no-repeat; - background-position: center; - background-size: 18px; - - border-radius: 4px; - } - - .figure .caption-cont:has(:hover)::after { - opacity: 0 - } - - .caption-cont:has(.children) { - background-color: #fff4; - } - - .caption-cont { - position: absolute; - bottom: 0; - background-color: white; - overflow: visible; - text-overflow: unset; - height: 32px; - } - - .caption-cont:hover { - transition: opacity 0.2s linear; - background-color: #fffd; - padding: 16px 16px 0 16px; - height: auto; - } - - .children { - text-align: left; - } -} - -div.expanding-side-img-container:has(:hover) .overlay, div.expanding-side-img-container.overlay:has(.figure:hover) { - width: 100vw; - height: 100vh; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - background-color: #dddd; - visibility: visible; - pointer-events: none; - - .figure img { - max-width: 90vw; - max-height: 90vh; - } -} - -div.expanding-side-img-container:has(:hover) .figure, div.expanding-side-img-container.overlay .figure:hover { - opacity: 1; - pointer-events: visible; } @media print, ( max-width: 680px ) { - img, div.expanding-side-img { + img { max-width: $prose-width; height: auto; overflow: clip; } - img:has(+ .caption) { - margin-bottom: 12px; - } - - .expanding-side-img:has(.caption) { - margin-bottom: 42px; - } - - .caption.no-children, .caption.with-children, .children { - font-weight: 400 !important; - font-style: italic; - } - .expressive-code { max-width: $prose-width !important; width: $prose-width !important; @@ -324,7 +153,7 @@ div.expanding-side-img-container:has(:hover) .figure, div.expanding-side-img-con margin-top: 0! important; } - .expanding-side-img img, .float-aside img { + .float-aside img { width: 100% !important; } @@ -372,7 +201,7 @@ div.expanding-side-img-container:has(:hover) .figure, div.expanding-side-img-con :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *))::before, :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { - content: ""; + content: ""; } strong { diff --git a/styles/variables.scss b/styles/variables.scss new file mode 100644 index 0000000..43e4191 --- /dev/null +++ b/styles/variables.scss @@ -0,0 +1,19 @@ + +$img-margin: 8px; +$max-size: 140; + +:root { + --aside-width: 260px; + --prose-width: 940px; + --gap: 32px; + + @media (max-width: 680px) { + --aside-width: 0; + --prose-width: 100vw; // Using 100% allows some elements to expand + --gap: 0; + } +} + +$aside-width: var(--aside-width); +$prose-width: var(--prose-width); +$gap: var(--gap);