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
58 changes: 58 additions & 0 deletions .github/workflows/triage_issue.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: Add Issue to Board

on:
issues:
types: [opened]

jobs:
track_issue:
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
projects: write
steps:
- name: Get project data
env:
GH_TOKEN: ${{ github.token }}
run: |
gh api graphql -f query='
query {
organization(login: "revoltchat"){
projectV2(number: 3) {
id
fields(first:20) {
nodes {
... on ProjectV2SingleSelectField {
id
name
options {
id
name
}
}
}
}
}
}
}' > project_data.json

echo 'PROJECT_ID='$(jq -r '.data.organization.projectV2.id' project_data.json) >> $GITHUB_ENV
echo 'STATUS_FIELD_ID='$(jq -r '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV
echo 'TODO_OPTION_ID='$(jq -r '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .options[] | select(.name=="Todo") |.id' project_data.json) >> $GITHUB_ENV

- name: Add issue to project
env:
GH_TOKEN: ${{ github.token }}
ISSUE_ID: ${{ github.event.issue.node_id }}
run: |
item_id="$( gh api graphql -f query='
mutation($project:ID!, $issue:ID!) {
addProjectV2ItemById(input: {projectId: $project, contentId: $issue}) {
item {
id
}
}
}' -f project=$PROJECT_ID -f issue=$ISSUE_ID --jq '.data.addProjectV2ItemById.item.id')"

echo 'ITEM_ID='$item_id >> $GITHUB_ENV
89 changes: 89 additions & 0 deletions .github/workflows/triage_pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
name: Add PR to Board

on:
pull_request_target:
types: [opened, synchronize, ready_for_review, review_requested]

permissions:
contents: read
pull-requests: write
issues: write
projects: write

jobs:
track_pr:
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Authenticate GitHub CLI
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token

- name: Get project data
run: |
set -eo pipefail
gh api graphql -f query='
query {
organization(login: "revoltchat"){
projectV2(number: 5) {
id
fields(first:20) {
nodes {
... on ProjectV2SingleSelectField {
id
name
options {
id
name
}
}
}
}
}
}
}' > project_data.json

echo 'PROJECT_ID='$(jq -r '.data.organization.projectV2.id' project_data.json) >> $GITHUB_ENV
echo 'STATUS_FIELD_ID='$(jq -r '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV
echo 'INCOMING_OPTION_ID='$(jq -r '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .options[] | select(.name=="🆕 Untriaged") | .id' project_data.json) >> $GITHUB_ENV

- name: Add PR to project
env:
PR_ID: ${{ github.event.pull_request.node_id }}
run: |
set -eo pipefail
item_id="$( gh api graphql -f query='
mutation($project:ID!, $pr:ID!) {
addProjectV2ItemById(input: {projectId: $project, contentId: $pr}) {
item {
id
}
}
}' -f project=$PROJECT_ID -f pr=$PR_ID --jq '.data.addProjectV2ItemById.item.id')"

echo 'ITEM_ID='$item_id >> $GITHUB_ENV

- name: Set fields
run: |
set -eo pipefail
gh api graphql -f query='
mutation (
$project: ID!
$item: ID!
$status_field: ID!
$status_value: String!
) {
set_status: updateProjectV2ItemFieldValue(input: {
projectId: $project
itemId: $item
fieldId: $status_field
value: {
singleSelectOptionId: $status_value
}
}) {
projectV2Item {
id
}
}
}' -f project=$PROJECT_ID -f item=$ITEM_ID -f status_field=$STATUS_FIELD_ID -f status_value=${{ env.INCOMING_OPTION_ID }} --silent
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
url = https://github.com/microsoft/fluentui-emoji
[submodule "packs/twemoji"]
path = packs/twemoji
url = https://github.com/twitter/twemoji
url = https://github.com/jdecked/twemoji
[submodule "packs/noto"]
path = packs/noto
url = https://github.com/googlefonts/noto-emoji
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ genemoji is a small CLI tool to generate Revolt's emoji asset folder. It transfo

- [Fluent](https://github.com/microsoft/fluentui-emoji)
- [Twemoji](https://twemoji.twitter.com)
- [Mutant](https://mutant.revolt.chat)
- [Mutant Remix](https://mutant.revolt.chat)
- [Noto Color Emoji](https://fonts.google.com/noto/specimen/Noto+Emoji)

## Submodule Hint
Expand Down
2 changes: 1 addition & 1 deletion packs/fluent
Submodule fluent updated 1760 files
2 changes: 1 addition & 1 deletion packs/noto
Submodule noto updated 1705 files
53 changes: 48 additions & 5 deletions src/extractors/fluent-generic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { existsSync } from "fs"
import { copyFile, mkdir, readdir, readFile, writeFile } from "fs/promises"
import { join as joinPath } from "path"
import { packsDir } from "../app.js"
import { sortEmojis } from "../sorting.js"
import {
FLUENT_TONE_DIRS,
FLUENT_TONE_DIR_TO_CODEPOINT,
Expand Down Expand Up @@ -96,10 +97,21 @@ const copySingle = async (

export const copyFluent = async (flavorName: string, toPath: string) => {
const fluentEmojiDir = joinPath(packsDir, "fluent", "assets")
const emojis = await readdir(fluentEmojiDir)
let emojis = await readdir(fluentEmojiDir)

if (!existsSync(toPath)) await mkdir(toPath)

// Process all emojis to get their filenames
const emojiFilenames: string[] = []
const emojiMetadata: Map<
string,
{
emojiPath: string
codepoints: string[]
hasSkinTones: boolean
}
> = new Map()

for (let emoji of emojis) {
const emojiPath = joinPath(fluentEmojiDir, emoji)
const emojiDirContents = (await readdir(emojiPath)).filter(
Expand All @@ -111,12 +123,43 @@ export const copyFluent = async (flavorName: string, toPath: string) => {
)
const codepoints = metadataFile.unicode.split(" ")

const hasSkinTones = emojiDirContents.includes("Medium-Dark") // name unlikely to be reused
const hasSkinTones = emojiDirContents.includes("Medium-Dark")

const filename = hasSkinTones
? codepoints.join("-") + ".svg"
: codepoints
.filter((x) => x !== VARIANT_SELECTOR_EMOJI)
.join("-") + ".svg"

emojiFilenames.push(filename)
emojiMetadata.set(filename, {
emojiPath,
codepoints,
hasSkinTones,
})
}

if (hasSkinTones) {
copyWithSkinTones(toPath, flavorName, emojiPath, codepoints)
// Sort emojis according to Emoji 15 ordering
const sortedFilenames = await sortEmojis(emojiFilenames)

// Copy emojis in sorted order
for (const filename of sortedFilenames) {
const metadata = emojiMetadata.get(filename)!

if (metadata.hasSkinTones) {
await copyWithSkinTones(
toPath,
flavorName,
metadata.emojiPath,
metadata.codepoints
)
} else {
copySingle(toPath, flavorName, emojiPath, codepoints)
await copySingle(
toPath,
flavorName,
metadata.emojiPath,
metadata.codepoints
)
}
}
}
26 changes: 21 additions & 5 deletions src/extractors/mutant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,42 @@ import { existsSync } from "fs"
import { copyFile, mkdir, readdir } from "fs/promises"
import { join as joinPath } from "path"
import { packsDir } from "../app.js"
import { sortEmojis } from "../sorting.js"
import { VARIANT_SELECTOR_EMOJI } from "../constants.js"

export const copyMutantTo = async (outDir: string) => {
const mutantDir = joinPath(packsDir, "mutant-remix", "emoji")

if (!existsSync(outDir)) await mkdir(outDir)

const mutantSvgs = await readdir(mutantDir)

for (const emoji of mutantSvgs) {
const inPath = joinPath(mutantDir, emoji)
let mutantSvgs = await readdir(mutantDir)

// Normalize filenames first
const normalizedSvgs = mutantSvgs.map((emoji) => {
const codepoints = emoji.split("-")
const normalizedFilename =
codepoints.length === 2
? codepoints
.filter((x) => x !== VARIANT_SELECTOR_EMOJI)
.join("-")
: codepoints.join("-")
const outPath = joinPath(outDir, normalizedFilename)
return { original: emoji, normalized: normalizedFilename }
})

// Sort by normalized filename
const sortedNormalized = await sortEmojis(
normalizedSvgs.map((x) => x.normalized)
)

// Create reverse mapping
const normalizedToOriginal = new Map(
normalizedSvgs.map((x) => [x.normalized, x.original])
)

for (const normalized of sortedNormalized) {
const original = normalizedToOriginal.get(normalized)!
const inPath = joinPath(mutantDir, original)
const outPath = joinPath(outDir, normalized)

await copyFile(inPath, outPath)
}
Expand Down
25 changes: 20 additions & 5 deletions src/extractors/noto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,36 @@ import { existsSync } from "fs"
import { copyFile, mkdir, readdir } from "fs/promises"
import { join as joinPath } from "path"
import { packsDir } from "../app.js"
import { sortEmojis } from "../sorting.js"

export const copyNotoTo = async (outDir: string) => {
const notoDir = joinPath(packsDir, "noto", "svg")

if (!existsSync(outDir)) await mkdir(outDir)

const notoSvgs = await readdir(notoDir)

for (const emoji of notoSvgs) {
const inPath = joinPath(notoDir, emoji)
let notoSvgs = await readdir(notoDir)

// Sort emojis according to Emoji 15 ordering
const normalizedSvgs = notoSvgs.map((emoji) => {
const normalizedFilename = emoji
.replace("emoji_u", "")
.replaceAll("_", "-")
const outPath = joinPath(outDir, normalizedFilename)
return { original: emoji, normalized: normalizedFilename }
})

const sortedNormalized = await sortEmojis(
normalizedSvgs.map((x) => x.normalized)
)

// Create reverse mapping
const normalizedToOriginal = new Map(
normalizedSvgs.map((x) => [x.normalized, x.original])
)

for (const normalized of sortedNormalized) {
const original = normalizedToOriginal.get(normalized)!
const inPath = joinPath(notoDir, original)
const outPath = joinPath(outDir, normalized)

await copyFile(inPath, outPath)
}
Expand Down
6 changes: 5 additions & 1 deletion src/extractors/twemoji.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { copyFile, mkdir, readdir } from "fs/promises"
import { existsSync } from "fs"
import { join as joinPath } from "path"
import { packsDir } from "../app.js"
import { sortEmojis } from "../sorting.js"

export const getAllExistingTwemoji = async () => {
let out: string[] = []
Expand All @@ -22,7 +23,10 @@ export const copyTwemojiTo = async (outDir: string) => {

if (!existsSync(outDir)) await mkdir(outDir)

const twemojiSvgs = await readdir(twemojiDir)
let twemojiSvgs = await readdir(twemojiDir)

// Sort emojis according to Emoji 15 ordering
twemojiSvgs = await sortEmojis(twemojiSvgs)

for (const emoji of twemojiSvgs) {
const inPath = joinPath(twemojiDir, emoji)
Expand Down
Loading
Loading