p-slides
Version:
Presentations made simple with Web Components
150 lines (146 loc) • 3.62 kB
CSS
:host {
--slide-width: min(100cqw, 100cqh * var(--slide-aspect-ratio));
--slide-height: min(100cqw / var(--slide-aspect-ratio), 100cqh);
--computed-font-size: calc(var(--slide-width) * var(--slide-font-size, 5) / 100);
--grid-gap: 0.6cqw;
position: fixed;
inset: 0;
overflow: clip;
display: grid;
grid-template: 100% / 100%;
justify-items: center;
align-items: center;
color: #222;
counter-reset: slide;
font-size: var(--computed-font-size);
@media (prefers-reduced-motion: no-preference) {
--sliding-duration: 0.5s;
}
}
aside {
display: none;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: calc(100% * var(--speaker-next-scale));
color: white;
flex-direction: column;
}
header {
font-size: 87.5%;
text-align: center;
background: #111;
margin-bottom: 0.25em;
flex: 0 0 auto;
}
ul {
background: #111;
margin: 0;
padding: 0.5em 0.5em 0.5em 1.5em;
flex: 1 1 auto;
overflow: auto;
font-size: 50%;
}
li {
transition: opacity var(--fragment-duration);
}
li:only-child {
list-style-type: none;
margin-left: -1em;
}
li[hidden] {
display: revert;
opacity: 0.5;
}
span::after {
font-size: 70%;
content: '/' attr(data-total);
}
button {
background: none;
border: none;
padding: 0;
font-family: inherit;
font-size: 0.75em;
color: inherit;
width: 1em;
height: 1em;
box-sizing: border-box;
position: relative;
}
button:first-of-type {
border-style: solid;
border-color: transparent currentColor;
border-width: 0.5em 0 0.5em 1em;
vertical-align: 0.5em;
}
time[aria-busy='true'] + button:first-of-type {
border-width: 0 0.33em;
vertical-align: 0;
}
button:last-of-type::before,
button:last-of-type::after {
content: '';
width: 0.25em;
height: 1em;
background: currentColor;
position: absolute;
top: 0;
left: 0.375em;
transform: rotate(45deg);
}
button:last-of-type::after {
transform: rotate(-45deg);
}
:host([mode='speaker']) {
background: black;
}
/* :not([aria-current='page'] ~ *) doesn't work inside ::slotted(), but we have a workaround */
:host([mode='speaker']) ::slotted(p-slide:not([aria-current='page']):not(:nth-child(1 of [aria-current='page'] ~ *))) {
position: absolute ;
visibility: hidden ;
}
:host([mode='speaker']) ::slotted(p-slide) {
animation: none ;
overflow: hidden;
}
:host([mode='speaker']) ::slotted(p-slide[aria-current='page']) {
transform: scale(calc(1 - var(--speaker-next-scale)));
position: relative;
top: calc(var(--speaker-next-scale) * -50%);
left: calc(var(--speaker-next-scale) * 50% - 50%);
opacity: calc(1 - var(--speaker-next-scale) / 2);
}
:host([mode='speaker']) ::slotted(p-slide:nth-child(1 of [aria-current='page'] ~ *)) {
transform: scale(calc(var(--speaker-next-scale)));
position: relative;
top: calc(50% - var(--speaker-next-scale) * 50%);
left: calc(var(--speaker-next-scale) * 50% - 50%);
}
:host([mode='speaker']) aside {
display: flex;
}
:host([mode='grid']) {
grid-template: auto / repeat(var(--grid-columns), minmax(0, 1fr));
padding: var(--grid-gap);
gap: var(--grid-gap);
height: fit-content;
overflow: auto;
max-height: 100cqh;
scrollbar-width: none;
--slide-width: calc((100cqw - (var(--grid-columns) + 1) * var(--grid-gap)) / var(--grid-columns));
--slide-height: calc(var(--slide-width) / var(--slide-aspect-ratio));
}
:host([mode='grid']) ::slotted(p-slide) {
animation: none ;
width: 100% ;
height: auto ;
aspect-ratio: var(--slide-aspect-ratio) ;
grid-area: auto ;
min-height: 0;
pointer-events: auto;
}
:host([mode='grid']) ::slotted(p-slide:hover) {
--is-highlighted: 1;
}