2023-09-04 20:54:16 +02:00
|
|
|
<script>
|
|
|
|
import baseColors from 'tailwindcss/colors'
|
|
|
|
|
2023-09-05 21:09:18 +02:00
|
|
|
const workspacesPerRow = 4
|
|
|
|
const workspaceHeight = 240
|
|
|
|
const gapLength = 32
|
2023-09-04 20:54:16 +02:00
|
|
|
const colors = [baseColors.blue[500], baseColors.cyan[400], baseColors.sky[500]]
|
2023-09-05 21:09:18 +02:00
|
|
|
const leftColumns = Array.from({ length: 3 }, () => generateRow(workspacesPerRow))
|
|
|
|
const rightColumns = Array.from({ length: 3 }, () => generateRow(workspacesPerRow))
|
|
|
|
/** Used to transform the rows by their own lenght*/
|
|
|
|
const height = workspacesPerRow * (workspaceHeight + gapLength)
|
|
|
|
|
|
|
|
let wrapperElement, mouseX, mouseY
|
2023-09-04 20:54:16 +02:00
|
|
|
|
|
|
|
function generateRow(amount) {
|
|
|
|
const base = Array.from({ length: amount }).map(generateWorkspace)
|
|
|
|
// For the effect to work, the items need to be duplicated
|
|
|
|
return [...base, ...base]
|
|
|
|
}
|
|
|
|
|
|
|
|
function generateWorkspace() {
|
|
|
|
return [
|
|
|
|
generateTiles(),
|
|
|
|
Math.random() > 0.4 ? generateTiles() : false,
|
|
|
|
Math.random() > 0.7 ? generateTiles() : false
|
|
|
|
].filter(Boolean)
|
|
|
|
}
|
|
|
|
|
|
|
|
function generateTiles() {
|
|
|
|
const result = Math.random() > 0.5 ? [getRandomColor()] : [getRandomColor(), getRandomColor()]
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
function getRandomColor() {
|
|
|
|
return colors.at(Math.floor(Math.random() * colors.length))
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
|
2023-09-05 21:09:18 +02:00
|
|
|
<div class="wrapper" aria-hidden="true" bind:this={wrapperElement}>
|
2023-09-04 20:54:16 +02:00
|
|
|
<div
|
|
|
|
class="inner-wrapper"
|
2023-09-05 21:09:18 +02:00
|
|
|
style={`--amount: ${workspacesPerRow}; --workspace-gap: ${gapLength}px;--workspace-height: ${workspaceHeight}px; --length: ${height}px;`}
|
2023-09-04 20:54:16 +02:00
|
|
|
>
|
2023-09-05 21:09:18 +02:00
|
|
|
<!-- Gradient background -->
|
|
|
|
<div class="top-light" />
|
|
|
|
|
|
|
|
<div class="columns left" aria-hidden="true">
|
2023-09-04 20:54:16 +02:00
|
|
|
{#each leftColumns as column}
|
|
|
|
<div class="column">
|
|
|
|
{#each column as workspace}
|
|
|
|
<div class="workspace">
|
|
|
|
{#each workspace as tiles}
|
|
|
|
<div class="tiles">
|
|
|
|
{#each tiles as tile}
|
|
|
|
<div class="tile" style:--color={tile}></div>
|
|
|
|
{/each}
|
|
|
|
</div>
|
|
|
|
{/each}
|
|
|
|
</div>
|
|
|
|
{/each}
|
|
|
|
</div>
|
|
|
|
{/each}
|
|
|
|
</div>
|
|
|
|
|
2023-09-05 21:09:18 +02:00
|
|
|
<div class="columns right" aria-hidden="true">
|
2023-09-04 20:54:16 +02:00
|
|
|
{#each rightColumns as column}
|
|
|
|
<div class="column">
|
|
|
|
{#each column as workspace}
|
|
|
|
<div class="workspace">
|
|
|
|
{#each workspace as tiles}
|
|
|
|
<div class="tiles">
|
|
|
|
{#each tiles as tile}
|
|
|
|
<div class="tile" style:--color={tile}></div>
|
|
|
|
{/each}
|
|
|
|
</div>
|
|
|
|
{/each}
|
|
|
|
</div>
|
|
|
|
{/each}
|
|
|
|
</div>
|
|
|
|
{/each}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<style lang="postcss">
|
|
|
|
.left {
|
2023-09-05 21:09:18 +02:00
|
|
|
transform: rotateY(10deg) rotateZ(90deg);
|
2023-09-04 20:54:16 +02:00
|
|
|
}
|
|
|
|
.right {
|
2023-09-05 21:09:18 +02:00
|
|
|
transform: rotateY(-10deg) rotateZ(-90deg);
|
2023-09-04 20:54:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
.wrapper {
|
|
|
|
width: 100vw;
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
justify-content: center;
|
2023-09-05 21:09:18 +02:00
|
|
|
height: calc(100vh - 48px);
|
|
|
|
contain: strict;
|
|
|
|
|
|
|
|
@apply max-sm:hidden;
|
2023-09-04 20:54:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
.inner-wrapper {
|
|
|
|
position: absolute;
|
|
|
|
perspective: 100px;
|
|
|
|
height: 100%;
|
2023-09-05 21:09:18 +02:00
|
|
|
width: max(100vw, 2200px);
|
2023-09-04 20:54:16 +02:00
|
|
|
contain: strict;
|
|
|
|
display: flex;
|
2023-09-05 21:09:18 +02:00
|
|
|
mask-image: linear-gradient(to top, transparent 0%, black 20%);
|
|
|
|
|
|
|
|
&::after {
|
|
|
|
content: ' ';
|
|
|
|
background: radial-gradient(80% 250%, theme(colors.black) 10%, transparent 50%);
|
|
|
|
position: absolute;
|
|
|
|
top: 50%;
|
|
|
|
left: 50%;
|
|
|
|
translate: -50% -50%;
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
z-index: -10;
|
|
|
|
pointer-events: none;
|
|
|
|
}
|
2023-09-04 20:54:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
.columns {
|
|
|
|
display: flex;
|
|
|
|
gap: 2rem;
|
|
|
|
flex-grow: 1;
|
2023-09-05 21:09:18 +02:00
|
|
|
mask-image: linear-gradient(to top, transparent 0%, black 30%);
|
|
|
|
z-index: -10;
|
|
|
|
height: var(--length);
|
|
|
|
min-height: var(--length);
|
|
|
|
max-height: var(--length);
|
2023-09-04 20:54:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
.column {
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
2023-09-05 21:09:18 +02:00
|
|
|
height: 200%;
|
2023-09-04 20:54:16 +02:00
|
|
|
width: 100%;
|
|
|
|
gap: var(--workspace-gap);
|
2023-09-05 21:09:18 +02:00
|
|
|
z-index: -50;
|
|
|
|
animation: loop 98s infinite linear;
|
|
|
|
|
|
|
|
@media (prefers-reduced-motion) {
|
|
|
|
animation: none;
|
|
|
|
}
|
2023-09-04 20:54:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
.workspace {
|
|
|
|
display: flex;
|
|
|
|
gap: 8px;
|
2023-09-05 21:09:18 +02:00
|
|
|
min-height: var(--workspace-height);
|
|
|
|
max-height: var(--workspace-height);
|
2023-09-04 20:54:16 +02:00
|
|
|
width: 100%;
|
|
|
|
}
|
|
|
|
|
|
|
|
.tiles {
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
gap: 8px;
|
|
|
|
flex-grow: 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
.tile {
|
2023-09-05 21:09:18 +02:00
|
|
|
border: var(--color) 2px solid;
|
2023-09-04 20:54:16 +02:00
|
|
|
flex-grow: 1;
|
|
|
|
height: var(--height);
|
|
|
|
border-radius: 12px;
|
|
|
|
pointer-events: auto;
|
2023-09-05 21:09:18 +02:00
|
|
|
transition: all 280ms ease-in-out;
|
2023-09-04 20:54:16 +02:00
|
|
|
|
|
|
|
&:hover {
|
2023-09-05 21:09:18 +02:00
|
|
|
background: color-mix(in hsl, var(--color), transparent 20%);
|
|
|
|
box-shadow:
|
|
|
|
0px 0px 10px var(--color),
|
|
|
|
0px 0px 40px var(--color);
|
2023-09-04 20:54:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-05 21:09:18 +02:00
|
|
|
.top-light {
|
|
|
|
background: radial-gradient(
|
|
|
|
100% 80% at top,
|
|
|
|
theme(colors.cyan.500 / 60%) 0%,
|
|
|
|
theme(colors.sky.500 / 20%),
|
|
|
|
transparent
|
|
|
|
);
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
position: absolute;
|
|
|
|
z-index: 10;
|
|
|
|
top: 0;
|
|
|
|
left: 0;
|
|
|
|
pointer-events: none;
|
2023-09-04 20:54:16 +02:00
|
|
|
}
|
|
|
|
|
2023-09-05 21:09:18 +02:00
|
|
|
@keyframes loop {
|
2023-09-04 20:54:16 +02:00
|
|
|
100% {
|
2023-09-05 21:09:18 +02:00
|
|
|
translate: 0px calc(-1 * var(--length));
|
|
|
|
/* translate: 0px -50%; */
|
2023-09-04 20:54:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
</style>
|