// 1st-party
import type { ReactIsland } from "@ethicdevs/react-monolith";
// 3rd-party
import React from "react";
// generated via script[generate:prisma]
import type { Organization, Repository } from "@prisma/client";
// app
import type { WithThemeSchemeProp } from "../types";
import { AppRoute } from "../routes.defs";
import { Card } from "../components/Card.styled";
import { Grid } from "../components/Grid";
import { buildRouteLink } from "../utils/shared";
import { breakpoints, NamedColors } from "../utils/style";
export interface RepositoriesListProps {
repositories: (Repository & { parentOrg: Organization })[];
}
const RepositoriesList: ReactIsland<
RepositoriesListProps & WithThemeSchemeProp
> = ({ repositories, themeScheme }) => {
const selector = ".container";
return (
<>
<style>{`
.container {
container-type: size;
container-name: repositories;
min-block-size: 210px;
height: max-content;
}
.card {
min-width: 300px;
max-width: calc(33% - 8px);
width: 100%;
flex: 0 0 33%;
max-height: 200px;
min-height: 200px;
gap: 8px;
}
@container repositories (min-width: ${breakpoints.sml}) {
.card {
flex: .3;
min-width: calc(33% - 8px);
}
}
@container repositories (max-width: ${breakpoints.sml}) {
.card {
flex: .5;
min-width: calc(50% - 8px);
}
}
@media only screen and (max-width: ${breakpoints.s}) {
.card {
flex: 1;
min-width: calc(100% - 8px);
}
}
`}</style>
<script>{`
// quick js to set @container height based on number of cards
function resize() {
const gap = 4;
const cardWidth = 300; // match your min-width
const cardHeight = 200; // use computed or measured height
const container = document.querySelector(\`${selector}\`);
const cards = document.querySelectorAll(\`${selector} .card\`);
if (!container || cards.length === 0) return;
const containerWidth = container.clientWidth;
const cols = Math.floor((containerWidth + gap) / (cardWidth + gap));
const rows = Math.ceil(cards.length / cols);
let height = (cols * cardHeight);
let i = 0;
if (cols === 1) {
height = rows * cardHeight;
height += cardHeight;
i += rows;
} else {
height = cols * cardHeight;
i += 1;
if (cols == 2) {
if (cards.length % cols !== 0) {
height += cardHeight * 2;
i += 1;
}
} else if (cols == 3) {
if (cards.length % rows !== 0) {
height += cardHeight;
height -= cardHeight / 1.2; // why 1.2?
}
i += 1;
} else if (cols == 4) {
if (cards.length % cols !== 0) {
height -= cardHeight;
i += 1;
}
}
}
height -= ((rows * gap) * i);
// container.style.height = \`\${height}px\`;
container.style.minBlockSize = \`\${height}px\`;
cards.forEach(function (card, index) {
card.style.height = cardHeight;
card.style.maxHeight = cardHeight;
card.style.minHeight = cardHeight;
});
console.log({
containerWidth,
cols,
rows,
height,
})
}
window.addEventListener(\`load\`, function(event) {
resize();
});
window.addEventListener(\`resize\`, function(event) {
// function debounce(func, wait) {
// let timeout;
// return function() {
// clearTimeout(timeout);
// timeout = setTimeout(func, wait);
// };
// }
// debounce(resize, 200);
resize();
});
`}</script>
<Grid.Row
fluid
gap={4}
alignItems={"stretch"}
justifyContent={"stretch"}
style={{ marginTop: 16 }}
className="container"
>
{repositories.map((repo) => (
<Card key={repo.id} themeScheme={themeScheme} className="card">
<Grid.Row fluid nowrap>
<h1 style={{ margin: 0, flex: 1 }}>
<a
href={buildRouteLink(AppRoute.REPOSITORY_DETAILS, {
orgSlug: repo.parentOrg.slug,
repoSlug: repo.slug,
})}
>
{repo.parentOrg.displayName || repo.parentOrg.slug}
{" / "}
{repo.displayName || repo.slug}
{" ∙ "}
<span style={{ textTransform: "capitalize" }}>
({repo.visibility.toLowerCase()})
</span>
</a>
</h1>
{repo.isFork && (
<p style={{ margin: 0, marginTop: 8 }}>
<code>[fork]</code>
</p>
)}
</Grid.Row>
<Grid.Col fluid gap={8}>
<p style={{ margin: 0 }}>{repo.shortDescription}</p>
{repo.lastPushedAt != null && (
<p
style={{
margin: 0,
fontSize: 14,
color: NamedColors.TEXT_MUTED[themeScheme],
}}
>
Last push: {new Date(repo.lastPushedAt).toLocaleString()}
</p>
)}
</Grid.Col>
</Card>
))}
</Grid.Row>
</>
);
};
RepositoriesList.displayName = "RepositoriesList";
export default RepositoriesList;
\n [fork]\n
{repo.shortDescription}
\n {repo.lastPushedAt != null && (\n\n Last push: {new Date(repo.lastPushedAt).toLocaleString()}\n
\n )}\n