diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..0243ef8 Binary files /dev/null and b/.DS_Store differ diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..a362bca --- /dev/null +++ b/.eslintignore @@ -0,0 +1,5 @@ +build +node_modules +bin +*.d.ts +dist diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..57a969e --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,18 @@ +/** + * @type {import("@types/eslint").Linter.BaseConfig} + */ +module.exports = { + extends: [ + '@remix-run/eslint-config', + 'plugin:hydrogen/recommended', + 'plugin:hydrogen/typescript', + ], + rules: { + '@typescript-eslint/ban-ts-comment': 'off', + '@typescript-eslint/naming-convention': 'off', + 'hydrogen/prefer-image-component': 'off', + 'no-useless-escape': 'off', + '@typescript-eslint/no-non-null-asserted-optional-chain': 'off', + 'no-case-declarations': 'off', + }, +}; diff --git a/.github/workflows/jira.yml b/.github/workflows/jira.yml new file mode 100644 index 0000000..63960ea --- /dev/null +++ b/.github/workflows/jira.yml @@ -0,0 +1,33 @@ +name: Create JIRA ISSUE +on: + pull_request: + types: [opened] +jobs: + security: + if: ${{ github.actor == 'dependabot[bot]' || github.actor == 'snyk-bot' || contains(github.event.pull_request.head.ref, 'snyk-fix-') || contains(github.event.pull_request.head.ref, 'snyk-upgrade-')}} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Login into JIRA + uses: atlassian/gajira-login@master + env: + JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} + JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} + JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} + - name: Create a JIRA Issue + id: create + uses: atlassian/gajira-create@master + with: + project: ${{ secrets.JIRA_PROJECT }} + issuetype: ${{ secrets.JIRA_ISSUE_TYPE }} + summary: | + ${{ github.event.pull_request.title }} + description: | + PR: ${{ github.event.pull_request.html_url }} + + fields: "${{ secrets.JIRA_FIELDS }}" + - name: Transition issue + uses: atlassian/gajira-transition@v3 + with: + issue: ${{ steps.create.outputs.issue }} + transition: ${{ secrets.JIRA_TRANSITION }} diff --git a/.github/workflows/oxygen-deployment-1000010341.yml b/.github/workflows/oxygen-deployment-1000010341.yml new file mode 100644 index 0000000..530548c --- /dev/null +++ b/.github/workflows/oxygen-deployment-1000010341.yml @@ -0,0 +1,57 @@ +# Don't change the line below! +#! oxygen_storefront_id: 1000010341 + +name: Storefront 1000010341 +on: [push] + +permissions: + contents: read + deployments: write + +jobs: + deploy: + name: Deploy to Oxygen + timeout-minutes: 30 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup node.js + uses: actions/setup-node@v4 + with: + node-version: 'lts/*' + check-latest: true + + - name: Cache node modules + id: cache-npm + uses: actions/cache@v3 + env: + cache-name: cache-node-modules + with: + path: ~/.npm + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + + - name: Install dependencies + run: npm ci + + - name: Build and Publish to Oxygen + id: deploy + uses: shopify/oxygenctl-action@v4 + with: + oxygen_deployment_token: ${{ secrets.OXYGEN_DEPLOYMENT_TOKEN_1000010341 }} + build_command: "npm run build" + + # Create GitHub Deployment + - name: Create GitHub Deployment + uses: shopify/github-deployment-action@v1 + if: always() + with: + token: ${{ github.token }} + environment: 'preview' + preview_url: ${{ steps.deploy.outputs.url }} + description: ${{ github.event.head_commit.message }} + \ No newline at end of file diff --git a/.github/workflows/sca-scan.yml b/.github/workflows/sca-scan.yml new file mode 100644 index 0000000..bf9c1eb --- /dev/null +++ b/.github/workflows/sca-scan.yml @@ -0,0 +1,15 @@ +name: Source Composition Analysis Scan +on: + pull_request: + types: [opened, synchronize, reopened] +jobs: + security: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Run Snyk to check for vulnerabilities + uses: snyk/actions/node@master + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + with: + args: --all-projects --fail-on=all diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0081f9e --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +/.cache +/build +/dist +/public/build +/.mf +.env +.shopify +/node_modules +/README 2.md \ No newline at end of file diff --git a/.graphqlrc.yml b/.graphqlrc.yml new file mode 100644 index 0000000..bd38d07 --- /dev/null +++ b/.graphqlrc.yml @@ -0,0 +1 @@ +schema: node_modules/@shopify/hydrogen-react/storefront.schema.json diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..ede2e9b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,143 @@ +# skeleton + +## 1.0.0 + +### Major Changes + +- The Storefront API 2023-10 now returns menu item URLs that include the `primaryDomainUrl`, instead of defaulting to the Shopify store ID URL (example.myshopify.com). The skeleton template requires changes to check for the `primaryDomainUrl`: by [@blittle](https://github.com/blittle) + + 1. Update the `HeaderMenu` component to accept a `primaryDomainUrl` and include + it in the internal url check + + ```diff + // app/components/Header.tsx + + + import type {HeaderQuery} from 'storefrontapi.generated'; + + export function HeaderMenu({ + menu, + + primaryDomainUrl, + viewport, + }: { + menu: HeaderProps['header']['menu']; + + primaryDomainUrl: HeaderQuery['shop']['primaryDomain']['url']; + viewport: Viewport; + }) { + + // ...code + + // if the url is internal, we strip the domain + const url = + item.url.includes('myshopify.com') || + item.url.includes(publicStoreDomain) || + + item.url.includes(primaryDomainUrl) + ? new URL(item.url).pathname + : item.url; + + // ...code + + } + ``` + + 2. Update the `FooterMenu` component to accept a `primaryDomainUrl` prop and include + it in the internal url check + + ```diff + // app/components/Footer.tsx + + - import type {FooterQuery} from 'storefrontapi.generated'; + + import type {FooterQuery, HeaderQuery} from 'storefrontapi.generated'; + + function FooterMenu({ + menu, + + primaryDomainUrl, + }: { + menu: FooterQuery['menu']; + + primaryDomainUrl: HeaderQuery['shop']['primaryDomain']['url']; + }) { + // code... + + // if the url is internal, we strip the domain + const url = + item.url.includes('myshopify.com') || + item.url.includes(publicStoreDomain) || + + item.url.includes(primaryDomainUrl) + ? new URL(item.url).pathname + : item.url; + + // ...code + + ); + } + ``` + + 3. Update the `Footer` component to accept a `shop` prop + + ```diff + export function Footer({ + menu, + + shop, + }: FooterQuery & {shop: HeaderQuery['shop']}) { + return ( + + ); + } + ``` + + 4. Update `Layout.tsx` to pass the `shop` prop + + ```diff + export function Layout({ + cart, + children = null, + footer, + header, + isLoggedIn, + }: LayoutProps) { + return ( + <> + + + +
+
{children}
+ + + - {(footer) =>