generated from vrchat-community/template-package-listing
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit ee05903
Showing
9 changed files
with
944 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
name: Build Repo Listing | ||
|
||
on: | ||
workflow_dispatch: | ||
push: | ||
branches: main | ||
paths: source.json | ||
|
||
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages | ||
permissions: | ||
contents: read | ||
pages: write | ||
id-token: write | ||
|
||
# Allow one concurrent deployment | ||
concurrency: | ||
group: "pages" | ||
cancel-in-progress: true | ||
|
||
env: | ||
listPublishDirectory: Website | ||
pathToCi: ci | ||
|
||
jobs: | ||
|
||
build-listing: | ||
name: build-listing | ||
environment: | ||
name: github-pages | ||
url: ${{ steps.deployment.outputs.page_url }} | ||
runs-on: ubuntu-latest | ||
steps: | ||
|
||
- uses: actions/checkout@v3 # check out this repo | ||
- uses: actions/checkout@v3 # check out automation repo | ||
with: | ||
repository: vrchat-community/package-list-action | ||
path: ${{env.pathToCi}} | ||
clean: false # otherwise the local repo will no longer be checked out | ||
|
||
- name: Restore Cache | ||
uses: actions/cache@v3 | ||
with: | ||
path: | | ||
${{env.pathToCi}}/.nuke/temp | ||
~/.nuget/packages | ||
key: ${{ runner.os }}-${{ hashFiles('**/global.json', '**/*.csproj') }} | ||
|
||
- name: Build Package Version Listing | ||
run: ${{env.pathToCi}}/build.cmd BuildMultiPackageListing --root ${{env.pathToCi}} --list-publish-directory $GITHUB_WORKSPACE/${{env.listPublishDirectory}} | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
|
||
- name: Setup Pages | ||
uses: actions/configure-pages@v3 | ||
|
||
- name: Upload artifact | ||
uses: actions/upload-pages-artifact@v1 | ||
with: | ||
path: ${{env.listPublishDirectory}} | ||
|
||
- name: Deploy to GitHub Pages | ||
id: deployment | ||
uses: actions/deploy-pages@v2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
.idea | ||
.vscode |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# VPM Package Listing Template | ||
|
||
Starter for making your own Package Listings, including automation for building and publishing them. | ||
|
||
Once you're all set up, you'll be able to update the `source.json` file, and generate a listing which works in the VPM for delivering updates for all the listed packages. | ||
|
||
## ▶ Getting Started | ||
|
||
* Press [![Use This Template](https://user-images.githubusercontent.com/737888/185467681-e5fdb099-d99f-454b-8d9e-0760e5a6e588.png)](https://github.com/vrchat-community/template-package-listing/generate) | ||
to start a new GitHub project based on this template, and follow the directions there. | ||
* Choose a fitting repository name and description. | ||
* Set the visibility to 'Public'. You can also choose 'Private' and change it later. | ||
* You don't need to select 'Include all branches.' | ||
* Edit this project on GitHub in your web browser, or clone it repository locally using Git. | ||
* If you're unfamiliar with Git and GitHub, [visit GitHub's documentation](https://docs.github.com/en/get-started/quickstart/ | ||
|
||
## Setting up the Automation | ||
|
||
You'll need to edit some of the files in this template, starting with [`source.json`](source.json): | ||
- Fill out general information about your listing, such as the `name`, `id`, `author`, `description`, etc. | ||
- Make sure to update the "url" field on line 4, replacing "vrchat-community" with your GitHub username, and "template-package-listing" with your repo name. This is the link that will be used to download your listing once it's published by GitHub. For example, the user "thupper" who made a repo called "thupper-listing" would update the url to "https://thupper.github.io/thupper-listing/index.json". | ||
- Update the "url" within "infoLink" (on line 11) with the url of this new repo you've created. | ||
- If you'd like to include packages hosted on GitHub, specify them in `githubRepos`. | ||
- If you'd like to include packages hosted elsewhere as a `.zip` file, specify them in `packages`. | ||
- You can safely remove either `githubRepos` or `packages` if you're not using them. | ||
- Finally, go to the "Settings" page for your repo, then choose "Pages", and look for the heading "Build and deployment". Change the "Source" dropdown from "Deploy from a branch" to "GitHub Actions". | ||
|
||
## 📃 Rebuilding the Listing | ||
|
||
Whenever you make a change to the `main` branch, or when you trigger it manually, the 'Build Repo Listing' action will make a new index of all the releases available and publish them as a website hosted fore free on GitHub Pages. This listing can be used by the VPM to keep your package up to date, and the generated index page can serve as a simple landing page with info for your package. The URL for your package will be in the format https://username.github.io/repo-name. | ||
|
||
## 🏠 Customizing the Landing Page | ||
|
||
The contents of the `Website` directory can be customized to change the appearance of the landing page. Most of the information will be automatically filled in with information from [`source.json`](source.json). Customizing the landing page by hand is not required. | ||
|
||
## Technical Stuff | ||
|
||
You are welcome to make your own changes to the automation process to make it fit your needs, and you can create Pull Requests if you have some changes you think we should adopt. Here's some more info on the included automation: | ||
|
||
### Build Listing | ||
[build-listing.yml](.github/workflows/build-listing.yml) | ||
|
||
This is a composite action which builds a vpm-compatible [Repo Listing](https://vcc.docs.vrchat.com/vpm/repos) based on the items you've added to your `source.json` file. you've created. In order to find all your releases and combine them into a listing, it checks out [another repository](https://github.com/vrchat-community/package-list-action) which has a [Nuke](https://nuke.build/) project which includes the VPM core lib to have access to its types and methods. This project will be expanded to include more functionality in the future - for now, the action just calls its `BuildRepoListing` target, which calls `RebuildHomePage` when it completes. If you wanted to make an action that just rebuilds the home page, you could call that directly instead - just copy the existing call and replace the target names. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,231 @@ | ||
import { baseLayerLuminance, StandardLuminance } from 'https://unpkg.com/@fluentui/web-components'; | ||
|
||
const LISTING_URL = "{{ listingInfo.Url }}"; | ||
|
||
const PACKAGES = { | ||
{{~ for package in packages ~}} | ||
"{{ package.Name }}": { | ||
name: "{{ package.Name }}", | ||
displayName: "{{ if package.DisplayName; package.DisplayName; end; }}", | ||
description: "{{ if package.Description; package.Description; end; }}", | ||
version: "{{ package.Version }}", | ||
author: { | ||
name: "{{ if package.Author.Name; package.Author.Name; end; }}", | ||
url: "{{ if package.Author.Url; package.Author.Url; end; }}", | ||
}, | ||
dependencies: { | ||
{{~ for dependency in package.Dependencies ~}} | ||
"{{ dependency.Name }}": "{{ dependency.Version }}", | ||
{{~ end ~}} | ||
}, | ||
keywords: [ | ||
{{~ for keyword in package.Keywords ~}} | ||
"{{ keyword }}", | ||
{{~ end ~}} | ||
], | ||
license: "{{ package.License }}", | ||
licensesUrl: "{{ package.LicensesUrl }}", | ||
}, | ||
{{~ end ~}} | ||
}; | ||
|
||
const setTheme = () => { | ||
const isDarkTheme = () => window.matchMedia("(prefers-color-scheme: dark)").matches; | ||
if (isDarkTheme()) { | ||
baseLayerLuminance.setValueFor(document.documentElement, StandardLuminance.DarkMode); | ||
} else { | ||
baseLayerLuminance.setValueFor(document.documentElement, StandardLuminance.LightMode); | ||
} | ||
} | ||
|
||
(() => { | ||
setTheme(); | ||
|
||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { | ||
setTheme(); | ||
}); | ||
|
||
const packageGrid = document.getElementById('packageGrid'); | ||
|
||
const searchInput = document.getElementById('searchInput'); | ||
searchInput.addEventListener('input', ({ target: { value = '' }}) => { | ||
const items = packageGrid.querySelectorAll('fluent-data-grid-row[row-type="default"]'); | ||
items.forEach(item => { | ||
if (value === '') { | ||
item.style.display = 'grid'; | ||
return; | ||
} | ||
if ( | ||
item.dataset?.packageName?.toLowerCase()?.includes(value.toLowerCase()) || | ||
item.dataset?.packageId?.toLowerCase()?.includes(value.toLowerCase()) | ||
) { | ||
item.style.display = 'grid'; | ||
} else { | ||
item.style.display = 'none'; | ||
} | ||
}); | ||
}); | ||
|
||
const urlBarHelpButton = document.getElementById('urlBarHelp'); | ||
const addListingToVccHelp = document.getElementById('addListingToVccHelp'); | ||
urlBarHelpButton.addEventListener('click', () => { | ||
addListingToVccHelp.hidden = false; | ||
}); | ||
const addListingToVccHelpClose = document.getElementById('addListingToVccHelpClose'); | ||
addListingToVccHelpClose.addEventListener('click', () => { | ||
addListingToVccHelp.hidden = true; | ||
}); | ||
|
||
const vccListingInfoUrlFieldCopy = document.getElementById('vccListingInfoUrlFieldCopy'); | ||
vccListingInfoUrlFieldCopy.addEventListener('click', () => { | ||
const vccUrlField = document.getElementById('vccListingInfoUrlField'); | ||
vccUrlField.select(); | ||
navigator.clipboard.writeText(vccUrlField.value); | ||
vccUrlFieldCopy.appearance = 'accent'; | ||
setTimeout(() => { | ||
vccUrlFieldCopy.appearance = 'neutral'; | ||
}, 1000); | ||
}); | ||
|
||
const vccAddRepoButton = document.getElementById('vccAddRepoButton'); | ||
vccAddRepoButton.addEventListener('click', () => window.location.assign(`vcc://vpm/addRepo?url=${encodeURIComponent(LISTING_URL)}`)); | ||
|
||
const vccUrlFieldCopy = document.getElementById('vccUrlFieldCopy'); | ||
vccUrlFieldCopy.addEventListener('click', () => { | ||
const vccUrlField = document.getElementById('vccUrlField'); | ||
vccUrlField.select(); | ||
navigator.clipboard.writeText(vccUrlField.value); | ||
vccUrlFieldCopy.appearance = 'accent'; | ||
setTimeout(() => { | ||
vccUrlFieldCopy.appearance = 'neutral'; | ||
}, 1000); | ||
}); | ||
|
||
const rowMoreMenu = document.getElementById('rowMoreMenu'); | ||
const hideRowMoreMenu = e => { | ||
if (rowMoreMenu.contains(e.target)) return; | ||
document.removeEventListener('click', hideRowMoreMenu); | ||
rowMoreMenu.hidden = true; | ||
} | ||
|
||
const rowMenuButtons = document.querySelectorAll('.rowMenuButton'); | ||
rowMenuButtons.forEach(button => { | ||
button.addEventListener('click', e => { | ||
if (rowMoreMenu?.hidden) { | ||
rowMoreMenu.style.top = `${e.clientY + e.target.clientHeight}px`; | ||
rowMoreMenu.style.left = `${e.clientX - 120}px`; | ||
rowMoreMenu.hidden = false; | ||
|
||
const downloadLink = rowMoreMenu.querySelector('#rowMoreMenuDownload'); | ||
const downloadListener = () => { | ||
window.open(e?.target?.dataset?.packageUrl, '_blank'); | ||
} | ||
downloadLink.addEventListener('change', () => { | ||
downloadListener(); | ||
downloadLink.removeEventListener('change', downloadListener); | ||
}); | ||
|
||
setTimeout(() => { | ||
document.addEventListener('click', hideRowMoreMenu); | ||
}, 1); | ||
} | ||
}); | ||
}); | ||
|
||
const packageInfoModal = document.getElementById('packageInfoModal'); | ||
const packageInfoModalClose = document.getElementById('packageInfoModalClose'); | ||
packageInfoModalClose.addEventListener('click', () => { | ||
packageInfoModal.hidden = true; | ||
}); | ||
|
||
// Fluent dialogs use nested shadow-rooted elements, so we need to use JS to style them | ||
const modalControl = packageInfoModal.shadowRoot.querySelector('.control'); | ||
modalControl.style.maxHeight = "90%"; | ||
modalControl.style.transition = 'height 0.2s ease-in-out'; | ||
modalControl.style.overflowY = 'hidden'; | ||
|
||
const packageInfoName = document.getElementById('packageInfoName'); | ||
const packageInfoId = document.getElementById('packageInfoId'); | ||
const packageInfoVersion = document.getElementById('packageInfoVersion'); | ||
const packageInfoDescription = document.getElementById('packageInfoDescription'); | ||
const packageInfoAuthor = document.getElementById('packageInfoAuthor'); | ||
const packageInfoDependencies = document.getElementById('packageInfoDependencies'); | ||
const packageInfoKeywords = document.getElementById('packageInfoKeywords'); | ||
const packageInfoLicense = document.getElementById('packageInfoLicense'); | ||
|
||
const rowAddToVccButtons = document.querySelectorAll('.rowAddToVccButton'); | ||
rowAddToVccButtons.forEach((button) => { | ||
button.addEventListener('click', () => window.location.assign(`vcc://vpm/addRepo?url=${encodeURIComponent(LISTING_URL)}`)); | ||
}); | ||
|
||
const rowPackageInfoButton = document.querySelectorAll('.rowPackageInfoButton'); | ||
rowPackageInfoButton.forEach((button) => { | ||
button.addEventListener('click', e => { | ||
const packageId = e.target.dataset?.packageId; | ||
const packageInfo = PACKAGES?.[packageId]; | ||
if (!packageInfo) { | ||
console.error(`Did not find package ${packageId}. Packages available:`, PACKAGES); | ||
return; | ||
} | ||
|
||
packageInfoName.textContent = packageInfo.displayName; | ||
packageInfoId.textContent = packageId; | ||
packageInfoVersion.textContent = `v${packageInfo.version}`; | ||
packageInfoDescription.textContent = packageInfo.description; | ||
packageInfoAuthor.textContent = packageInfo.author.name; | ||
packageInfoAuthor.href = packageInfo.author.url; | ||
|
||
if ((packageInfo.keywords?.length ?? 0) === 0) { | ||
packageInfoKeywords.parentElement.classList.add('hidden'); | ||
} else { | ||
packageInfoKeywords.parentElement.classList.remove('hidden'); | ||
packageInfoKeywords.innerHTML = null; | ||
packageInfo.keywords.forEach(keyword => { | ||
const keywordDiv = document.createElement('div'); | ||
keywordDiv.classList.add('me-2', 'mb-2', 'badge'); | ||
keywordDiv.textContent = keyword; | ||
packageInfoKeywords.appendChild(keywordDiv); | ||
}); | ||
} | ||
|
||
if (!packageInfo.license?.length && !packageInfo.licensesUrl?.length) { | ||
packageInfoLicense.parentElement.classList.add('hidden'); | ||
} else { | ||
packageInfoLicense.parentElement.classList.remove('hidden'); | ||
packageInfoLicense.textContent = packageInfo.license ?? 'See License'; | ||
packageInfoLicense.href = packageInfo.licensesUrl ?? '#'; | ||
} | ||
|
||
packageInfoDependencies.innerHTML = null; | ||
Object.entries(packageInfo.dependencies).forEach(([name, version]) => { | ||
const depRow = document.createElement('li'); | ||
depRow.classList.add('mb-2'); | ||
depRow.textContent = `${name} @ v${version}`; | ||
packageInfoDependencies.appendChild(depRow); | ||
}); | ||
|
||
packageInfoModal.hidden = false; | ||
|
||
setTimeout(() => { | ||
const height = packageInfoModal.querySelector('.col').clientHeight; | ||
modalControl.style.setProperty('--dialog-height', `${height + 14}px`); | ||
}, 1); | ||
}); | ||
}); | ||
|
||
const packageInfoVccUrlFieldCopy = document.getElementById('packageInfoVccUrlFieldCopy'); | ||
packageInfoVccUrlFieldCopy.addEventListener('click', () => { | ||
const vccUrlField = document.getElementById('packageInfoVccUrlField'); | ||
vccUrlField.select(); | ||
navigator.clipboard.writeText(vccUrlField.value); | ||
vccUrlFieldCopy.appearance = 'accent'; | ||
setTimeout(() => { | ||
vccUrlFieldCopy.appearance = 'neutral'; | ||
}, 1000); | ||
}); | ||
|
||
const packageInfoListingHelp = document.getElementById('packageInfoListingHelp'); | ||
packageInfoListingHelp.addEventListener('click', () => { | ||
addListingToVccHelp.hidden = false; | ||
}); | ||
})(); |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Oops, something went wrong.