diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index ae3ffc5fd..a0c45afbe 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -29,7 +29,6 @@ jobs:
client-id: ${{ vars.DOTCOM_SHARED_COMPONENTS_APP_CLIENT_ID }}
client-secret: ${{ secrets.DOTCOM_SHARED_COMPONENTS_APP_CLIENT_SECRET }}
installation-id: ${{ vars.DOTCOM_SHARED_COMPONENTS_APP_INSTALLATION_ID }}
-
- name: Checkout default branch
uses: actions/checkout@v2
@@ -53,6 +52,7 @@ jobs:
run: yarn build
env:
GITHUB_TOKEN: ${{ steps.get-dotcom-access-token.outputs.access-token }}
+ FIGMA_API_TOKEN: ${{ secrets.FIGMA_TOKEN }}
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
diff --git a/.github/workflows/deploy_preview.yml b/.github/workflows/deploy_preview.yml
index 3ee032c8c..1bd02d528 100644
--- a/.github/workflows/deploy_preview.yml
+++ b/.github/workflows/deploy_preview.yml
@@ -48,6 +48,7 @@ jobs:
run: yarn build:preview
env:
GITHUB_TOKEN: ${{ steps.get-dotcom-access-token.outputs.access-token }}
+ FIGMA_API_TOKEN: ${{ secrets.FIGMA_TOKEN }}
- name: Upload artifact
uses: actions/upload-pages-artifact@v2
diff --git a/.github/workflows/get_figma_images.yml b/.github/workflows/get_figma_images.yml
deleted file mode 100644
index 63b055a7e..000000000
--- a/.github/workflows/get_figma_images.yml
+++ /dev/null
@@ -1,48 +0,0 @@
-name: Get Figma Images
-
-on:
- push:
- branches:
- - main
- pull_request:
- types:
- - labeled
-
-concurrency:
- group: ${{ github.workflow }}-${{ github.ref }}
- cancel-in-progress: true
-
-jobs:
- findNodeReferences:
- if: ${{ github.event.label.name == 'update figma images' || github.event_name == 'push' }}
- runs-on: ubuntu-latest
- env:
- FilesToScan: '**/*.mdx'
- ImageUrlFile: figmaImageNodeUrls.json
- ImageOutputDir: content/images/figma
- FigmaToken: ${{ secrets.FIGMA_TOKEN }}
- steps:
- - name: Checkout repository
- uses: actions/checkout@v4
- - name: Set up Node
- uses: actions/setup-node@v4
- with:
- node-version: 20
- cache: 'yarn'
- - name: Install dependencies
- run: yarn
- - name: Get Figma Images
- run: node scripts/getFigmaImages.js "${{env.FilesToScan}}" > ${{env.ImageUrlFile}}
- - name: Log file content
- run: cat ${{env.ImageUrlFile}}
- - name: Download images from figma
- run: npx @primer/figma-images --figmaToken ${{env.FigmaToken}} --nodeURLsFile ${{env.ImageUrlFile}} --outputDir ${{env.ImageOutputDir}}
- - name: Log output dir content
- run: ls ${{env.ImageOutputDir}}
- - uses: stefanzweifel/git-auto-commit-action@v4
- with:
- commit_message: github-actions[bot] Update figma images
- - uses: actions-ecosystem/action-remove-labels@v1
- if: always()
- with:
- labels: 'update figma images'
\ No newline at end of file
diff --git a/README.md b/README.md
index 7797d8c65..4085b5c7c 100644
--- a/README.md
+++ b/README.md
@@ -21,6 +21,13 @@ This repository is evolving as our documentation needs change. See our [contribu
4. `yarn` to install dependencies
5. `yarn start` to start the dev server
+### Figma API token
+
+To get images downloaded from the Figma API, you'll need to create a `.env` file in the root of the project and add your Figma API token. You can create a new token [here](https://www.figma.com/developers/api#access-tokens).
+
+```sh
+`FIGMA_API_TOKEN=your-token-here`
+``
## Deployment
diff --git a/content/components/banner.mdx b/content/components/banner.mdx
index 2dcbbae50..514da9c9a 100644
--- a/content/components/banner.mdx
+++ b/content/components/banner.mdx
@@ -13,11 +13,12 @@ import {Box} from '@primer/react'
import ComponentLayout from '~/src/layouts/component-layout'
export default ComponentLayout
import {AccessibilityLink} from '~/src/components/accessibility-link'
+import {FigmaImage} from '~/src/components/figma-image'
-
## Usage
diff --git a/package.json b/package.json
index 1cbe23c21..9c83935ce 100644
--- a/package.json
+++ b/package.json
@@ -3,15 +3,15 @@
"repository": "primer/design",
"version": "1.0.0",
"scripts": {
- "start": "gatsby develop",
+ "start": "yarn build:figma-images && gatsby develop",
"clean": "gatsby clean",
- "build": "npm run copy:figma-images && gatsby build",
+ "build": "yarn build:figma-images && gatsby build",
+ "build:figma-images": "node scripts/buildFigmaImages.mjs",
+ "build:preview": "yarn build:figma-images && gatsby build",
"serve": "gatsby serve",
- "build:preview": "npm run copy:figma-images && gatsby build",
"now-build": "yarn build",
"lint": "eslint .",
- "markdownlint": "markdownlint-cli2 \"**/*.{md,mdx}\" \"!.github\" \"!node_modules\"",
- "copy:figma-images": "mkdir -p public/images && cp -r content/images/figma public/images || true"
+ "markdownlint": "markdownlint-cli2 \"**/*.{md,mdx}\" \"!.github\" \"!node_modules\""
},
"dependencies": {
"@github/prettier-config": "^0.0.6",
@@ -21,8 +21,8 @@
"@primer/gatsby-theme-doctocat": "^4.7.1",
"@primer/octicons-react": "^17.3.0",
"@primer/react": "35.5.0",
- "@styled-system/props": "^5.1.5",
"@styled-system/prop-types": "5.1.5",
+ "@styled-system/props": "^5.1.5",
"@styled-system/theme-get": "^5.1.2",
"@svgr/webpack": "^6.5.1",
"@tanstack/react-query": "^4.23.0",
@@ -51,7 +51,8 @@
},
"devDependencies": {
"@github/markdownlint-github": "^0.3.0",
- "@primer/figma-images": "^0.1.2",
+ "@primer/figma-images": "^0.1.5",
+ "dotenv": "^16.4.5",
"esm": "^3.2.25",
"fast-glob": "^3.3.2",
"markdownlint-cli2": "^0.5.1",
diff --git a/scripts/buildFigmaImages.mjs b/scripts/buildFigmaImages.mjs
new file mode 100644
index 000000000..c6893d65a
--- /dev/null
+++ b/scripts/buildFigmaImages.mjs
@@ -0,0 +1,57 @@
+// Import necessary modules
+import fs from 'fs/promises'
+import fastGlob from 'fast-glob'
+import {config} from 'dotenv'
+import figmaImages from '@primer/figma-images'
+
+config()
+
+const fileGlob = '**/*.mdx'
+const outputDir = 'public/images/figma/'
+
+const isFigmaLink = match => {
+ return match.startsWith('https://www.figma.com/design/')
+}
+
+const findMatches = async (regexPattern, files) => {
+ const matches = await Promise.all(
+ files.map(async filePath => {
+ // read file content
+ const content = await fs.readFile(filePath, {encoding: 'utf8'})
+ // try to find all matches in the file content
+ const matches = [...content.matchAll(regexPattern)]
+ // for each match, return the first group
+ return matches.map(match => match[1]).filter(isFigmaLink)
+ }),
+ )
+ //
+ return matches.flat()
+}
+
+const run = async () => {
+ // check for Figma API token before proceeding
+ if (!process.env.FIGMA_API_TOKEN) {
+ console.warn('⚠️ No Figma API token provided. Skipping image download from Figma.')
+ console.log('To get a Figma API token, visit https://www.figma.com/developers/api#access-tokens')
+ console.log('Then, add the token to an .env file in the root of the project with: FIGMA_API_TOKEN=your-token-here')
+ return
+ }
+
+ // get all files that match the file glob
+ const files = await fastGlob([fileGlob])
+
+ // define the regex pattern to search
+ const pattern = /]*src="([^"]+)"[^>]*>/g
+
+ // find matches in find
+ const nodeURLs = await findMatches(pattern, files)
+
+ // fetch and download images
+ await figmaImages(process.env.FIGMA_API_TOKEN, {
+ nodeURLs,
+ outputDir,
+ missingImagesLogLevel: 'warn',
+ })
+}
+
+run()
diff --git a/scripts/getFigmaImages.js b/scripts/getFigmaImages.js
deleted file mode 100644
index dda344eac..000000000
--- a/scripts/getFigmaImages.js
+++ /dev/null
@@ -1,42 +0,0 @@
-// Import necessary modules
-const fs = require('fs').promises;
-const fastGlob = require('fast-glob');
-
-const isFigmaLink = (match) => {
- return match.startsWith('https://www.figma.com/design/')
-}
-
-const findMatches = async (regexPattern, files) => {
- const matches = await Promise.all(
- files.map(async (filePath) => {
- // read file content
- const content = await fs.readFile(filePath, { encoding: 'utf8' })
- // try to find all matches in the file content
- const matches = [...content.matchAll(regexPattern)]
- // for each match, return the first group
- return matches.map((match) => match[1]).filter(isFigmaLink);
- })
- )
- //
- return matches.flat()
-}
-
-const run = async () => {
- // get arguments
- const [fileGlob] = process.argv.slice(2)
- if(!fileGlob) {
- console.error('❌ Please provide a file glob as the argument. It needs to be wrapped in quotes.')
- return
- }
- // get all files that match the file glob
- const files = await fastGlob([fileGlob])
- // define the regex pattern to search
- const pattern = /]*src="([^"]+)"[^>]*>/g
- // find matches in find
- const matches = await findMatches(pattern, files)
- // output result
- console.log(JSON.stringify(matches, null, 2))
-
-}
-
-run()
\ No newline at end of file
diff --git a/src/components/figma-image.tsx b/src/components/figma-image.tsx
new file mode 100644
index 000000000..4daf9516a
--- /dev/null
+++ b/src/components/figma-image.tsx
@@ -0,0 +1,54 @@
+import React from 'react'
+import styled from 'styled-components'
+import {parseFigmaNodeUrl} from '@primer/figma-images/src/utils'
+import {LinkButton, StyledOcticon} from '@primer/react'
+import {PencilIcon} from '@primer/octicons-react'
+
+type FigmaImageProps = React.ImgHTMLAttributes & {
+ src: string
+ caption?: string
+}
+
+const StyledImg = styled.img`
+ max-width: 100%;
+ height: auto;
+`
+
+const StyledLinkButton = styled(LinkButton)`
+ position: absolute;
+ top: 16px;
+ right: 16px;
+ opacity: 0;
+`
+
+const StyledFigure = styled.figure`
+ position: relative;
+ width: 100%;
+ margin: 0;
+
+ &:hover ${StyledLinkButton} {
+ opacity: 1;
+ }
+`
+
+const StyledCaption = styled.figcaption``
+
+const FigmaImageDir = '/images/figma'
+export const FigmaImage: React.FC = ({src, caption, ...props}) => {
+ // check for missing prop
+ if (src === undefined) throw new Error('src is required on FigmaImage component')
+ // get real image url
+ const {nodeId, fileId} = parseFigmaNodeUrl(src)
+ const imagePath = `${FigmaImageDir}/${fileId}-${nodeId}.png`
+ // return image component
+ return (
+
+
+
+
+ Edit in Figma
+
+ {caption && {caption}}
+
+ )
+}
diff --git a/yarn.lock b/yarn.lock
index a3b505125..e6d870d31 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1992,10 +1992,10 @@
resolved "https://registry.npmjs.org/@primer/component-metadata/-/component-metadata-0.5.1.tgz"
integrity sha512-+3tuJScHWRifOAyMV+cn1I533j+PcprvPXbKnH1W7N+vhaGyaaHTao8Dkyyhxbhklmumcf8XR+Lz6dK1ojDrCg==
-"@primer/figma-images@^0.1.2":
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/@primer/figma-images/-/figma-images-0.1.2.tgz#e8fe6df96e23eaa9c1f69b6eb0f674e1be82173d"
- integrity sha512-dfWVbs67GePlYyyKoXi0AiKdTxKP3ko5nkV7+mjiOVa9Hkba6ry1KUnTVnwhs8Xceube/BoXxU/LgfdflZkxag==
+"@primer/figma-images@^0.1.5":
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/@primer/figma-images/-/figma-images-0.1.5.tgz#0f073ae968b6d725cd3c115bee2143a75bb5d6d7"
+ integrity sha512-GsKIJ+pVKdui30fiXSj/sQkZLS5WkEbwYFQcJIehzU2dQ+r5DeL1IP+gwn0x8hvi5B9PELvdXMzsrGtb2at+rg==
dependencies:
axios "^1.3.4"
dotenv "^16.0.3"
@@ -5766,7 +5766,7 @@ dot-prop@^5.2.0:
dependencies:
is-obj "^2.0.0"
-dotenv@^16.0.3:
+dotenv@^16.0.3, dotenv@^16.4.5:
version "16.4.5"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f"
integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==