Adds components for showing Docker stats and markdown docs
This commit is contained in:
77
src/lib/DockerStats.svelte
Normal file
77
src/lib/DockerStats.svelte
Normal file
@@ -0,0 +1,77 @@
|
||||
|
||||
<script lang="ts">
|
||||
import type { DockerHubResponse } from '$src/Types';
|
||||
|
||||
export let info: DockerHubResponse;
|
||||
|
||||
const formatBigNumber = (num: number): string => {
|
||||
if (!num) return '';
|
||||
const units = ['k', 'M', 'B'];
|
||||
let unitIndex = 0;
|
||||
let value = num;
|
||||
while (value >= 1000 && unitIndex < units.length) {
|
||||
value /= 1000;
|
||||
unitIndex++;
|
||||
}
|
||||
const decimalPlaces = num < 10000 || (num >= 100000 && num < 1000000) ? 0 : 1;
|
||||
return num < 1000 ? num.toString() : value.toFixed(decimalPlaces) + units[unitIndex - 1];
|
||||
};
|
||||
|
||||
const formatDate = (dateTime: string): string => {
|
||||
if (!dateTime) return '';
|
||||
const date = new Date(dateTime);
|
||||
return new Intl.DateTimeFormat('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: '2-digit',
|
||||
}).format(date);
|
||||
};
|
||||
|
||||
const timeAgo = (dateTime: string): string => {
|
||||
if (!dateTime) return '';
|
||||
const elapsed = Date.now() - new Date(dateTime).getTime();
|
||||
const msPer = [60000, 3600000, 86400000, 2592000000, 31536000000];
|
||||
const units = ['minute', 'hour', 'day', 'month', 'year'];
|
||||
|
||||
for (let i = 0; i < msPer.length; i++) {
|
||||
if (elapsed < msPer[i]) {
|
||||
const value = Math.floor(elapsed / (i > 0 ? msPer[i - 1] : 1));
|
||||
return value === 0 ? 'just now' : `${value} ${units[i - 1] || 'minute'}${value > 1 ? 's' : ''} ago`;
|
||||
}
|
||||
}
|
||||
return `${Math.floor(elapsed / msPer[4])} years ago`;
|
||||
};
|
||||
|
||||
const makeRenderData = () => {
|
||||
const results = [
|
||||
{ label: 'Pulls', value: formatBigNumber(info.pull_count) },
|
||||
{ label: 'Stars', value: formatBigNumber(info.star_count) },
|
||||
{ label: 'User', value: info.hub_user },
|
||||
{ label: 'Created', value: formatDate(info.date_registered) },
|
||||
{ label: 'Updated', value: timeAgo(info.last_updated) },
|
||||
{ label: 'Status', value: info.status_description }
|
||||
];
|
||||
return results;
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="stats">
|
||||
{#each makeRenderData() as stat}
|
||||
<div class="row">
|
||||
<span class="lbl">{stat.label}: </span>
|
||||
<span>{stat.value}</span>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.stats {
|
||||
background: var(--card-2);
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
.lbl {
|
||||
font-weight: 500;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
85
src/lib/MdContent.svelte
Normal file
85
src/lib/MdContent.svelte
Normal file
@@ -0,0 +1,85 @@
|
||||
<script lang="ts">
|
||||
import { slide } from 'svelte/transition';
|
||||
import snarkdown from 'snarkdown';
|
||||
export let content: string;
|
||||
export let multiContent: { name: string, content: string, description: string, visible: false }[];
|
||||
|
||||
let showDocs = false;
|
||||
|
||||
const toggleDocs = () => {
|
||||
showDocs = !showDocs;
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<section class="docker-docs">
|
||||
<h2>Container Documentation</h2>
|
||||
{#if content}
|
||||
<button on:click={toggleDocs}>{ showDocs ? 'Hide' : 'Expand' } Content</button>
|
||||
{#if showDocs}
|
||||
<p transition:slide>{@html snarkdown(content)}</p>
|
||||
{/if}
|
||||
|
||||
{:else if multiContent && multiContent.length > 0}
|
||||
{#each multiContent as { name, description, content, visible }}
|
||||
<h3>{name} Documentation</h3>
|
||||
<p class="desc">{description || ''}</p>
|
||||
<button on:click={() => visible = !visible}>{ visible ? 'Hide' : 'Expand' } {name}</button>
|
||||
{#if visible}
|
||||
<p transition:slide>{@html snarkdown(content)}</p>
|
||||
{/if}
|
||||
{/each}
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
<style lang="scss">
|
||||
.docker-docs {
|
||||
background: var(--card);
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
margin: 1rem auto;
|
||||
max-width: 1000px;
|
||||
transition: all 0.2s ease-in-out;
|
||||
button {
|
||||
background: var(--background);
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 6px;
|
||||
border: none;
|
||||
color: var(--foreground);
|
||||
font-family: Kanit;
|
||||
font-size: 1.2rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease-in-out;
|
||||
&:hover {
|
||||
background: var(--gradient);
|
||||
transform: scale(1.1) rotate(-1deg);
|
||||
}
|
||||
}
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
margin: 0;
|
||||
}
|
||||
h3 {
|
||||
margin: 0.5rem 0;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
.desc {
|
||||
opacity: 0.7;
|
||||
margin: 0.5rem 0;
|
||||
font-style: italic;
|
||||
}
|
||||
:global(img) {
|
||||
max-width: 100%;
|
||||
}
|
||||
:global(a) {
|
||||
color: var(--accent);
|
||||
text-decoration: none;
|
||||
}
|
||||
:global(pre) {
|
||||
background: var(--card-2);
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user