hydrogen-forge 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/README.md +212 -0
  2. package/dist/commands/add.d.ts +7 -0
  3. package/dist/commands/add.d.ts.map +1 -0
  4. package/dist/commands/add.js +123 -0
  5. package/dist/commands/add.js.map +1 -0
  6. package/dist/commands/create.d.ts +8 -0
  7. package/dist/commands/create.d.ts.map +1 -0
  8. package/dist/commands/create.js +160 -0
  9. package/dist/commands/create.js.map +1 -0
  10. package/dist/commands/setup-mcp.d.ts +7 -0
  11. package/dist/commands/setup-mcp.d.ts.map +1 -0
  12. package/dist/commands/setup-mcp.js +179 -0
  13. package/dist/commands/setup-mcp.js.map +1 -0
  14. package/dist/index.d.ts +3 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +50 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/lib/generators.d.ts +6 -0
  19. package/dist/lib/generators.d.ts.map +1 -0
  20. package/dist/lib/generators.js +470 -0
  21. package/dist/lib/generators.js.map +1 -0
  22. package/dist/lib/utils.d.ts +17 -0
  23. package/dist/lib/utils.d.ts.map +1 -0
  24. package/dist/lib/utils.js +101 -0
  25. package/dist/lib/utils.js.map +1 -0
  26. package/package.json +54 -0
  27. package/templates/starter/.env.example +21 -0
  28. package/templates/starter/.graphqlrc.ts +27 -0
  29. package/templates/starter/README.md +117 -0
  30. package/templates/starter/app/assets/favicon.svg +28 -0
  31. package/templates/starter/app/components/AddToCartButton.tsx +102 -0
  32. package/templates/starter/app/components/Aside.tsx +136 -0
  33. package/templates/starter/app/components/CartLineItem.tsx +229 -0
  34. package/templates/starter/app/components/CartMain.tsx +131 -0
  35. package/templates/starter/app/components/CartSummary.tsx +315 -0
  36. package/templates/starter/app/components/CollectionFilters.tsx +330 -0
  37. package/templates/starter/app/components/CollectionGrid.tsx +141 -0
  38. package/templates/starter/app/components/Footer.tsx +218 -0
  39. package/templates/starter/app/components/Header.tsx +296 -0
  40. package/templates/starter/app/components/PageLayout.tsx +174 -0
  41. package/templates/starter/app/components/PaginatedResourceSection.tsx +41 -0
  42. package/templates/starter/app/components/ProductCard.tsx +151 -0
  43. package/templates/starter/app/components/ProductForm.tsx +156 -0
  44. package/templates/starter/app/components/ProductGallery.tsx +164 -0
  45. package/templates/starter/app/components/ProductGrid.tsx +64 -0
  46. package/templates/starter/app/components/ProductImage.tsx +23 -0
  47. package/templates/starter/app/components/ProductItem.tsx +44 -0
  48. package/templates/starter/app/components/ProductPrice.tsx +97 -0
  49. package/templates/starter/app/components/SearchDialog.tsx +599 -0
  50. package/templates/starter/app/components/SearchForm.tsx +68 -0
  51. package/templates/starter/app/components/SearchFormPredictive.tsx +76 -0
  52. package/templates/starter/app/components/SearchResults.tsx +161 -0
  53. package/templates/starter/app/components/SearchResultsPredictive.tsx +461 -0
  54. package/templates/starter/app/entry.client.tsx +21 -0
  55. package/templates/starter/app/entry.server.tsx +53 -0
  56. package/templates/starter/app/graphql/customer-account/CustomerAddressMutations.ts +64 -0
  57. package/templates/starter/app/graphql/customer-account/CustomerDetailsQuery.ts +40 -0
  58. package/templates/starter/app/graphql/customer-account/CustomerOrderQuery.ts +90 -0
  59. package/templates/starter/app/graphql/customer-account/CustomerOrdersQuery.ts +63 -0
  60. package/templates/starter/app/graphql/customer-account/CustomerUpdateMutation.ts +25 -0
  61. package/templates/starter/app/lib/context.ts +60 -0
  62. package/templates/starter/app/lib/fragments.ts +234 -0
  63. package/templates/starter/app/lib/orderFilters.ts +90 -0
  64. package/templates/starter/app/lib/redirect.ts +23 -0
  65. package/templates/starter/app/lib/search.ts +79 -0
  66. package/templates/starter/app/lib/session.ts +72 -0
  67. package/templates/starter/app/lib/variants.ts +46 -0
  68. package/templates/starter/app/root.tsx +209 -0
  69. package/templates/starter/app/routes/$.tsx +11 -0
  70. package/templates/starter/app/routes/[robots.txt].tsx +117 -0
  71. package/templates/starter/app/routes/[sitemap.xml].tsx +16 -0
  72. package/templates/starter/app/routes/_index.tsx +167 -0
  73. package/templates/starter/app/routes/account.$.tsx +9 -0
  74. package/templates/starter/app/routes/account._index.tsx +5 -0
  75. package/templates/starter/app/routes/account.addresses.tsx +516 -0
  76. package/templates/starter/app/routes/account.orders.$id.tsx +222 -0
  77. package/templates/starter/app/routes/account.orders._index.tsx +222 -0
  78. package/templates/starter/app/routes/account.profile.tsx +133 -0
  79. package/templates/starter/app/routes/account.tsx +97 -0
  80. package/templates/starter/app/routes/account_.authorize.tsx +5 -0
  81. package/templates/starter/app/routes/account_.login.tsx +7 -0
  82. package/templates/starter/app/routes/account_.logout.tsx +11 -0
  83. package/templates/starter/app/routes/api.$version.[graphql.json].tsx +14 -0
  84. package/templates/starter/app/routes/blogs.$blogHandle.$articleHandle.tsx +129 -0
  85. package/templates/starter/app/routes/blogs.$blogHandle._index.tsx +175 -0
  86. package/templates/starter/app/routes/blogs._index.tsx +109 -0
  87. package/templates/starter/app/routes/cart.$lines.tsx +70 -0
  88. package/templates/starter/app/routes/cart.tsx +117 -0
  89. package/templates/starter/app/routes/collections.$handle.tsx +161 -0
  90. package/templates/starter/app/routes/collections._index.tsx +133 -0
  91. package/templates/starter/app/routes/collections.all.tsx +122 -0
  92. package/templates/starter/app/routes/discount.$code.tsx +48 -0
  93. package/templates/starter/app/routes/pages.$handle.tsx +88 -0
  94. package/templates/starter/app/routes/policies.$handle.tsx +93 -0
  95. package/templates/starter/app/routes/policies._index.tsx +69 -0
  96. package/templates/starter/app/routes/products.$handle.tsx +232 -0
  97. package/templates/starter/app/routes/search.tsx +426 -0
  98. package/templates/starter/app/routes/sitemap.$type.$page[.xml].tsx +23 -0
  99. package/templates/starter/app/routes.ts +9 -0
  100. package/templates/starter/app/styles/app.css +574 -0
  101. package/templates/starter/app/styles/reset.css +139 -0
  102. package/templates/starter/app/styles/tailwind.css +116 -0
  103. package/templates/starter/customer-accountapi.generated.d.ts +543 -0
  104. package/templates/starter/env.d.ts +7 -0
  105. package/templates/starter/eslint.config.js +247 -0
  106. package/templates/starter/guides/predictiveSearch/predictiveSearch.jpg +0 -0
  107. package/templates/starter/guides/predictiveSearch/predictiveSearch.md +394 -0
  108. package/templates/starter/guides/search/search.jpg +0 -0
  109. package/templates/starter/guides/search/search.md +335 -0
  110. package/templates/starter/package.json +71 -0
  111. package/templates/starter/postcss.config.js +6 -0
  112. package/templates/starter/public/.gitkeep +0 -0
  113. package/templates/starter/react-router.config.ts +13 -0
  114. package/templates/starter/server.ts +59 -0
  115. package/templates/starter/storefrontapi.generated.d.ts +1264 -0
  116. package/templates/starter/tailwind.config.js +83 -0
  117. package/templates/starter/tsconfig.json +67 -0
  118. package/templates/starter/vite.config.ts +32 -0
@@ -0,0 +1,21 @@
1
+ import {HydratedRouter} from 'react-router/dom';
2
+ import {startTransition, StrictMode} from 'react';
3
+ import {hydrateRoot} from 'react-dom/client';
4
+ import {NonceProvider} from '@shopify/hydrogen';
5
+
6
+ if (!window.location.origin.includes('webcache.googleusercontent.com')) {
7
+ startTransition(() => {
8
+ // Extract nonce from existing script tags
9
+ const existingNonce =
10
+ document.querySelector<HTMLScriptElement>('script[nonce]')?.nonce;
11
+
12
+ hydrateRoot(
13
+ document,
14
+ <StrictMode>
15
+ <NonceProvider value={existingNonce}>
16
+ <HydratedRouter />
17
+ </NonceProvider>
18
+ </StrictMode>,
19
+ );
20
+ });
21
+ }
@@ -0,0 +1,53 @@
1
+ import {ServerRouter} from 'react-router';
2
+ import {isbot} from 'isbot';
3
+ import {renderToReadableStream} from 'react-dom/server';
4
+ import {
5
+ createContentSecurityPolicy,
6
+ type HydrogenRouterContextProvider,
7
+ } from '@shopify/hydrogen';
8
+ import type {EntryContext} from 'react-router';
9
+
10
+ export default async function handleRequest(
11
+ request: Request,
12
+ responseStatusCode: number,
13
+ responseHeaders: Headers,
14
+ reactRouterContext: EntryContext,
15
+ context: HydrogenRouterContextProvider,
16
+ ) {
17
+ const {nonce, header, NonceProvider} = createContentSecurityPolicy({
18
+ shop: {
19
+ checkoutDomain: context.env.PUBLIC_CHECKOUT_DOMAIN,
20
+ storeDomain: context.env.PUBLIC_STORE_DOMAIN,
21
+ },
22
+ });
23
+
24
+ const body = await renderToReadableStream(
25
+ <NonceProvider>
26
+ <ServerRouter
27
+ context={reactRouterContext}
28
+ url={request.url}
29
+ nonce={nonce}
30
+ />
31
+ </NonceProvider>,
32
+ {
33
+ nonce,
34
+ signal: request.signal,
35
+ onError(error) {
36
+ console.error(error);
37
+ responseStatusCode = 500;
38
+ },
39
+ },
40
+ );
41
+
42
+ if (isbot(request.headers.get('user-agent'))) {
43
+ await body.allReady;
44
+ }
45
+
46
+ responseHeaders.set('Content-Type', 'text/html');
47
+ responseHeaders.set('Content-Security-Policy', header);
48
+
49
+ return new Response(body, {
50
+ headers: responseHeaders,
51
+ status: responseStatusCode,
52
+ });
53
+ }
@@ -0,0 +1,64 @@
1
+ // NOTE: https://shopify.dev/docs/api/customer/latest/mutations/customerAddressUpdate
2
+ export const UPDATE_ADDRESS_MUTATION = `#graphql
3
+ mutation customerAddressUpdate(
4
+ $address: CustomerAddressInput!
5
+ $addressId: ID!
6
+ $defaultAddress: Boolean
7
+ $language: LanguageCode
8
+ ) @inContext(language: $language) {
9
+ customerAddressUpdate(
10
+ address: $address
11
+ addressId: $addressId
12
+ defaultAddress: $defaultAddress
13
+ ) {
14
+ customerAddress {
15
+ id
16
+ }
17
+ userErrors {
18
+ code
19
+ field
20
+ message
21
+ }
22
+ }
23
+ }
24
+ ` as const;
25
+
26
+ // NOTE: https://shopify.dev/docs/api/customer/latest/mutations/customerAddressDelete
27
+ export const DELETE_ADDRESS_MUTATION = `#graphql
28
+ mutation customerAddressDelete(
29
+ $addressId: ID!
30
+ $language: LanguageCode
31
+ ) @inContext(language: $language) {
32
+ customerAddressDelete(addressId: $addressId) {
33
+ deletedAddressId
34
+ userErrors {
35
+ code
36
+ field
37
+ message
38
+ }
39
+ }
40
+ }
41
+ ` as const;
42
+
43
+ // NOTE: https://shopify.dev/docs/api/customer/latest/mutations/customerAddressCreate
44
+ export const CREATE_ADDRESS_MUTATION = `#graphql
45
+ mutation customerAddressCreate(
46
+ $address: CustomerAddressInput!
47
+ $defaultAddress: Boolean
48
+ $language: LanguageCode
49
+ ) @inContext(language: $language) {
50
+ customerAddressCreate(
51
+ address: $address
52
+ defaultAddress: $defaultAddress
53
+ ) {
54
+ customerAddress {
55
+ id
56
+ }
57
+ userErrors {
58
+ code
59
+ field
60
+ message
61
+ }
62
+ }
63
+ }
64
+ ` as const;
@@ -0,0 +1,40 @@
1
+ // NOTE: https://shopify.dev/docs/api/customer/latest/objects/Customer
2
+ export const CUSTOMER_FRAGMENT = `#graphql
3
+ fragment Customer on Customer {
4
+ id
5
+ firstName
6
+ lastName
7
+ defaultAddress {
8
+ ...Address
9
+ }
10
+ addresses(first: 6) {
11
+ nodes {
12
+ ...Address
13
+ }
14
+ }
15
+ }
16
+ fragment Address on CustomerAddress {
17
+ id
18
+ formatted
19
+ firstName
20
+ lastName
21
+ company
22
+ address1
23
+ address2
24
+ territoryCode
25
+ zoneCode
26
+ city
27
+ zip
28
+ phoneNumber
29
+ }
30
+ ` as const;
31
+
32
+ // NOTE: https://shopify.dev/docs/api/customer/latest/queries/customer
33
+ export const CUSTOMER_DETAILS_QUERY = `#graphql
34
+ query CustomerDetails($language: LanguageCode) @inContext(language: $language) {
35
+ customer {
36
+ ...Customer
37
+ }
38
+ }
39
+ ${CUSTOMER_FRAGMENT}
40
+ ` as const;
@@ -0,0 +1,90 @@
1
+ // NOTE: https://shopify.dev/docs/api/customer/latest/queries/order
2
+ export const CUSTOMER_ORDER_QUERY = `#graphql
3
+ fragment OrderMoney on MoneyV2 {
4
+ amount
5
+ currencyCode
6
+ }
7
+ fragment DiscountApplication on DiscountApplication {
8
+ value {
9
+ __typename
10
+ ... on MoneyV2 {
11
+ ...OrderMoney
12
+ }
13
+ ... on PricingPercentageValue {
14
+ percentage
15
+ }
16
+ }
17
+ }
18
+ fragment OrderLineItemFull on LineItem {
19
+ id
20
+ title
21
+ quantity
22
+ price {
23
+ ...OrderMoney
24
+ }
25
+ discountAllocations {
26
+ allocatedAmount {
27
+ ...OrderMoney
28
+ }
29
+ discountApplication {
30
+ ...DiscountApplication
31
+ }
32
+ }
33
+ totalDiscount {
34
+ ...OrderMoney
35
+ }
36
+ image {
37
+ altText
38
+ height
39
+ url
40
+ id
41
+ width
42
+ }
43
+ variantTitle
44
+ }
45
+ fragment Order on Order {
46
+ id
47
+ name
48
+ confirmationNumber
49
+ statusPageUrl
50
+ fulfillmentStatus
51
+ processedAt
52
+ fulfillments(first: 1) {
53
+ nodes {
54
+ status
55
+ }
56
+ }
57
+ totalTax {
58
+ ...OrderMoney
59
+ }
60
+ totalPrice {
61
+ ...OrderMoney
62
+ }
63
+ subtotal {
64
+ ...OrderMoney
65
+ }
66
+ shippingAddress {
67
+ name
68
+ formatted(withName: true)
69
+ formattedArea
70
+ }
71
+ discountApplications(first: 100) {
72
+ nodes {
73
+ ...DiscountApplication
74
+ }
75
+ }
76
+ lineItems(first: 100) {
77
+ nodes {
78
+ ...OrderLineItemFull
79
+ }
80
+ }
81
+ }
82
+ query Order($orderId: ID!, $language: LanguageCode)
83
+ @inContext(language: $language) {
84
+ order(id: $orderId) {
85
+ ... on Order {
86
+ ...Order
87
+ }
88
+ }
89
+ }
90
+ ` as const;
@@ -0,0 +1,63 @@
1
+ // NOTE: https://shopify.dev/docs/api/customer/latest/objects/Order
2
+ export const ORDER_ITEM_FRAGMENT = `#graphql
3
+ fragment OrderItem on Order {
4
+ totalPrice {
5
+ amount
6
+ currencyCode
7
+ }
8
+ financialStatus
9
+ fulfillmentStatus
10
+ fulfillments(first: 1) {
11
+ nodes {
12
+ status
13
+ }
14
+ }
15
+ id
16
+ number
17
+ confirmationNumber
18
+ processedAt
19
+ }
20
+ ` as const;
21
+
22
+ // NOTE: https://shopify.dev/docs/api/customer/latest/objects/Customer
23
+ export const CUSTOMER_ORDERS_FRAGMENT = `#graphql
24
+ fragment CustomerOrders on Customer {
25
+ orders(
26
+ sortKey: PROCESSED_AT,
27
+ reverse: true,
28
+ first: $first,
29
+ last: $last,
30
+ before: $startCursor,
31
+ after: $endCursor,
32
+ query: $query
33
+ ) {
34
+ nodes {
35
+ ...OrderItem
36
+ }
37
+ pageInfo {
38
+ hasPreviousPage
39
+ hasNextPage
40
+ endCursor
41
+ startCursor
42
+ }
43
+ }
44
+ }
45
+ ${ORDER_ITEM_FRAGMENT}
46
+ ` as const;
47
+
48
+ // NOTE: https://shopify.dev/docs/api/customer/latest/queries/customer
49
+ export const CUSTOMER_ORDERS_QUERY = `#graphql
50
+ ${CUSTOMER_ORDERS_FRAGMENT}
51
+ query CustomerOrders(
52
+ $endCursor: String
53
+ $first: Int
54
+ $last: Int
55
+ $startCursor: String
56
+ $query: String
57
+ $language: LanguageCode
58
+ ) @inContext(language: $language) {
59
+ customer {
60
+ ...CustomerOrders
61
+ }
62
+ }
63
+ ` as const;
@@ -0,0 +1,25 @@
1
+ // NOTE: https://shopify.dev/docs/api/customer/latest/mutations/customerUpdate
2
+ export const CUSTOMER_UPDATE_MUTATION = `#graphql
3
+ mutation customerUpdate(
4
+ $customer: CustomerUpdateInput!
5
+ $language: LanguageCode
6
+ ) @inContext(language: $language) {
7
+ customerUpdate(input: $customer) {
8
+ customer {
9
+ firstName
10
+ lastName
11
+ emailAddress {
12
+ emailAddress
13
+ }
14
+ phoneNumber {
15
+ phoneNumber
16
+ }
17
+ }
18
+ userErrors {
19
+ code
20
+ field
21
+ message
22
+ }
23
+ }
24
+ }
25
+ ` as const;
@@ -0,0 +1,60 @@
1
+ import {createHydrogenContext} from '@shopify/hydrogen';
2
+ import {AppSession} from '~/lib/session';
3
+ import {CART_QUERY_FRAGMENT} from '~/lib/fragments';
4
+
5
+ // Define the additional context object
6
+ const additionalContext = {
7
+ // Additional context for custom properties, CMS clients, 3P SDKs, etc.
8
+ // These will be available as both context.propertyName and context.get(propertyContext)
9
+ // Example of complex objects that could be added:
10
+ // cms: await createCMSClient(env),
11
+ // reviews: await createReviewsClient(env),
12
+ } as const;
13
+
14
+ // Automatically augment HydrogenAdditionalContext with the additional context type
15
+ type AdditionalContextType = typeof additionalContext;
16
+
17
+ declare global {
18
+ interface HydrogenAdditionalContext extends AdditionalContextType {}
19
+ }
20
+
21
+ /**
22
+ * Creates Hydrogen context for React Router 7.9.x
23
+ * Returns HydrogenRouterContextProvider with hybrid access patterns
24
+ * */
25
+ export async function createHydrogenRouterContext(
26
+ request: Request,
27
+ env: Env,
28
+ executionContext: ExecutionContext,
29
+ ) {
30
+ /**
31
+ * Open a cache instance in the worker and a custom session instance.
32
+ */
33
+ if (!env?.SESSION_SECRET) {
34
+ throw new Error('SESSION_SECRET environment variable is not set');
35
+ }
36
+
37
+ const waitUntil = executionContext.waitUntil.bind(executionContext);
38
+ const [cache, session] = await Promise.all([
39
+ caches.open('hydrogen'),
40
+ AppSession.init(request, [env.SESSION_SECRET]),
41
+ ]);
42
+
43
+ const hydrogenContext = createHydrogenContext(
44
+ {
45
+ env,
46
+ request,
47
+ cache,
48
+ waitUntil,
49
+ session,
50
+ // Or detect from URL path based on locale subpath, cookies, or any other strategy
51
+ i18n: {language: 'EN', country: 'US'},
52
+ cart: {
53
+ queryFragment: CART_QUERY_FRAGMENT,
54
+ },
55
+ },
56
+ additionalContext,
57
+ );
58
+
59
+ return hydrogenContext;
60
+ }
@@ -0,0 +1,234 @@
1
+ // NOTE: https://shopify.dev/docs/api/storefront/latest/queries/cart
2
+ export const CART_QUERY_FRAGMENT = `#graphql
3
+ fragment Money on MoneyV2 {
4
+ currencyCode
5
+ amount
6
+ }
7
+ fragment CartLine on CartLine {
8
+ id
9
+ quantity
10
+ attributes {
11
+ key
12
+ value
13
+ }
14
+ cost {
15
+ totalAmount {
16
+ ...Money
17
+ }
18
+ amountPerQuantity {
19
+ ...Money
20
+ }
21
+ compareAtAmountPerQuantity {
22
+ ...Money
23
+ }
24
+ }
25
+ merchandise {
26
+ ... on ProductVariant {
27
+ id
28
+ availableForSale
29
+ compareAtPrice {
30
+ ...Money
31
+ }
32
+ price {
33
+ ...Money
34
+ }
35
+ requiresShipping
36
+ title
37
+ image {
38
+ id
39
+ url
40
+ altText
41
+ width
42
+ height
43
+
44
+ }
45
+ product {
46
+ handle
47
+ title
48
+ id
49
+ vendor
50
+ }
51
+ selectedOptions {
52
+ name
53
+ value
54
+ }
55
+ }
56
+ }
57
+ }
58
+ fragment CartLineComponent on ComponentizableCartLine {
59
+ id
60
+ quantity
61
+ attributes {
62
+ key
63
+ value
64
+ }
65
+ cost {
66
+ totalAmount {
67
+ ...Money
68
+ }
69
+ amountPerQuantity {
70
+ ...Money
71
+ }
72
+ compareAtAmountPerQuantity {
73
+ ...Money
74
+ }
75
+ }
76
+ merchandise {
77
+ ... on ProductVariant {
78
+ id
79
+ availableForSale
80
+ compareAtPrice {
81
+ ...Money
82
+ }
83
+ price {
84
+ ...Money
85
+ }
86
+ requiresShipping
87
+ title
88
+ image {
89
+ id
90
+ url
91
+ altText
92
+ width
93
+ height
94
+ }
95
+ product {
96
+ handle
97
+ title
98
+ id
99
+ vendor
100
+ }
101
+ selectedOptions {
102
+ name
103
+ value
104
+ }
105
+ }
106
+ }
107
+ }
108
+ fragment CartApiQuery on Cart {
109
+ updatedAt
110
+ id
111
+ appliedGiftCards {
112
+ id
113
+ lastCharacters
114
+ amountUsed {
115
+ ...Money
116
+ }
117
+ }
118
+ checkoutUrl
119
+ totalQuantity
120
+ buyerIdentity {
121
+ countryCode
122
+ customer {
123
+ id
124
+ email
125
+ firstName
126
+ lastName
127
+ displayName
128
+ }
129
+ email
130
+ phone
131
+ }
132
+ lines(first: $numCartLines) {
133
+ nodes {
134
+ ...CartLine
135
+ }
136
+ nodes {
137
+ ...CartLineComponent
138
+ }
139
+ }
140
+ cost {
141
+ subtotalAmount {
142
+ ...Money
143
+ }
144
+ totalAmount {
145
+ ...Money
146
+ }
147
+ totalDutyAmount {
148
+ ...Money
149
+ }
150
+ totalTaxAmount {
151
+ ...Money
152
+ }
153
+ }
154
+ note
155
+ attributes {
156
+ key
157
+ value
158
+ }
159
+ discountCodes {
160
+ code
161
+ applicable
162
+ }
163
+ }
164
+ ` as const;
165
+
166
+ const MENU_FRAGMENT = `#graphql
167
+ fragment MenuItem on MenuItem {
168
+ id
169
+ resourceId
170
+ tags
171
+ title
172
+ type
173
+ url
174
+ }
175
+ fragment ChildMenuItem on MenuItem {
176
+ ...MenuItem
177
+ }
178
+ fragment ParentMenuItem on MenuItem {
179
+ ...MenuItem
180
+ items {
181
+ ...ChildMenuItem
182
+ }
183
+ }
184
+ fragment Menu on Menu {
185
+ id
186
+ items {
187
+ ...ParentMenuItem
188
+ }
189
+ }
190
+ ` as const;
191
+
192
+ export const HEADER_QUERY = `#graphql
193
+ fragment Shop on Shop {
194
+ id
195
+ name
196
+ description
197
+ primaryDomain {
198
+ url
199
+ }
200
+ brand {
201
+ logo {
202
+ image {
203
+ url
204
+ }
205
+ }
206
+ }
207
+ }
208
+ query Header(
209
+ $country: CountryCode
210
+ $headerMenuHandle: String!
211
+ $language: LanguageCode
212
+ ) @inContext(language: $language, country: $country) {
213
+ shop {
214
+ ...Shop
215
+ }
216
+ menu(handle: $headerMenuHandle) {
217
+ ...Menu
218
+ }
219
+ }
220
+ ${MENU_FRAGMENT}
221
+ ` as const;
222
+
223
+ export const FOOTER_QUERY = `#graphql
224
+ query Footer(
225
+ $country: CountryCode
226
+ $footerMenuHandle: String!
227
+ $language: LanguageCode
228
+ ) @inContext(language: $language, country: $country) {
229
+ menu(handle: $footerMenuHandle) {
230
+ ...Menu
231
+ }
232
+ }
233
+ ${MENU_FRAGMENT}
234
+ ` as const;