diff --git a/components/package/list/list.css b/components/package/list/list.css
new file mode 100644
index 00000000..4ed2fd05
--- /dev/null
+++ b/components/package/list/list.css
@@ -0,0 +1,84 @@
+/* GitHub's package list: the search, type filter and Search button on one line, then a box with a row per package
+ (its icon, name and type, then the latest version and who published it). */
+.theme-package-search {
+ margin: 0 0 16px;
+}
+
+.theme-package-search-controls {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.theme-package-search-controls > .theme-search-field {
+ flex: 1;
+}
+
+.theme-package-row {
+ border: 1px solid var(--color-secondary);
+ border-bottom: 0;
+}
+
+.theme-package-row:first-child {
+ border-radius: 6px 6px 0 0;
+}
+
+.theme-package-row:last-of-type {
+ border-bottom: 1px solid var(--color-secondary);
+ border-radius: 0 0 6px 6px;
+}
+
+.theme-package-row:only-of-type {
+ border-radius: var(--border-radius);
+}
+
+.theme-package-row > .flex-item {
+ gap: 16px;
+ padding: 16px;
+}
+
+.theme-package-icon {
+ flex: none;
+ color: var(--color-text-light-1);
+}
+
+.theme-package-row .flex-item-title {
+ flex-wrap: wrap;
+ gap: 8px;
+ font-size: 16px;
+ line-height: 24px;
+}
+
+.theme-package-row .flex-item-title > a {
+ color: var(--color-primary);
+}
+
+.theme-package-row .flex-item-body {
+ display: block;
+ margin-top: 4px;
+ color: var(--color-text-light-1);
+ font-size: 12px;
+ line-height: 18px;
+}
+
+.theme-package-version {
+ margin-right: 12px;
+}
+
+@media (max-width: 767px) {
+ .theme-package-search-controls {
+ flex-wrap: wrap;
+ }
+
+ .theme-package-search-controls > .theme-search-field {
+ flex-basis: 100%;
+ }
+
+ .theme-package-search-controls > .theme-select-wrap {
+ flex: 1;
+ }
+
+ .theme-package-search-controls .theme-select {
+ width: 100%;
+ }
+}
diff --git a/components/package/list/list.tmpl b/components/package/list/list.tmpl
new file mode 100644
index 00000000..f247b323
--- /dev/null
+++ b/components/package/list/list.tmpl
@@ -0,0 +1,60 @@
+{{- /* GitHub's package list for a user, an organization or a repository: the search with the type filter, then a box
+with a row per package, or the empty state. Called with the page context. */ -}}
+{{if .HasPackages}}
+
+ {{range .PackageDescriptors}}
+
+
+
{{svg .Package.Type.SVGName 24}}
+
+
+
+ {{.Version.LowerVersion}}
+ {{$timeStr := DateUtils.TimeSince .Version.CreatedUnix}}
+ {{$hasRepositoryAccess := false}}
+ {{if .Repository}}
+ {{$hasRepositoryAccess = index $.RepositoryAccessMap .Repository.ID}}
+ {{end}}
+ {{if $hasRepositoryAccess}}
+ {{ctx.Locale.Tr "packages.published_by_in" $timeStr .Creator.HomeLink .Creator.GetDisplayName .Repository.Link .Repository.FullName}}
+ {{else}}
+ {{ctx.Locale.Tr "packages.published_by" $timeStr .Creator.HomeLink .Creator.GetDisplayName}}
+ {{end}}
+
+
+
+
+ {{else}}
+ {{if not .HasPackages}}
+
+ {{svg "octicon-package" 48}}
+
{{ctx.Locale.Tr "packages.empty"}}
+ {{if and .Repository .CanWritePackages}}
+ {{$packagesUrl := URLJoin .Owner.HomeLink "-" "packages"}}
+
{{ctx.Locale.Tr "packages.empty.repo" $packagesUrl}}
+ {{end}}
+
{{ctx.Locale.Tr "packages.empty.documentation" "https://forgejo.org/docs/latest/user/packages/"}}
+
+ {{else}}
+ {{template "user/profile_empty" dict "Icon" "octicon-package" "Title" (ctx.Locale.Tr "packages.filter.no_result")}}
+ {{end}}
+ {{end}}
+
+{{template "base/paginate" .}}
diff --git a/scripts/assembleForgejo.ts b/scripts/assembleForgejo.ts
index a72a6fff..61a19ab4 100644
--- a/scripts/assembleForgejo.ts
+++ b/scripts/assembleForgejo.ts
@@ -28,7 +28,7 @@ const copyTemplates = (source: string, target: string): void => {
};
copyTemplates(join(root, "components"), join(templates, "components"));
-for (const directory of ["common", "project", "repository"]) {
+for (const directory of readdirSync(join(root, "components"))) {
const source = join(root, "components", directory);
for (const component of readdirSync(source, { withFileTypes: true })) {
if (!component.isDirectory()) continue;
diff --git a/src/build-output.test.ts b/src/build-output.test.ts
index 9fba01a1..8f1661b2 100644
--- a/src/build-output.test.ts
+++ b/src/build-output.test.ts
@@ -594,6 +594,22 @@ describe("Forgejo 15 native integration", () => {
expect(read("templates", "repo", "activity.tmpl")).toContain("flex-container github-insights");
});
+ it("lists a repository's packages like a user's or an organization's", () => {
+ const read = (...parts: string[]) => fs.readFileSync(path.join(ROOT_DIR, ...parts), "utf-8");
+ expect(read("templates", "repo", "packages.tmpl")).toContain('{{template "components/package/list/list" .}}');
+ expect(read("templates", "user", "profile_packages.tmpl")).toContain(
+ '{{template "components/package/list/list" .}}'
+ );
+ // Forgejo's flash message is a classless div; the old list rule boxed it into a stray line.
+ expect(read("styles", "components", "repo", "packages.ts")).not.toContain("div:not([class])");
+ expect(read("scripts", "assembleForgejo.ts")).toContain('readdirSync(join(root, "components"))');
+ expect(
+ fs.existsSync(
+ path.join(DIST_DIR, "forgejo", "public", "assets", "css", "components", "package", "list", "list.css")
+ )
+ ).toBe(true);
+ });
+
it("matches GitHub's repository About, visibility, and code-search details", () => {
const headerStyle = fs.readFileSync(path.join(ROOT_DIR, "styles", "templates", "repo", "header.ts"), "utf-8");
const headerTemplate = fs.readFileSync(path.join(ROOT_DIR, "templates", "repo", "home_header.tmpl"), "utf-8");
diff --git a/styles/components/repo/packages.ts b/styles/components/repo/packages.ts
index dcc36723..bb4fdbb1 100644
--- a/styles/components/repo/packages.ts
+++ b/styles/components/repo/packages.ts
@@ -17,44 +17,7 @@
* limitations under the License.
*/
-import { css, cssCombine, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core";
-
-const packageList = css`
- .page-content.packages > .ui.container > div:not([class]):not(:has(img.ui.avatar)) {
- border: 1px solid ${themeVars.color.light.border};
- border-radius: ${otherThemeVars.border.radius};
- margin-top: 16px;
- > .flex-list {
- border-top: 1px solid ${themeVars.color.light.border};
- &:first-child {
- border-top: 0;
- }
- > .flex-item {
- padding: 16px;
- .flex-item-title {
- gap: 8px;
- > a {
- min-height: 25px;
- }
- .ui.label {
- background-color: transparent;
- border: 1px solid ${themeVars.color.light.border};
- color: ${themeVars.color.primary.self};
- gap: 4px;
- min-height: 24.5px;
- padding: 3px 6px;
- }
- }
- .flex-item-body {
- font-size: 12px;
- a {
- text-decoration: underline;
- }
- }
- }
- }
- }
-`;
+import { css, cssCombine, themeVars } from "@lutinglt/gitea-github-theme/core";
const packageDetails = css`
.page-content.packages {
@@ -138,4 +101,4 @@ const packageDetailsMobile = css`
}
`;
-export default cssCombine(packageList, packageDetails, packageDetailsMobile);
+export default cssCombine(packageDetails, packageDetailsMobile);
diff --git a/styles/pages/profile-subpages.css b/styles/pages/profile-subpages.css
index 3c187be3..44282992 100644
--- a/styles/pages/profile-subpages.css
+++ b/styles/pages/profile-subpages.css
@@ -266,53 +266,6 @@
line-height: 20px;
}
-:is(.github-profile, .github-org) .profile-package-row {
- border: 1px solid var(--color-secondary);
- border-bottom: 0;
-}
-
-:is(.github-profile, .github-org) .profile-package-row:first-child {
- border-radius: 6px 6px 0 0;
-}
-
-:is(.github-profile, .github-org) .profile-package-row:last-of-type {
- border-bottom: 1px solid var(--color-secondary);
- border-radius: 0 0 6px 6px;
-}
-
-:is(.github-profile, .github-org) .profile-package-row:only-of-type {
- border-radius: var(--border-radius);
-}
-
-:is(.github-profile, .github-org) .profile-package-row > .flex-item {
- gap: 16px;
- padding: 16px;
-}
-
-:is(.github-profile, .github-org) .profile-package-icon {
- flex: none;
- color: var(--color-text-light-1);
-}
-
-:is(.github-profile, .github-org) .profile-packages .flex-item-title {
- flex-wrap: wrap;
- gap: 8px;
- font-size: 16px;
- line-height: 24px;
-}
-
-:is(.github-profile, .github-org) .profile-packages .flex-item-body {
- display: block;
- margin-top: 4px;
- color: var(--color-text-light-1);
- font-size: 12px;
- line-height: 18px;
-}
-
-:is(.github-profile, .github-org) .profile-package-version {
- margin-right: 12px;
-}
-
:is(.github-profile, .github-org) .profile-package-breadcrumb {
margin: 0 0 16px;
font-size: 14px;
@@ -363,10 +316,6 @@
border-color: var(--github-borderColor-accent-emphasis);
}
-:is(.github-profile, .github-org) .profile-packages .flex-item-title > a {
- color: var(--color-primary);
-}
-
:is(.github-profile, .github-org) .profile-subpage-title {
overflow-wrap: anywhere;
}
diff --git a/templates/base/component_assets.tmpl b/templates/base/component_assets.tmpl
index 17e8b3cc..7f8d7210 100644
--- a/templates/base/component_assets.tmpl
+++ b/templates/base/component_assets.tmpl
@@ -19,6 +19,7 @@
+
+
+ {{if (and .Repository.IsPrivate .Repository.Owner.Visibility.IsPublic)}}
+
+ {{svg "octicon-alert"}}
+ {{ctx.Locale.Tr "repo.packages.visibility_warning" .Repository.OwnerName}}
+
+ {{end}}
+
{{ctx.Locale.Tr "packages.title"}}
+ {{template "base/alert" .}}
+ {{template "components/package/list/list" .}}
+
+
+{{template "base/footer" .}}
diff --git a/templates/user/profile_packages.tmpl b/templates/user/profile_packages.tmpl
index 70000f9c..da5375ba 100644
--- a/templates/user/profile_packages.tmpl
+++ b/templates/user/profile_packages.tmpl
@@ -1,63 +1,5 @@