mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-11-16 03:40:37 +08:00
- Move all global typography styles to its own file. This makes it easier to find all the typography related definitions for newcomers. - Prefix all typography related global CSS classes with a unique prefix `.txt-`. This allows us to grep the codebase and see exactly where they are applied. Another benefit of this convention is that it helps to avoid accidentally mixing global and local styles. Having global CSS classes that sometimes overlap with component CSS classes makes it very hard to reason about the resulting visuals and making changes unpredictable. - Introduce CSS variables for standardised typography sizes and apply them to the whole codebase consistently. This way we can adjust the size in one place and it will be applied everywhere. - Avoid using predefined HTML tags which might have differing styling from browser to browser, e.g. `<h1>`, `<strong>`. We should stick to applying styling either by adding a specific global CSS class or using the predefined CSS variables, this way we can be sure that the styles won't be overridden by browser defaults. - Have a minimal set of modifiers `.txt-monospace` and `.txt-bold` and apply them consistently. Since `.txt-monospace` is defined via a CSS variable, we'll be able to switch out fonts via a user setting in the future. Signed-off-by: Rūdolfs Ošiņš <rudolfs@osins.org>
164 lines
4.4 KiB
Svelte
164 lines
4.4 KiB
Svelte
<script lang="ts">
|
|
import type { Writable } from "svelte/store";
|
|
import { navigate } from "svelte-routing";
|
|
import { Browser, ProjectContent, Project } from "@app/project";
|
|
import AnchorBadge from "@app/base/profiles/AnchorBadge.svelte";
|
|
import BranchSelector from "@app/base/projects/BranchSelector.svelte";
|
|
import CloneButton from "@app/base/projects/CloneButton.svelte";
|
|
import PeerSelector from "@app/base/projects/PeerSelector.svelte";
|
|
import type { Tree } from "@app/project";
|
|
|
|
export let project: Project;
|
|
export let tree: Tree;
|
|
export let commit: string;
|
|
export let browserStore: Writable<Browser>;
|
|
export let noAnchor = false;
|
|
|
|
const { urn, peers, branches, seed, anchors } = project;
|
|
|
|
$: browser = $browserStore;
|
|
$: revision = browser.revision || commit;
|
|
$: content = browser.content;
|
|
|
|
// Switches between project views.
|
|
const toggleContent = (input: ProjectContent, keepSourceInPath: boolean) => {
|
|
project.navigateTo({
|
|
content: content === input ? ProjectContent.Tree : input,
|
|
issue: null, // Removing issue here from browserStore to not contaminate path on navigation.
|
|
patch: null, // Removing patch here from browserStore to not contaminate path on navigation.
|
|
...(keepSourceInPath ? null : { revision: null, path: null }),
|
|
});
|
|
};
|
|
|
|
const updatePeer = (peer: string) => {
|
|
project.navigateTo({ peer, revision: null });
|
|
};
|
|
|
|
const updateRevision = (revision: string) => {
|
|
project.navigateTo({ revision });
|
|
};
|
|
</script>
|
|
|
|
<style>
|
|
header {
|
|
font-size: var(--font-size-tiny);
|
|
padding: 0 2rem 0 8rem;
|
|
margin-bottom: 2rem;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: left;
|
|
flex-wrap: wrap;
|
|
gap: 0.5rem;
|
|
}
|
|
.widget {
|
|
border-radius: var(--border-radius-small);
|
|
min-width: max-content;
|
|
}
|
|
.anchor {
|
|
display: inline-flex;
|
|
}
|
|
.clickable {
|
|
cursor: pointer;
|
|
}
|
|
.clickable:hover {
|
|
background-color: var(--color-foreground-background-lighter);
|
|
}
|
|
.not-allowed {
|
|
cursor: not-allowed;
|
|
}
|
|
.not-allowed.widget {
|
|
color: var(--color-foreground-faded);
|
|
}
|
|
.stat {
|
|
font-family: var(--font-family-monospace);
|
|
padding: 0.5rem 0.75rem;
|
|
height: 2.125rem;
|
|
background: var(--color-foreground-background);
|
|
}
|
|
.stat.active {
|
|
color: var(--color-background);
|
|
background: var(--color-foreground-90);
|
|
}
|
|
|
|
@media (max-width: 960px) {
|
|
header {
|
|
padding-left: 2rem;
|
|
}
|
|
header {
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<header>
|
|
{#if peers.length > 0}
|
|
<PeerSelector
|
|
{peers}
|
|
peer={browser.peer}
|
|
on:peerChanged={event => updatePeer(event.detail)} />
|
|
{/if}
|
|
|
|
<BranchSelector
|
|
{branches}
|
|
{project}
|
|
{revision}
|
|
on:branchChanged={event => updateRevision(event.detail)} />
|
|
|
|
{#if !noAnchor}
|
|
<div class="anchor widget">
|
|
<AnchorBadge
|
|
{commit}
|
|
{anchors}
|
|
head={project.head}
|
|
on:click={event => updateRevision(event.detail)} />
|
|
</div>
|
|
{/if}
|
|
|
|
{#if seed.git.host}
|
|
<CloneButton seedHost={seed.git.host} {urn} />
|
|
{/if}
|
|
<span>
|
|
{#if seed.api.host}
|
|
<div
|
|
class="stat seed clickable widget"
|
|
title="Project data is fetched from this seed"
|
|
on:click={() => navigate(`/seeds/${seed.api.host}`)}>
|
|
<span>{seed.api.host}</span>
|
|
</div>
|
|
{/if}
|
|
</span>
|
|
<div
|
|
class="stat commit-count clickable widget"
|
|
class:active={content === ProjectContent.History}
|
|
on:click={() => toggleContent(ProjectContent.History, true)}>
|
|
<span class="txt-bold">{tree.stats.commits}</span>
|
|
commit(s)
|
|
</div>
|
|
{#if project.issues}
|
|
<div
|
|
class="stat issue-count clickable widget"
|
|
class:active={content === ProjectContent.Issues}
|
|
class:not-allowed={project.issues === 0}
|
|
class:clickable={project.issues > 0}
|
|
on:click={() => toggleContent(ProjectContent.Issues, false)}>
|
|
<span class="txt-bold">{project.issues}</span>
|
|
issue(s)
|
|
</div>
|
|
{/if}
|
|
{#if project.patches}
|
|
<div
|
|
class="stat patch-count clickable widget"
|
|
class:active={content === ProjectContent.Patches}
|
|
class:not-allowed={project.patches === 0}
|
|
class:clickable={project.patches > 0}
|
|
on:click={() => toggleContent(ProjectContent.Patches, false)}>
|
|
<span class="txt-bold">{project.patches}</span>
|
|
patch(es)
|
|
</div>
|
|
{/if}
|
|
<div class="stat contributor-count widget">
|
|
<span class="txt-bold">{tree.stats.contributors}</span>
|
|
contributor(s)
|
|
</div>
|
|
</header>
|