diff --git a/.github/workflows/create-discussions.yml b/.github/workflows/create-discussions.yml new file mode 100644 index 0000000..ccff162 --- /dev/null +++ b/.github/workflows/create-discussions.yml @@ -0,0 +1,58 @@ +name: Create GitHub Discussions + +on: + pull_request: + types: [opened] + paths: + - 'src/content/apps/**' + workflow_dispatch: + inputs: + name: + description: 'App Name' + required: true + type: string + author: + description: 'App Author' + required: true + type: string + description: + description: 'App Description' + required: true + type: string + +jobs: + create-discussion: + runs-on: ubuntu-latest + permissions: + discussions: write + pull-requests: read + contents: read + steps: + - uses: actions/checkout@v4 + + - name: Get App Data + id: app-data + run: | + if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then + echo "name=${{ inputs.name }}" >> $GITHUB_OUTPUT + echo "author=${{ inputs.author }}" >> $GITHUB_OUTPUT + echo "description=${{ inputs.description }}" >> $GITHUB_OUTPUT + else + # Add script to extract app data from PR changes + echo "name=..." >> $GITHUB_OUTPUT + echo "author=..." >> $GITHUB_OUTPUT + echo "description=..." >> $GITHUB_OUTPUT + fi + + - name: Create Discussion + uses: abirismyname/create-discussion@v1.2.0 + with: + title: "Vote: ${{ steps.app-data.outputs.name }} by ${{ steps.app-data.outputs.author }}" + body: | + 🗳️ **Vote for this app by giving it a 👍 reaction!** + + ${{ steps.app-data.outputs.description }} + repository-id: ${{ secrets.REPO_ID }} + category-id: ${{ secrets.CAT_ID }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/update-votes.yml b/.github/workflows/update-votes.yml new file mode 100644 index 0000000..c5bff0a --- /dev/null +++ b/.github/workflows/update-votes.yml @@ -0,0 +1,61 @@ +name: Update Vote Counts + +on: + schedule: + - cron: '0 */6 * * *' # Run every 6 hours + workflow_dispatch: # Allow manual triggers + +jobs: + update-votes: + runs-on: ubuntu-latest + permissions: + contents: write + discussions: read + steps: + - uses: actions/checkout@v4 + + - name: Update Vote Counts + uses: actions/github-script@v7 + env: + CAT_ID: ${{ secrets.CAT_ID }} # Use the same secret as create-discussion + with: + script: | + const fs = require('fs').promises; + const path = require('path'); + const yaml = require('js-yaml'); + + // Get all discussions in the Flutter of the Year category + const discussions = await github.paginate(github.rest.discussions.listForRepo, { + owner: context.repo.owner, + repo: context.repo.repo, + category_id: process.env.CAT_ID // Use the environment variable + }); + + // Create votes.json with the current vote counts + const votes = {}; + for (const discussion of discussions) { + if (discussion.title.startsWith('Vote: ')) { + const appName = discussion.title.replace('Vote: ', '').split(' by ')[0]; + // Count thumbs up reactions + const reactions = await github.rest.reactions.listForDiscussion({ + owner: context.repo.owner, + repo: context.repo.repo, + discussion_number: discussion.number + }); + votes[appName] = reactions.data.filter(r => r.content === '+1').length; + } + } + + // Write the votes to a JSON file + await fs.writeFile( + 'src/data/votes.json', + JSON.stringify(votes, null, 2) + ); + + // Commit and push the changes + const date = new Date().toISOString(); + await exec.exec('git', ['config', 'user.name', 'github-actions[bot]']); + await exec.exec('git', ['config', 'user.email', 'github-actions[bot]@users.noreply.github.com']); + await exec.exec('git', ['add', 'src/data/votes.json']); + await exec.exec('git', ['commit', '-m', `Update vote counts - ${date}`]); + await exec.exec('git', ['push']); diff --git a/src/data/votes.json b/src/data/votes.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/src/data/votes.json @@ -0,0 +1 @@ +{} diff --git a/src/pages/index.astro b/src/pages/index.astro index dd9ee21..852718b 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -2,9 +2,18 @@ import { getCollection } from 'astro:content'; import { Image } from 'astro:assets'; import Layout from '../layouts/Layout.astro'; +import { getVotes, type VoteData } from '../utils/votes'; const currentYear = new Date().getFullYear(); const allApps = await getCollection('apps'); +const votes: VoteData = getVotes(); + +// Sort apps by vote count (descending) +const sortedApps = allApps.sort((a, b) => { + const votesA = votes[a.data.name] || 0; + const votesB = votes[b.data.name] || 0; + return votesB - votesA; +}); --- @@ -51,7 +60,7 @@ const allApps = await getCollection('apps');
- {allApps.map((app) => ( + {sortedApps.map((app) => (
@@ -89,6 +98,13 @@ const allApps = await getCollection('apps'); ))}
+
+

{app.data.name}

+
+ 👍 + {votes[app.data.name] || 0} +
+
))} diff --git a/src/utils/votes.ts b/src/utils/votes.ts new file mode 100644 index 0000000..9205ed5 --- /dev/null +++ b/src/utils/votes.ts @@ -0,0 +1,15 @@ +export interface VoteData { + [appName: string]: number; +} + +export function getVotes(): VoteData { + try { + // During build time, this file will be created by GitHub Actions + // We import it as a module to get the data + const votes = import.meta.glob('/src/data/votes.json', { eager: true }); + return Object.values(votes)[0] as VoteData || {}; + } catch (error) { + console.error('Error reading votes:', error); + return {}; + } +}