applied the cool new carousel css feature!
This commit is contained in:
parent
6a0c1cb377
commit
3142ac6185
8 changed files with 233 additions and 75 deletions
|
@ -9,6 +9,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.list {
|
.list {
|
||||||
|
list-style-type: none;
|
||||||
|
|
||||||
|
container-type: inline-size;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-auto-flow: column;
|
grid-auto-flow: column;
|
||||||
|
|
||||||
|
@ -18,14 +21,53 @@
|
||||||
margin: -10em -4em 0em;
|
margin: -10em -4em 0em;
|
||||||
|
|
||||||
overflow: visible auto;
|
overflow: visible auto;
|
||||||
scroll-snap-type: inline proximity;
|
scroll-snap-type: inline mandatory;
|
||||||
|
overscroll-behavior-inline: contain;
|
||||||
|
|
||||||
@media (hover: none) {
|
@media (prefers-reduced-motion: no-preference) {
|
||||||
padding: 5em;
|
scroll-behavior: smooth;
|
||||||
margin: 0;
|
}
|
||||||
|
|
||||||
|
/* the before and afters have unsnappable elements that create bouncy edges to the scroll */
|
||||||
|
&::before,
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
order: 0;
|
||||||
|
inline-size: 15cqi;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
order: 11;
|
||||||
|
inline-size: 50cqi;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > li {
|
||||||
|
scroll-snap-align: start;
|
||||||
|
container-type: scroll-state;
|
||||||
|
padding: 0;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
order: calc(var(--sibling-count) - var(--sibling-index));
|
||||||
|
z-index: var(--sibling-index);
|
||||||
|
|
||||||
& > * {
|
& > * {
|
||||||
scroll-snap-align: start;
|
@supports (animation-timeline: view()) {
|
||||||
|
@media (prefers-reduced-motion: no-preference) {
|
||||||
|
animation: slide-in linear both;
|
||||||
|
animation-timeline: view(inline);
|
||||||
|
animation-range: cover -100cqi contain 15cqi;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes slide-in {
|
||||||
|
from {
|
||||||
|
transform: translateX(-100cqi) scale(0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,13 +10,15 @@ interface ListProps<T> {
|
||||||
|
|
||||||
export function List<T>(props: ListProps<T>) {
|
export function List<T>(props: ListProps<T>) {
|
||||||
return (
|
return (
|
||||||
<section class={`${css.container} ${props.class ?? ''}`}>
|
<section class={`${css.container} ${props.class ?? ""}`}>
|
||||||
<b role="heading" class={css.heading}>
|
<b role="heading" class={css.heading}>
|
||||||
{props.label}
|
{props.label}
|
||||||
</b>
|
</b>
|
||||||
|
|
||||||
<ul class={css.list}>
|
<ul class={css.list}>
|
||||||
<Index each={props.items}>{(item) => props.children(item)}</Index>
|
<Index each={props.items}>
|
||||||
|
{(item) => <li>{props.children(item)}</li>}
|
||||||
|
</Index>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|
|
@ -13,8 +13,7 @@ const client = createClient<paths>({
|
||||||
|
|
||||||
export const listUsers = query(async () => {
|
export const listUsers = query(async () => {
|
||||||
const { data, error } = await client.GET("/Users", {
|
const { data, error } = await client.GET("/Users", {
|
||||||
params: {
|
params: {},
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return data ?? [];
|
return data ?? [];
|
||||||
|
@ -62,7 +61,7 @@ export const getContinueWatching = query(
|
||||||
const items = (data?.Items ?? []).map(({ Id, Name }) => ({
|
const items = (data?.Items ?? []).map(({ Id, Name }) => ({
|
||||||
id: Id,
|
id: Id,
|
||||||
title: Name,
|
title: Name,
|
||||||
thumbnail: `${baseUrl}Items/${Id}/Images/Primary`,
|
thumbnail: `${baseUrl}/Items/${Id}/Images/Primary`,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
import type { Category, Entry } from "./types";
|
import type { Category, Entry } from "./types";
|
||||||
import { query } from "@solidjs/router";
|
import { query } from "@solidjs/router";
|
||||||
import { entries } from "./data";
|
import { entries } from "./data";
|
||||||
|
import { getContinueWatching } from "./apis/jellyfin";
|
||||||
|
|
||||||
export const listCategories = query(async (): Promise<Category[]> => {
|
export const listCategories = query(async (): Promise<Category[]> => {
|
||||||
"use server";
|
"use server";
|
||||||
|
|
||||||
|
const jellyfinUserId = "a9c51af84bf54578a99ab4dd0ebf0763";
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
{ label: "Continue", entries: await getContinueWatching(jellyfinUserId) },
|
||||||
{
|
{
|
||||||
label: "Popular",
|
label: "Popular",
|
||||||
entries: [
|
entries: [
|
||||||
|
|
|
@ -26,14 +26,17 @@
|
||||||
radial-gradient(circle at 25% 30% #7772 #7774 1em transparent 1em),
|
radial-gradient(circle at 25% 30% #7772 #7774 1em transparent 1em),
|
||||||
/* Dot */
|
/* Dot */
|
||||||
radial-gradient(circle at 85% 15% #7772 #7774 1em transparent 1em),
|
radial-gradient(circle at 85% 15% #7772 #7774 1em transparent 1em),
|
||||||
/* Bottom fade */
|
/* Bottom fade */ linear-gradient(165deg transparent 60% #555 60% #333),
|
||||||
linear-gradient(165deg transparent 60% #555 60% #333),
|
|
||||||
/* wave dark part */
|
/* wave dark part */
|
||||||
radial-gradient(ellipse 5em 2.25em at 0.5em calc(50% - 1em) #333 100% transparent 100%),
|
radial-gradient(
|
||||||
|
ellipse 5em 2.25em at 0.5em calc(50% - 1em) #333 100% transparent 100%
|
||||||
|
),
|
||||||
/* wave light part */
|
/* wave light part */
|
||||||
radial-gradient(ellipse 5em 2.25em at calc(100% - 0.5em) calc(50% + 1em) #555 100% transparent 100%),
|
radial-gradient(
|
||||||
/* Base */
|
ellipse 5em 2.25em at calc(100% - 0.5em) calc(50% + 1em) #555 100%
|
||||||
linear-gradient(to bottom #333 50% #555 50%);
|
transparent 100%
|
||||||
|
),
|
||||||
|
/* Base */ linear-gradient(to bottom #333 50% #555 50%);
|
||||||
|
|
||||||
transform-origin: 50% 0;
|
transform-origin: 50% 0;
|
||||||
transform: scale(1.1) translateY(calc(-4 * var(--padding)));
|
transform: scale(1.1) translateY(calc(-4 * var(--padding)));
|
||||||
|
@ -41,7 +44,7 @@
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > main {
|
& > figcaption {
|
||||||
--offset: calc(1.5 * var(--padding));
|
--offset: calc(1.5 * var(--padding));
|
||||||
grid-area: 1/ 1;
|
grid-area: 1/ 1;
|
||||||
display: grid;
|
display: grid;
|
||||||
|
@ -98,11 +101,10 @@
|
||||||
will-change: transform;
|
will-change: transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > main {
|
& > figcaption {
|
||||||
clip-path: inset(40%);
|
clip-path: inset(40%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
@media (prefers-reduced-motion: no-preference) {
|
||||||
& {
|
& {
|
||||||
transition: transform var(--duration-moderate-1) linear;
|
transition: transform var(--duration-moderate-1) linear;
|
||||||
|
@ -112,7 +114,7 @@
|
||||||
transition: transform var(--duration-moderate-1) ease-in-out;
|
transition: transform var(--duration-moderate-1) ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > main {
|
& > figcaption {
|
||||||
transition: clip-path var(--duration-moderate-1) ease-in-out;
|
transition: clip-path var(--duration-moderate-1) ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,14 +7,14 @@ export const ListItem: Component<{ entry: Entry }> = (props) => {
|
||||||
const slug = createMemo(() => createSlug(props.entry));
|
const slug = createMemo(() => createSlug(props.entry));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class={css.listItem}>
|
<figure class={css.listItem}>
|
||||||
<img src={props.entry.thumbnail} />
|
<img src={props.entry.thumbnail} alt={props.entry.title} />
|
||||||
|
|
||||||
<main>
|
<figcaption>
|
||||||
<strong>{props.entry.title}</strong>
|
<strong>{props.entry.title}</strong>
|
||||||
|
|
||||||
<a href={`/watch/${slug()}`}>Watch now</a>
|
<a href={`/watch/${slug()}`}>Watch now</a>
|
||||||
</main>
|
</figcaption>
|
||||||
</div>
|
</figure>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,39 +1,121 @@
|
||||||
.list {
|
.carousel {
|
||||||
|
display: block grid;
|
||||||
|
grid: auto 1fr / 100%;
|
||||||
|
|
||||||
|
& > header {
|
||||||
anchor-name: --carousel;
|
anchor-name: --carousel;
|
||||||
overflow: auto;
|
padding-inline: 3rem;
|
||||||
scroll-snap-type: inline mandatory;
|
font-size: 1.75rem;
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > ul {
|
||||||
|
list-style-type: none;
|
||||||
|
|
||||||
|
container-type: size;
|
||||||
|
inline-size: 100%;
|
||||||
|
block-size: min(60svh, 720px);
|
||||||
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-auto-flow: column;
|
grid-auto-flow: column;
|
||||||
|
|
||||||
inline-size: 80%;
|
overflow: visible auto;
|
||||||
|
scroll-snap-type: inline mandatory;
|
||||||
|
overscroll-behavior-inline: contain;
|
||||||
|
|
||||||
justify-self: center;
|
justify-self: center;
|
||||||
|
|
||||||
& > li {
|
gap: 1em;
|
||||||
inline-size: 30vw;
|
padding-inline: 2em;
|
||||||
list-style: none;
|
scroll-padding-inline: 2em;
|
||||||
scroll-snap-align: start;
|
padding-block: 2em 4em;
|
||||||
|
margin-block-end: 5em;
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: no-preference) {
|
||||||
|
scroll-behavior: smooth;
|
||||||
}
|
}
|
||||||
|
|
||||||
&::scroll-button(inline-start),
|
/* the before and afters have unsnappable elements that create bouncy edges to the scroll */
|
||||||
&::scroll-button(inline-end) {
|
&::before,
|
||||||
position: fixed;
|
&::after {
|
||||||
position-anchor: --carousel;
|
content: "";
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
order: 0;
|
||||||
|
inline-size: 15cqi;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
order: 11;
|
||||||
|
inline-size: 50cqi;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::scroll-button(*) {
|
||||||
|
z-index: 20;
|
||||||
|
background: oklch(from var(--surface-1) l c h / 50%);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
}
|
}
|
||||||
|
|
||||||
&::scroll-button(inline-start) {
|
&::scroll-button(inline-start) {
|
||||||
--_inner: center span-inline-end;
|
position-area: center span-inline-start;
|
||||||
--_outer: inline-start center;
|
content: "◄" / "Previous";
|
||||||
|
|
||||||
position-area: var(--_outer);
|
|
||||||
content: 'arrow_back' / 'Previous';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&::scroll-button(inline-end) {
|
&::scroll-button(inline-end) {
|
||||||
--_inner: center span-inline-start;
|
position-area: center span-inline-end;
|
||||||
--_outer: inline-end center;
|
content: "►" / "Next";
|
||||||
|
}
|
||||||
|
|
||||||
position-area: var(--_outer);
|
& > li {
|
||||||
content: 'arrow_forward' / 'Next';
|
scroll-snap-align: start;
|
||||||
|
container-type: scroll-state;
|
||||||
|
padding: 0;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
order: calc(var(--sibling-count) - var(--sibling-index));
|
||||||
|
z-index: var(--sibling-index);
|
||||||
|
|
||||||
|
& > figure {
|
||||||
|
@supports (animation-timeline: view()) {
|
||||||
|
@media (prefers-reduced-motion: no-preference) {
|
||||||
|
animation: slide-in linear both;
|
||||||
|
animation-timeline: view(inline);
|
||||||
|
animation-range: cover -100cqi contain 25cqi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@container scroll-state(snapped: inline) {
|
||||||
|
outline: 1px solid var(--gray-1);
|
||||||
|
outline-offset: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
flex-shrink: 0;
|
||||||
|
block-size: 100cqb;
|
||||||
|
aspect-ratio: 9/16;
|
||||||
|
background: light-dark(#ccc, #444);
|
||||||
|
box-shadow: var(--shadow-5);
|
||||||
|
border-radius: 20px;
|
||||||
|
overflow: clip;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
@container (width < 480px) {
|
||||||
|
block-size: 50cqb;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > img {
|
||||||
|
inline-size: 100%;
|
||||||
|
block-size: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slide-in {
|
||||||
|
from {
|
||||||
|
transform: translateX(-100cqi) scale(0.75);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,47 +7,74 @@ import {
|
||||||
getContinueWatching,
|
getContinueWatching,
|
||||||
} from "~/features/content";
|
} from "~/features/content";
|
||||||
import { Show } from "solid-js";
|
import { Show } from "solid-js";
|
||||||
import { List } from "~/components/list";
|
import css from "./index.module.css";
|
||||||
import { ListItem } from "~/features/overview/list-item";
|
|
||||||
import css from './index.module.css';
|
|
||||||
|
|
||||||
export const route = {
|
export const route = {
|
||||||
preload: async () => ({
|
preload: async () => ({
|
||||||
highlight: await getEntry("14"),
|
highlight: await getEntry("14"),
|
||||||
categories: await listCategories(),
|
categories: await listCategories(),
|
||||||
continue: await getContinueWatching("a9c51af84bf54578a99ab4dd0ebf0763"),
|
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const highlight = createAsync(() => getEntry("14"));
|
const highlight = createAsync(() => getEntry("14"));
|
||||||
const categories = createAsync(() => listCategories());
|
const categories = createAsync(() => listCategories());
|
||||||
const continueWatching = createAsync(() =>
|
|
||||||
getContinueWatching("a9c51af84bf54578a99ab4dd0ebf0763"),
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title>Home</Title>
|
<Title>Home</Title>
|
||||||
|
|
||||||
<ul class={css.list}>
|
{/* <div class={css.carousel}>
|
||||||
<li>Item 0</li>
|
<header>some category</header>
|
||||||
<li>Item 1</li>
|
|
||||||
<li>Item 2</li>
|
|
||||||
<li>Item 3</li>
|
|
||||||
<li>Item 4</li>
|
|
||||||
<li>Item 5</li>
|
|
||||||
<li>Item 6</li>
|
|
||||||
<li>Item 7</li>
|
|
||||||
<li>Item 8</li>
|
|
||||||
<li>Item 9</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
{/* <Show when={continueWatching()}>{
|
<ul>
|
||||||
entries => <List label="Continue watching" items={entries()}>
|
<li>
|
||||||
{(item) => <ListItem entry={item()} />}
|
<figure>
|
||||||
</List>
|
<img src="https://assets.codepen.io/2585/1.jpg" alt="Item 1" />
|
||||||
}</Show> */}
|
</figure>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<figure>
|
||||||
|
<img src="https://assets.codepen.io/2585/2.avif" alt="Item 2" />
|
||||||
|
</figure>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<figure>
|
||||||
|
<img src="https://assets.codepen.io/2585/3.avif" alt="Item 3" />
|
||||||
|
</figure>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<figure>
|
||||||
|
<img src="https://assets.codepen.io/2585/4.avif" alt="Item 4" />
|
||||||
|
</figure>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<figure>
|
||||||
|
<img src="https://assets.codepen.io/2585/5.avif" alt="Item 5" />
|
||||||
|
</figure>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<figure>
|
||||||
|
<img src="https://assets.codepen.io/2585/6.avif" alt="Item 6" />
|
||||||
|
</figure>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<figure>
|
||||||
|
<img src="https://assets.codepen.io/2585/7.avif" alt="Item 7" />
|
||||||
|
</figure>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<figure>
|
||||||
|
<img src="https://assets.codepen.io/2585/8.avif" alt="Item 8" />
|
||||||
|
</figure>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<figure>
|
||||||
|
<img src="https://assets.codepen.io/2585/9.avif" alt="Item 9" />
|
||||||
|
</figure>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div> */}
|
||||||
|
|
||||||
<Show when={highlight() && categories()}>
|
<Show when={highlight() && categories()}>
|
||||||
<Overview highlight={highlight()!} categories={categories()!} />
|
<Overview highlight={highlight()!} categories={categories()!} />
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue