Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Where available, use the GitHub organisation avatar as the logo #33

Merged
merged 1 commit into from
Dec 6, 2022
Merged
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
8 changes: 8 additions & 0 deletions gatsby-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ module.exports = {
path: `${__dirname}/src/images`,
},
},
`github-enricher`,
{
resolve: `gatsby-plugin-remote-images`,
options: {
nodeType: "extension",
imagePath: "fields.sourceControlInfo.logoUrl",
},
},
{
resolve: `gatsby-transformer-remark`,
options: {
Expand Down
10 changes: 10 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"gatsby-plugin-fontawesome-css": "^1.2.0",
"gatsby-plugin-image": "^2.22.0",
"gatsby-plugin-manifest": "^4.22.0",
"gatsby-plugin-remote-images": "^3.6.0-alpha",
"gatsby-plugin-sharp": "^4.22.0",
"gatsby-plugin-styled-components": "^5.23.0",
"gatsby-remark-copy-linked-files": "^5.22.0",
Expand Down
45 changes: 45 additions & 0 deletions plugins/github-enricher/gatsby-node.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const defaultOptions = {
nodeType: "extension",
}

exports.onCreateNode = async ({ node, getNode, actions }, pluginOptions) => {
const { createNodeField } = actions

const options = {
...defaultOptions,
...pluginOptions,
}

if (node.internal.type !== options.nodeType) {
return
}

const { metadata } = node
const scmUrl = metadata["scm-url"]

if (scmUrl) {
// We should do this properly with the API, but for now make an educated guess about the image URL
// See https://stackoverflow.com/questions/22932422/get-github-avatar-from-email-or-name
// remove everything after the last backslash
const orgUrl = scmUrl.substr(0, scmUrl.lastIndexOf("/"))
const logoUrl = orgUrl + ".png"
const scmInfo = { url: scmUrl, logoUrl }

createNodeField({
node,
name: "sourceControlInfo",
value: scmInfo,
})
}
}

exports.createSchemaCustomization = ({ actions }) => {
const { createTypes } = actions
const typeDefs = `
type SourceControlInfo implements Node {
url: String
logo: String
}
`
createTypes(typeDefs)
}
68 changes: 68 additions & 0 deletions plugins/github-enricher/gatsby-node.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
const { onCreateNode } = require("./gatsby-node")

// This test relies on a mock in __mocks__. To validate things against
// the real implementation, rename __mocks__/node-geocoder.js to something else temporarily.

const createNodeField = jest.fn(({ node, name, value }) => {
if (!node.fields) {
node.fields = {}
}
node.fields[name] = value
})
const actions = { createNodeField }
const internal = { type: "extension" }

describe("the preprocessor", () => {
describe("for an extension with no scm information", () => {
const metadata = {}

const node = {
metadata,
internal,
}

beforeAll(async () => {
await onCreateNode({ node, actions })
})

afterAll(() => {})

it("changes nothing", async () => {
expect(node.metadata).toEqual({})
expect(node.sourceControlInfo).toBeUndefined()
})
})

describe("for an extension with a scm-url", () => {
const url = "http://gitsomething.com/someuser/somerepo"
const imageUrl = "http://gitsomething.com/someuser.png"
const metadata = {
"scm-url": url,
}

const node = {
metadata,
internal,
}

beforeAll(async () => {
await onCreateNode({ node, actions })
})

afterAll(() => {})

it("creates an scm object", async () => {
expect(node.fields.sourceControlInfo).toBeTruthy()
})

it("copies across the url", async () => {
expect(node.fields.sourceControlInfo.url).toEqual(url)
})

it("fills in an image", async () => {
expect(node.fields.sourceControlInfo.logoUrl).toEqual(imageUrl)
})

xit("adds a node for the remote image", async () => {})
})
})
3 changes: 3 additions & 0 deletions plugins/github-enricher/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "github-enricher"
}
41 changes: 31 additions & 10 deletions src/components/extension-card.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as React from "react"
import { StaticImage } from "gatsby-plugin-image"
import Link from "gatsby-link"

import styled from "styled-components"
import prettyCategory from "./util/pretty-category"
import { GatsbyImage, StaticImage } from "gatsby-plugin-image"

const Card = styled(props => <Link {...props} />)`
font-size: 3.5em;
Expand All @@ -24,8 +24,11 @@ const Card = styled(props => <Link {...props} />)`

const Logo = styled.div`
width: 80px;
height: 56px;
height: 80px;
margin-bottom: 25px;
display: flex;
justify-content: center;
align-items: center;
`

const ExtensionName = styled.div`
Expand Down Expand Up @@ -65,18 +68,36 @@ const FinerDetails = styled.div`
padding-bottom: 30px;
`

const logo = extension => {
if (extension.localImage?.childImageSharp?.gatsbyImageData) {
return (
<Logo>
<GatsbyImage
layout="constrained"
image={extension.localImage?.childImageSharp.gatsbyImageData}
alt="The extension logo"
/>
</Logo>
)
} else {
return (
<Logo>
<StaticImage
layout="constrained"
formats={["auto", "webp", "avif"]}
src="../images/generic-extension-logo.png"
alt="A generic image as a placeholder for the extension logo"
/>
</Logo>
)
}
}

const ExtensionCard = ({ extension }) => {
return (
<Card to={extension.slug} $unlisted={extension.metadata.unlisted}>
<MainInformation>
<Logo>
<StaticImage
layout="constrained"
formats={["auto", "webp", "avif"]}
src="../images/generic-extension-logo.png"
alt="The extension logo"
/>
</Logo>
{logo(extension)}
<ExtensionName $unlisted={extension.metadata.unlisted}>
{extension.name}
</ExtensionName>
Expand Down
8 changes: 8 additions & 0 deletions src/components/extension-card.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ describe("extension card", () => {
it("renders the version", () => {
expect(screen.getByText("Version: " + version)).toBeTruthy()
})

it("renders a placeholder image with appropriate source ", async () => {
const image = screen.getByAltText(
"A generic image as a placeholder for the extension logo"
)

expect(image.src).toContain("generic-extension-logo.png")
})
})

describe("an unlisted extension", () => {
Expand Down
5 changes: 5 additions & 0 deletions src/pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ export const pageQuery = graphql`
}
}
platforms
localImage {
childImageSharp {
gatsbyImageData(width: 80)
}
}
}
}
}
Expand Down