Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ export function Breadcrumbs() {
(m) => m.id === "tools/markdown-preview/markdownPreview"
);
const loginPage = matches.find((m) => m.id === "login/login");
const readmeEditPage = matches.find(
(m) => m.id === "p/readmeEdit/ReadmeEdit"
);

const communityBreadcrumb = useMemo(
() =>
Expand Down Expand Up @@ -249,9 +252,9 @@ export function Breadcrumbs() {
return <NewBreadCrumbsItem>Log in</NewBreadCrumbsItem>;
}, [loginPage]);

// No breadcrumb bar on the home page. After the hooks, as the component
// stays mounted across navigations.
if (rootIndexPage) {
// Hide breadcrumbs on the home page and the editor, which has its own
// "Go back" header. Keep this after the hooks for client-side navigation.
if (rootIndexPage || readmeEditPage) {
return null;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { faEdit } from "@fortawesome/pro-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Suspense } from "react";
import { Await } from "react-router";

import { NewButton, NewIcon } from "@thunderstore/cyberstorm";

import { type getUserPermissions } from "../../listingUtils";

export function EditMarkdownButton(props: {
permissions: ReturnType<typeof getUserPermissions> | undefined;
community: string;
namespace: string;
package: string;
version: string;
queryParams?: string;
}) {
return (
<Suspense fallback={null}>
<Await resolve={props.permissions} errorElement={<></>}>
{(resolvedPermissions) =>
resolvedPermissions?.permissions.can_manage_wiki ? (
<NewButton
csSize="small"
csVariant="secondary"
csModifiers={["ghost"]}
primitiveType="cyberstormLink"
linkId="PackageVersionReadmeEdit"
community={props.community}
namespace={props.namespace}
package={props.package}
version={props.version}
queryParams={props.queryParams}
>
<NewIcon csMode="inline" noWrapper>
<FontAwesomeIcon icon={faEdit} />
</NewIcon>
Edit
</NewButton>
) : null
}
</Await>
</Suspense>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@layer nimbus-layout {
.markdown-edited-note {
width: fit-content;
margin-bottom: var(--space-8);
color: var(--color-text-tertiary);
font-size: var(--font-size-body-sm);
}

.markdown-edited-note__label {
cursor: help;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { LocalDateTime } from "@thunderstore/cyberstorm";

import "./MarkdownEditedNote.css";

export function MarkdownEditedNote(props: {
doc: { is_edited?: boolean; edited_at?: string | null } | null;
label: "README" | "CHANGELOG";
}) {
if (!props.doc?.is_edited) return null;
return (
<div className="markdown-edited-note">
<span
className="markdown-edited-note__label"
title={`${props.label} edited on Thunderstore.`}
>
Edited
</span>
{props.doc.edited_at ? (
<>
{" · "}
<LocalDateTime time={props.doc.edited_at} timeStyle={null} />
</>
) : null}
</div>
);
}
31 changes: 31 additions & 0 deletions apps/cyberstorm-remix/app/p/packageListing.css
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,28 @@
height: 47px;
}

.package-listing__tabs-slot {
display: flex;
flex-shrink: 0;
align-items: center;

/* Match the tab items' border-bottom so the button centers on tab text. */
margin-bottom: 3px;
margin-left: auto;
padding-left: var(--space-16);
}

/* Narrow-screen stand-in for the tab-strip slot (see packageListing.tsx). */
.package-listing__edit-button-row {
display: none;
}

/* The edit button renders nothing for viewers who cannot edit. */
.package-listing__tabs-slot:empty,
.package-listing__edit-button-row:empty {
display: none;
}

.package-listing__content {
display: flex;
flex: 1 1 auto;
Expand Down Expand Up @@ -206,6 +228,15 @@
display: flex;
}

.package-listing__tabs-slot {
display: none;
}

.package-listing__edit-button-row {
display: flex;
align-items: center;
}

.package-listing__main {
grid-template-columns: minmax(0, 1fr);
width: 100%;
Expand Down
23 changes: 23 additions & 0 deletions apps/cyberstorm-remix/app/p/packageListing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import { PackageLikeAction } from "@thunderstore/cyberstorm-forms";
import { DapperTs, type DapperTsInterface } from "@thunderstore/dapper-ts";

import type { Route } from "./+types/packageListing";
import { EditMarkdownButton } from "./components/EditMarkdownButton/EditMarkdownButton";
import { PackageActions } from "./components/PackageListing/PackageActions";
import { PackageCategoriesAndTags } from "./components/PackageListing/PackageCategoriesAndTags";
import { PackageDependencyString } from "./components/PackageListing/PackageDependencyString";
Expand Down Expand Up @@ -381,6 +382,22 @@ export default function PackageListing() {
return <SkeletonBox />;
}

// Duplicated below the tab strip for narrow screens, where the strip scrolls
// the slot out of view.
const editButton =
currentTab === "details" || currentTab === "changelog" ? (
<EditMarkdownButton
permissions={permissions}
community={community_identifier}
namespace={namespace_id}
package={package_id}
version={listing.latest_version_number}
queryParams={
currentTab === "changelog" ? "document=changelog" : undefined
}
/>
) : null;

// TODO: some variables are available in props (communityId, namespaceId, packageId)
return (
<>
Expand Down Expand Up @@ -598,7 +615,13 @@ export default function PackageListing() {
>
Analysis
</NewLink>
{editButton ? (
<div className="package-listing__tabs-slot">{editButton}</div>
) : null}
</Tabs>
{editButton ? (
<div className="package-listing__edit-button-row">{editButton}</div>
) : null}

<div className="package-listing__content">
<Outlet
Expand Down
35 changes: 32 additions & 3 deletions apps/cyberstorm-remix/app/p/packageListingVersion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { faGithub } from "@fortawesome/free-brands-svg-icons";
import { faCaretRight, faUsers } from "@fortawesome/free-solid-svg-icons";
import { faArrowUpRight } from "@fortawesome/pro-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { getSessionTools } from "cyberstorm/security/publicEnvVariables";
import { getDapperForRequest } from "cyberstorm/utils/dapperSingleton";
import { getApiHostForSsr, getCanonicalUrl } from "cyberstorm/utils/env";
import { gatedSsr404 } from "cyberstorm/utils/gatedSsr";
Expand Down Expand Up @@ -39,12 +40,14 @@ import { DapperTs } from "@thunderstore/dapper-ts";
import type { PackageListingDetails } from "@thunderstore/dapper/types";

import type { Route } from "./+types/packageListingVersion";
import { EditMarkdownButton } from "./components/EditMarkdownButton/EditMarkdownButton";
import { PackageActions } from "./components/PackageListing/PackageActions";
import { PackageDependencyString } from "./components/PackageListing/PackageDependencyString";
import { PackageMeta } from "./components/PackageListing/PackageListingSidebar";
import {
getPrivateListing,
getPublicListing,
getUserPermissions,
isGithubUrl,
} from "./listingUtils";
import "./packageListing.css";
Expand Down Expand Up @@ -126,6 +129,7 @@ export const loader = ssrLoader(
return gatedSsr404({
community,
listing: undefined,
permissions: undefined,
packageVersion,
team,
seo: createSeo({ descriptors: [] }),
Expand All @@ -140,6 +144,7 @@ export const loader = ssrLoader(
return {
community,
listing,
permissions: undefined,
packageVersion,
team,
seo: packageVersionSeo(listing, packageVersion, request),
Expand Down Expand Up @@ -172,6 +177,13 @@ export async function clientLoader({
return {
community: dapper.getCommunity(communityId),
listing,
permissions: getUserPermissions(
getSessionTools(),
dapper,
communityId,
namespaceId,
packageId
),
packageVersion,
team: dapper.getTeamDetails(namespaceId),
// Match the SSR title so hydration doesn't drop it (see packageVersionSeo).
Expand All @@ -197,9 +209,8 @@ export function shouldRevalidate(arg: ShouldRevalidateFunctionArgs) {
}

export default function PackageListingVersion() {
const { community, listing, packageVersion, team } = useLoaderData<
typeof loader | typeof clientLoader
>();
const { community, listing, permissions, packageVersion, team } =
useLoaderData<typeof loader | typeof clientLoader>();

const location = useLocation();
const outletContext = useOutletContext() as OutletContextShape;
Expand All @@ -211,6 +222,18 @@ export default function PackageListingVersion() {
return <div>Loading listing...</div>;
}

const editButton =
currentTab === "details" ? (
<EditMarkdownButton
permissions={permissions}
community={listing.community_identifier}
namespace={listing.namespace}
package={listing.name}
version={packageVersion}
queryParams="from=version"
/>
) : null;

return (
<>
{/* Community hero banner — its own grid row (see
Expand Down Expand Up @@ -371,7 +394,13 @@ export default function PackageListingVersion() {
>
Versions
</NewLink>
{editButton ? (
<div className="package-listing__tabs-slot">{editButton}</div>
) : null}
</Tabs>
{editButton ? (
<div className="package-listing__edit-button-row">{editButton}</div>
) : null}

<div className="package-listing__content">
<Outlet context={outletContext} />
Expand Down
Loading
Loading