+
+
{post.title}
-
- {blogArticles[0].tags.map((tag, key) => (
+
+ {post.tags.map((tag, key) => (
{
- 5 min read
+ {post.readingTime || '5'} min read
diff --git a/packages/docs/src/routes/(blog)/blog/components/featured-article.tsx b/packages/docs/src/routes/(blog)/blog/components/featured-article.tsx
index ce511e7a18b..bb2d2833bca 100644
--- a/packages/docs/src/routes/(blog)/blog/components/featured-article.tsx
+++ b/packages/docs/src/routes/(blog)/blog/components/featured-article.tsx
@@ -7,24 +7,32 @@ export const FeaturedArticle = component$(() => {
return (
-
+
-
+
{blogArticles[0].title}
-
+
{blogArticles[0].tags.map((tag, key) => (
{tag}
@@ -33,7 +41,7 @@ export const FeaturedArticle = component$(() => {
- 5 min read
+ {blogArticles[0].readingTime || '5'} min read
diff --git a/packages/docs/src/routes/(blog)/blog/components/mdx/article-block.tsx b/packages/docs/src/routes/(blog)/blog/components/mdx/article-block.tsx
new file mode 100644
index 00000000000..c743a808835
--- /dev/null
+++ b/packages/docs/src/routes/(blog)/blog/components/mdx/article-block.tsx
@@ -0,0 +1,22 @@
+import { component$, Slot } from '@builder.io/qwik';
+import { ArticleHero } from './article-hero';
+import { useDocumentHead, useLocation } from '@builder.io/qwik-city';
+import { authors, blogArticles } from '~/routes/(blog)/data';
+
+type Props = { authorLink: string };
+
+export const ArticleBlock = component$(({ authorLink }) => {
+ const location = useLocation();
+ const { frontmatter } = useDocumentHead();
+ const article = blogArticles.find(({ path }) => path === location.url.pathname);
+ const author = authors[frontmatter.authorName];
+
+ return (
+
+
+
+
+
+
+ );
+});
diff --git a/packages/docs/src/routes/(blog)/blog/components/mdx/article-block/article-block.tsx b/packages/docs/src/routes/(blog)/blog/components/mdx/article-block/article-block.tsx
deleted file mode 100644
index eccd2381656..00000000000
--- a/packages/docs/src/routes/(blog)/blog/components/mdx/article-block/article-block.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { component$, Slot } from '@builder.io/qwik';
-import { ArticleHero } from '../article-hero/article-hero';
-
-type Props = { imageSrc: string; authorLink: string };
-
-export const ArticleBlock = component$(({ imageSrc, authorLink }) => {
- return (
-
-
-
-
-
-
- );
-});
diff --git a/packages/docs/src/routes/(blog)/blog/components/mdx/article-hero/article-hero.tsx b/packages/docs/src/routes/(blog)/blog/components/mdx/article-hero.tsx
similarity index 87%
rename from packages/docs/src/routes/(blog)/blog/components/mdx/article-hero/article-hero.tsx
rename to packages/docs/src/routes/(blog)/blog/components/mdx/article-hero.tsx
index b854b861918..7b47ff88946 100644
--- a/packages/docs/src/routes/(blog)/blog/components/mdx/article-hero/article-hero.tsx
+++ b/packages/docs/src/routes/(blog)/blog/components/mdx/article-hero.tsx
@@ -2,9 +2,9 @@ import { component$ } from '@builder.io/qwik';
import { useDocumentHead } from '@builder.io/qwik-city';
import { Image } from 'qwik-image';
-type Props = { imageSrc: string; authorLink: string };
+type Props = { image: string; authorLink: string };
-export const ArticleHero = component$(({ imageSrc, authorLink }) => {
+export const ArticleHero = component$(({ image, authorLink }) => {
const { title, frontmatter } = useDocumentHead();
if (!frontmatter.authorName || !frontmatter.tags || !frontmatter.date) {
@@ -60,8 +60,8 @@ export const ArticleHero = component$(({ imageSrc, authorLink }) => {
-
-
+
+
>
);
diff --git a/packages/docs/src/routes/(blog)/blog/components/mdx/discord-link.tsx b/packages/docs/src/routes/(blog)/blog/components/mdx/discord-link.tsx
new file mode 100644
index 00000000000..a1aa0e405f8
--- /dev/null
+++ b/packages/docs/src/routes/(blog)/blog/components/mdx/discord-link.tsx
@@ -0,0 +1,9 @@
+import { component$ } from '@builder.io/qwik';
+
+type Props = { text?: string };
+
+export const DiscordLink = component$(({ text = 'Discord server' }) => (
+
+ {text}
+
+));
diff --git a/packages/docs/src/routes/(blog)/blog/components/newsletter.tsx b/packages/docs/src/routes/(blog)/blog/components/newsletter.tsx
deleted file mode 100644
index 19d3d79c69e..00000000000
--- a/packages/docs/src/routes/(blog)/blog/components/newsletter.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import { component$ } from '@builder.io/qwik';
-import { SendIcon } from '../icons/send-icon';
-
-export const Newsletter = component$(() => {
- return (
-
-
- Stay Updated
-
- Get the latest articles and insights delivered straight to your inbox.
-
-
-
-
-
- );
-});
diff --git a/packages/docs/src/routes/(blog)/blog/index.tsx b/packages/docs/src/routes/(blog)/blog/index.tsx
index 2e0741e333b..1fc354d9ef4 100644
--- a/packages/docs/src/routes/(blog)/blog/index.tsx
+++ b/packages/docs/src/routes/(blog)/blog/index.tsx
@@ -2,7 +2,6 @@ import { component$, useStyles$ } from '@builder.io/qwik';
import type { DocumentHead } from '@builder.io/qwik-city';
import { FeaturedArticle } from './components/featured-article';
import { ArticlesGrid } from './components/articles-grid';
-import { Newsletter } from './components/newsletter';
export default component$(() => {
useStyles$(`
@@ -45,9 +44,6 @@ export default component$(() => {
Latest Articles
-
-
-
);
});
diff --git a/packages/docs/src/routes/(blog)/data.ts b/packages/docs/src/routes/(blog)/data.ts
index 3a82809eec5..e18d35929c7 100644
--- a/packages/docs/src/routes/(blog)/data.ts
+++ b/packages/docs/src/routes/(blog)/data.ts
@@ -1,31 +1,150 @@
+export const authors: Record = {
+ 'The Qwik Team': { socialLink: 'https://bsky.app/profile/qwik.dev' },
+ 'Jack Shelton': { socialLink: 'https://twitter.com/TheJackShelton' },
+ 'Vishwas Gopinath': { socialLink: 'https://twitter.com/CodevolutionWeb' },
+ 'Manu Mtz.-Almeida': { socialLink: 'https://twitter.com/manucorporat' },
+ 'Steve Sewell': { socialLink: 'https://twitter.com/steve8708' },
+ 'Yoav Ganbar': { socialLink: 'https://twitter.com/HamatoYogi' },
+ 'Miško Hevery': { socialLink: 'https://twitter.com/mhevery' },
+};
+
type BlogArticle = {
title: string;
image: string;
- featuredImage: string;
path: string;
tags: string[];
+ featuredTitlePosition?: 'top' | 'bottom' | 'none';
+ readingTime: number;
};
export const blogArticles: BlogArticle[] = [
{
- title: 'Example',
- image: 'https://placehold.co/400x200',
- featuredImage: 'https://placehold.co/1200x400',
- path: '/blog/qwik-next-leap',
- tags: ['Web development'],
+ title: 'Moving Forward Together',
+ image:
+ 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F78b0d6ebdc154e2db77876ec00aef6f7',
+ path: '/blog/qwik-next-leap/',
+ tags: ['Web Development'],
+ featuredTitlePosition: 'top',
+ readingTime: 3,
+ },
+ {
+ title: 'Towards Qwik 2.0: Lighter, Faster, Better',
+ image:
+ 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F9dd98bcf8fee4b42a718449c5151d53d',
+ path: '/blog/qwik-2-coming-soon/',
+ tags: ['Qwik'],
+ readingTime: 9,
+ },
+ {
+ title: 'Astro + Qwik: Houston, we have Resumability!',
+ image:
+ 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F2418eac0b25046b197bf7b8bf5dfd637',
+ path: '/blog/astro-qwik/',
+ tags: ['Qwik'],
+ readingTime: 4,
+ },
+ {
+ title: 'Qwik City Routing: A Visual Guide',
+ image:
+ 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F4f52dab5f87142a38002269540e69cef',
+ path: '/blog/qwik-city-routing/',
+ tags: ['Web Development'],
+ readingTime: 11,
+ },
+ {
+ title: 'Qwik 1.2: Performance in Autopilot',
+ image:
+ 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F447d6d0349d4442496c3d7e246ce3d24',
+ path: '/blog/qwik-1-2-performance-autopilot/',
+ tags: ['Web Development'],
+ readingTime: 10,
+ },
+ {
+ title: "Boost Your Site Perf with Qwik's useVisibleTask$ Hook",
+ image:
+ 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F5d90a118ceac4678a9e0576e61a955a9',
+ path: '/blog/qwik-tasks/',
+ tags: ['Web Development'],
+ readingTime: 4,
+ },
+ {
+ title: 'Qwik Reaches v1.0',
+ image:
+ 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2Fca46e4da83b7429ea159e2a42a197288',
+ path: '/blog/qwik-v1/',
+ tags: ['Qwik'],
+ readingTime: 5,
+ },
+ {
+ title: 'Type Safe Forms in Qwik with Modular Forms',
+ image:
+ 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F7abec2f848764aa99fead32861505344',
+ path: '/blog/type-safe-forms-in-qwik/',
+ tags: ['Web Development'],
+ readingTime: 8,
+ },
+ {
+ title: 'Qwik Reaches RC Milestone',
+ image:
+ 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F043bec968cb7465fac152147b9e5bd57',
+ path: '/blog/qwik-rc-milestone/',
+ tags: ['Qwik'],
+ readingTime: 2,
+ },
+ {
+ title: 'Building Framer Motion Animations with Qwik',
+ image:
+ 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2Fbf1420524b2241619cc68efbba7b7c13',
+ path: '/blog/framer-motion-qwik/',
+ tags: ['Web Development'],
+ readingTime: 7,
+ },
+ {
+ title: 'Code Extraction: The Silent Web Revolution',
+ image:
+ 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F0a8170ff2659474883ee032a0129cddd',
+ path: '/blog/module-extraction-the-silent-web-revolution/',
+ tags: ['Qwik'],
+ readingTime: 9,
+ },
+ {
+ title: 'Introducing Qwik City Server Functions',
+ image:
+ 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F48d8fd6d22ae4c3b9c1ec4817ce4046d',
+ path: '/blog/qwik-city-server-functions/',
+ tags: ['Qwik'],
+ readingTime: 6,
+ },
+ {
+ title: 'Resumable React: How to Use React Inside Qwik',
+ image:
+ 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F9071a7def0b240e5b5ca6aab756e81b8',
+ path: '/blog/resumable-react-how-to-use-react-inside-qwik/',
+ tags: ['Web Development'],
+ readingTime: 8,
+ },
+ {
+ title: 'The Qase for Qwik: Love At First TTI',
+ image:
+ 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F69e3a278f34d4bfc9deb783dc705cd9a',
+ path: '/blog/the-qase-for-qwik-love-at-first-tti/',
+ tags: ['Qwik'],
+ readingTime: 18,
},
{
- title: 'Example',
- image: 'https://placehold.co/400x200',
- featuredImage: 'https://placehold.co/1200x400',
- path: '/blog/qwik-next-leap',
- tags: ['Web development'],
+ title: 'Qwik and Qwik City have reached beta! 🎉',
+ image:
+ 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F5f8db18f68c74f6f9919f3877b6246b4',
+ path: '/blog/qwik-and-qwik-city-have-reached-beta/',
+ tags: ['Web Development'],
+ readingTime: 3,
},
{
- title: 'Example',
- image: 'https://placehold.co/400x200',
- featuredImage: 'https://placehold.co/1200x400',
- path: '/blog/qwik-next-leap',
- tags: ['Web development'],
+ title: 'Introducing Qwik starters - get up and running with Qwik now',
+ image:
+ 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F85209017e99f4753a56614f6712817c5',
+ path: '/blog/introducing-qwik-starters/',
+ tags: ['Qwik'],
+ readingTime: 1,
},
];
diff --git a/packages/docs/src/routes/(blog)/layout.tsx b/packages/docs/src/routes/(blog)/layout.tsx
index 92306a193a7..4279f0f55df 100644
--- a/packages/docs/src/routes/(blog)/layout.tsx
+++ b/packages/docs/src/routes/(blog)/layout.tsx
@@ -11,6 +11,14 @@ export const onRequest: RequestHandler = async (request) => {
export default component$(() => {
useStyles$(docsStyles);
+ useStyles$(`
+ .docs article p {
+ font-size: 18px;
+ }
+
+ #qwik-image-warning-container {
+ display: none;
+ }`);
useImageProvider({ imageTransformer$: $(({ src }: ImageTransformerProps): string => src) });
@@ -22,7 +30,7 @@ export default component$(() => {
-
+
diff --git a/packages/docs/src/routes/(shop)/layout.tsx b/packages/docs/src/routes/(shop)/layout.tsx
deleted file mode 100644
index dae78451dc1..00000000000
--- a/packages/docs/src/routes/(shop)/layout.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-import { $, component$, Slot, useContextProvider, useStore, useTask$ } from '@builder.io/qwik';
-import { Header } from '../../components/header/header';
-import { Footer } from '../../components/footer/footer';
-import { routeLoader$, type RequestHandler } from '@builder.io/qwik-city';
-import {
- COOKIE_CART_ID_KEY,
- fetchFromShopify,
- mapProducts,
- setCookie,
- SHOP_CONTEXT,
-} from './utils';
-import { checkoutQuery, productsQuery } from './query';
-import { checkoutCreateMutation } from './mutation';
-import { useImageProvider, type ImageTransformerProps } from 'qwik-image';
-import type { CheckoutQuery, ProductsQuery, CheckoutCreateMutation, ShopApp } from './types';
-
-export const onRequest: RequestHandler = async (request) => {
- request.cacheControl(600);
-};
-
-export const useProductsLoader = routeLoader$(async () => {
- const response = await fetchFromShopify(productsQuery());
- const {
- data: { node },
- }: ProductsQuery = await response.json();
- return mapProducts(node.products.edges);
-});
-
-export const useCartLoader = routeLoader$(async ({ cookie }) => {
- const cartId = cookie.get(COOKIE_CART_ID_KEY)?.value;
- const body = cartId ? checkoutQuery(cartId) : checkoutCreateMutation();
- const response = await fetchFromShopify(body);
- const { data }: CheckoutQuery | CheckoutCreateMutation = await response.json();
-
- const cart = 'node' in data ? data.node : data.checkoutCreate.checkout;
-
- if (!cartId && cart.id) {
- setCookie(cookie, cart.id);
- }
- return cart;
-});
-
-export default component$(() => {
- const cart = useCartLoader();
- useImageProvider({ imageTransformer$: $(({ src }: ImageTransformerProps): string => src) });
- const appShop = useStore({ products: useProductsLoader().value });
- useContextProvider(SHOP_CONTEXT, appShop);
-
- useTask$(() => {
- appShop.cart = cart.value;
- });
-
- return (
- <>
-
-
-
-
-
-
-
- >
- );
-});
diff --git a/packages/docs/src/routes/(shop)/mutation.ts b/packages/docs/src/routes/(shop)/mutation.ts
deleted file mode 100644
index 39e6e2f1955..00000000000
--- a/packages/docs/src/routes/(shop)/mutation.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-export const checkoutCreateMutation = () => ({
- variables: { input: {} },
- query: `
- ${checkoutFragment}
- mutation ($input: CheckoutCreateInput!) {
- checkoutCreate(input: $input) {
- checkout {
- ...CheckoutFragment
- }
- }
- }
-`,
-});
-
-export const modifyLineItemMutation = (
- checkoutId: string,
- variantId: string,
- quantity: number
-) => ({
- variables: { checkoutId, lineItems: [{ variantId, quantity }] },
- query: `
- ${checkoutFragment}
- mutation ($checkoutId: ID!, $lineItems: [CheckoutLineItemInput!]!) {
- checkoutLineItemsAdd(checkoutId: $checkoutId, lineItems: $lineItems) {
- checkout {
- ...CheckoutFragment
- }
- }
- }
-`,
-});
-
-export const removeLineItemMutation = (checkoutId: string, lineItemIds: string[]) => ({
- variables: { checkoutId, lineItemIds },
- query: `
- ${checkoutFragment}
- mutation ($checkoutId: ID!, $lineItemIds: [ID!]!) {
- checkoutLineItemsRemove(checkoutId: $checkoutId, lineItemIds: $lineItemIds) {
- checkout {
- ...CheckoutFragment
- }
- }
- }
-`,
-});
-
-const variantFragment = `
- fragment VariantFragment on ProductVariant {
- id
- title
- price {
- amount
- currencyCode
- }
- available: availableForSale
- image {
- url
- altText
- }
- }
-`;
-
-const variantWithProductFragment = `
- ${variantFragment}
- fragment VariantWithProductFragment on ProductVariant {
- ...VariantFragment
- }
-`;
-
-export const checkoutFragment = `
- ${variantWithProductFragment}
- fragment CheckoutFragment on Checkout {
- id
- webUrl
- totalPrice {
- amount
- currencyCode
- }
- lineItems(first: 250) {
- edges {
- node {
- id
- title
- quantity
- variant {
- ...VariantWithProductFragment
- }
- }
- }
- }
- }
-`;
diff --git a/packages/docs/src/routes/(shop)/query.ts b/packages/docs/src/routes/(shop)/query.ts
deleted file mode 100644
index 3e7a438d9e1..00000000000
--- a/packages/docs/src/routes/(shop)/query.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-import { checkoutFragment } from './mutation';
-
-export const productsQuery = (
- id = import.meta.env.PUBLIC_SHOPIFY_COLLECTION_ID,
- productsFirst = 100
-) => ({
- variables: { id, productsFirst },
- query: `
- fragment VariantFragment on ProductVariant {
- id
- available: availableForSale
- title
- price {
- amount
- currencyCode
- }
- }
- fragment ProductFragment on Product {
- id
- title
- availableForSale
- descriptionHtml
- images(first: 250) {
- edges {
- node {
- url
- altText
- }
- }
- }
- variants(first: 250) {
- edges {
- node {
- ...VariantFragment
- }
- }
- }
- }
- query ($id: ID!, $productsFirst: Int!) {
- node(id: $id) {
- ... on Collection {
- products(first: $productsFirst) {
- edges {
- node {
- ...ProductFragment
- }
- }
- }
- }
- }
- }
-`,
-});
-
-export const checkoutQuery = (id: string) => ({
- variables: { id },
- query: `
- ${checkoutFragment}
- query ($id: ID!) {
- node(id: $id) {
- ...CheckoutFragment
- }
- }
-`,
-});
diff --git a/packages/docs/src/routes/(shop)/shop.css b/packages/docs/src/routes/(shop)/shop.css
deleted file mode 100644
index 6212c773f40..00000000000
--- a/packages/docs/src/routes/(shop)/shop.css
+++ /dev/null
@@ -1,63 +0,0 @@
-.shop .purple-gradient {
- position: fixed;
- pointer-events: none;
- width: 1400px;
- height: 800px;
- top: 100px;
- right: -400px;
- background: radial-gradient(
- 57.58% 57.58% at 48.79% 42.42%,
- rgba(24, 180, 244, 0.5) 0%,
- rgba(46, 55, 114, 0) 63.22%
- );
- transform: rotate(5deg);
-}
-
-.shop .blue-gradient {
- position: fixed;
- pointer-events: none;
- width: 1400px;
- height: 1200px;
- top: 600px;
- left: -200px;
- background: radial-gradient(
- 50% 50% at 50% 50%,
- rgba(172, 127, 244, 0.5) 0%,
- rgba(21, 25, 52, 0) 100%
- );
- transform: rotate(-5deg);
-}
-
-.shop .product {
- @apply relative flex w-full max-w-xs flex-col overflow-hidden rounded-lg border border-slate-600 shadow-md;
- background-color: var(--bg-color);
- color: var(--text-color);
-}
-
-.shop .product .title {
- @apply mt-4 px-5 text-xl tracking-tight text-center truncate;
-}
-
-.shop .product .info {
- @apply mx-5 mt-4 relative flex h-60 rounded-xl;
-}
-
-.shop .product .select {
- @apply mr-4 border border-gray-300 rounded-lg focus:ring-blue-500 focus:border-blue-500 w-full p-2.5 bg-white text-black text-xs;
-}
-
-.shop .product .button_primary,
-.shop .cart .button_primary {
- @apply flex items-center justify-center rounded-md px-5 py-2.5 text-center text-sm font-medium bg-slate-900 focus:outline-none focus:ring-4 focus:ring-blue-300 w-full h-[40px];
- background-color: var(--text-color);
- color: var(--bg-color);
-}
-
-.shop-cart {
- @apply fixed right-6 z-[100] pt-[55px];
-}
-
-.header-open .shop-cart,
-.DocSearch--active .shop-cart {
- z-index: 99;
-}
diff --git a/packages/docs/src/routes/(shop)/shop/index.tsx b/packages/docs/src/routes/(shop)/shop/index.tsx
deleted file mode 100644
index 86aa13f5385..00000000000
--- a/packages/docs/src/routes/(shop)/shop/index.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import { component$, useContext, useStyles$ } from '@builder.io/qwik';
-import styles from '../shop.css?inline';
-import { SHOP_CONTEXT } from '../utils';
-import type { DocumentHead } from '@builder.io/qwik-city';
-import { ShopHeader } from './shop-header';
-import { ShopProduct } from './shop-product';
-
-export default component$(() => {
- useStyles$(styles);
- const appShop = useContext(SHOP_CONTEXT);
-
- return (
-
-
-
-
-
-
- {(appShop.products || []).map((product, key) => (
-
- ))}
-
-
-
- );
-});
-
-export const head: DocumentHead = {
- title: 'Qwik Shop',
-};
diff --git a/packages/docs/src/routes/(shop)/shop/shop-cart-rows.tsx b/packages/docs/src/routes/(shop)/shop/shop-cart-rows.tsx
deleted file mode 100644
index cd3ff98fa52..00000000000
--- a/packages/docs/src/routes/(shop)/shop/shop-cart-rows.tsx
+++ /dev/null
@@ -1,147 +0,0 @@
-import { component$, useContext, useSignal, $ } from '@builder.io/qwik';
-import { SHOP_CONTEXT, fetchFromShopify, formatPrice } from '../utils';
-import { Image } from 'qwik-image';
-import { modifyLineItemMutation, removeLineItemMutation } from '../mutation';
-
-export const ShopCartRows = component$(() => {
- const loadingSignal = useSignal(false);
- const appShop = useContext(SHOP_CONTEXT);
-
- const onModifyLineItemMutation = $(async (variantId: string, quantity: number) => {
- loadingSignal.value = true;
- const response = await fetchFromShopify(
- modifyLineItemMutation(appShop.cart?.id || '', variantId, quantity)
- );
- const {
- data: { checkoutLineItemsAdd },
- } = await response.json();
- appShop.cart = checkoutLineItemsAdd.checkout;
- loadingSignal.value = false;
- });
-
- const onRemoveLineItemMutation = $(async (lineItemId: string) => {
- loadingSignal.value = true;
- const response = await fetchFromShopify(
- removeLineItemMutation(appShop.cart?.id || '', [lineItemId])
- );
- const {
- data: { checkoutLineItemsRemove },
- } = await response.json();
- appShop.cart = checkoutLineItemsRemove.checkout;
- loadingSignal.value = false;
- });
-
- return (
-
-
- {appShop.cart &&
- appShop.cart.lineItems.edges.map(({ node: lineItem }) => {
- return (
- -
-
-
-
-
-
-
-
-
- {lineItem.title}
- {lineItem.variant.title}
-
-
- {formatPrice(
- parseFloat(lineItem.variant.price.amount) * lineItem.quantity,
- lineItem.variant.price.currencyCode
- )}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
- })}
-
-
- );
-});
diff --git a/packages/docs/src/routes/(shop)/shop/shop-cart.tsx b/packages/docs/src/routes/(shop)/shop/shop-cart.tsx
deleted file mode 100644
index d7fdf839eda..00000000000
--- a/packages/docs/src/routes/(shop)/shop/shop-cart.tsx
+++ /dev/null
@@ -1,132 +0,0 @@
-import { $, component$, useComputed$, useContext, useSignal } from '@builder.io/qwik';
-import { COOKIE_CART_ID_KEY, SHOP_CONTEXT, deleteCookie, formatPrice } from '../utils';
-import { ShopCartRows } from './shop-cart-rows';
-
-export const ShopCart = component$(() => {
- const showCartSignal = useSignal(false);
- const appShop = useContext(SHOP_CONTEXT);
- const isEmptySignal = useComputed$(
- () => appShop.cart?.lineItems?.edges?.length || 0 > 0 || false
- );
- const totalQuantitySignal = useComputed$(() =>
- appShop.cart
- ? appShop.cart.lineItems.edges.reduce(
- (quantity: number, { node }) => quantity + node.quantity,
- 0
- )
- : 0
- );
- return (
- <>
- {appShop.cart && (
-
-
- {showCartSignal.value && (
-
-
-
-
-
-
-
-
- Shopping cart
-
-
-
-
-
- {isEmptySignal.value ? (
-
- ) : (
-
- 🛒 Your cart is empty
-
- )}
-
-
- {isEmptySignal.value && (
-
-
- Subtotal
-
- {formatPrice(
- parseFloat(appShop.cart.totalPrice.amount),
- appShop.cart.totalPrice.currencyCode
- )}
-
-
- 🚛 Shipping will be calculated at checkout.
- {
- deleteCookie(COOKIE_CART_ID_KEY);
- })}
- >
- Checkout
-
-
- )}
-
-
-
-
-
- )}
-
- )}
- >
- );
-});
diff --git a/packages/docs/src/routes/(shop)/shop/shop-header.tsx b/packages/docs/src/routes/(shop)/shop/shop-header.tsx
deleted file mode 100644
index 4ce5f51964f..00000000000
--- a/packages/docs/src/routes/(shop)/shop/shop-header.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import { component$ } from '@builder.io/qwik';
-import { ShopCart } from './shop-cart';
-import { ShopIcon } from './shop-icon';
-
-export const ShopHeader = component$(() => {
- return (
-
-
-
-
-
-
- );
-});
diff --git a/packages/docs/src/routes/(shop)/shop/shop-icon.tsx b/packages/docs/src/routes/(shop)/shop/shop-icon.tsx
deleted file mode 100644
index 488864be1bb..00000000000
--- a/packages/docs/src/routes/(shop)/shop/shop-icon.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import { component$ } from '@builder.io/qwik';
-
-export const ShopIcon = component$(() => {
- return (
-
- );
-});
diff --git a/packages/docs/src/routes/(shop)/shop/shop-product.tsx b/packages/docs/src/routes/(shop)/shop/shop-product.tsx
deleted file mode 100644
index 41045e98edd..00000000000
--- a/packages/docs/src/routes/(shop)/shop/shop-product.tsx
+++ /dev/null
@@ -1,142 +0,0 @@
-import { component$, useComputed$, useContext, useSignal } from '@builder.io/qwik';
-import { modifyLineItemMutation } from '../mutation';
-import { SHOP_CONTEXT, fetchFromShopify, formatPrice } from '../utils';
-import type { UIProduct } from '../types';
-import { Image } from '@unpic/qwik';
-
-type Props = {
- product: UIProduct;
-};
-
-export const ShopProduct = component$(({ product }) => {
- const appShop = useContext(SHOP_CONTEXT);
- const loadingSignal = useSignal(false);
- const showProductSignal = useSignal(true);
- const selectedVariantId = useSignal(product.variants.find((v) => v.available)?.id || '');
- const selectedVariantSignal = useComputed$(() =>
- product.variants.find((v) => v.id === selectedVariantId.value)
- );
- return (
-
- {product.title}
-
- {showProductSignal.value ? (
-
- ) : (
-
- )}
-
-
- {
- showProductSignal.value = !showProductSignal.value;
- }}
- >
- {showProductSignal.value ? 'Description' : 'Image'}
-
-
-
-
- {product.variants.length > 1 ? (
-
- ) : (
-
- )}
-
- {selectedVariantSignal.value
- ? formatPrice(
- parseFloat(selectedVariantSignal.value.price.amount),
- selectedVariantSignal.value.price.currencyCode
- )
- : '--'}
-
-
-
-
-
-
-
- );
-});
diff --git a/packages/docs/src/routes/(shop)/types.d.ts b/packages/docs/src/routes/(shop)/types.d.ts
deleted file mode 100644
index 1f3123fa011..00000000000
--- a/packages/docs/src/routes/(shop)/types.d.ts
+++ /dev/null
@@ -1,80 +0,0 @@
-export type ShopApp = { products?: UIProduct[]; cart?: Checkout };
-
-export type CheckoutLineItemsAddMutation = {
- data: { checkoutLineItemsAdd: { checkout: Checkout } };
-};
-
-export type CheckoutLineItemsRemoveMutation = {
- data: { checkoutLineItemsRemove: { checkout: Checkout } };
-};
-
-export type CheckoutCreateMutation = {
- data: { checkoutCreate: { checkout: Checkout } };
-};
-
-export type CheckoutQuery = {
- data: { node: Checkout };
-};
-
-export type Checkout = {
- id: string;
- webUrl: string;
- totalPrice: TotalPrice;
- lineItems: LineItems;
-};
-
-export type TotalPrice = {
- amount: string;
- currencyCode: string;
-};
-
-export type LineItems = {
- edges: { node: LineItemsNode }[];
-};
-
-export type LineItemsNode = {
- id: string;
- title: string;
- quantity: number;
- variant: Variant;
-};
-
-export type Variant = {
- id: string;
- title: string;
- price: Price;
- available: boolean;
- image: Image;
-};
-
-export type Price = {
- amount: string;
- currencyCode: string;
-};
-
-export type Image = {
- url: string;
- altText: string;
-};
-
-export type ProductsQuery = {
- data: { node: { products: { edges: { node: Product }[] } } };
-};
-
-export type Product = {
- id: string;
- title: string;
- availableForSale: boolean;
- descriptionHtml: string;
- images: { edges: { node: Image }[] };
- variants: { edges: { node: Variant }[] };
-};
-
-export type UIProduct = {
- id: string;
- title: string;
- availableForSale: boolean;
- descriptionHtml: string;
- image: Image;
- variants: Variant[];
-};
diff --git a/packages/docs/src/routes/(shop)/utils.ts b/packages/docs/src/routes/(shop)/utils.ts
deleted file mode 100644
index 6339b5538db..00000000000
--- a/packages/docs/src/routes/(shop)/utils.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import { createContextId } from '@builder.io/qwik';
-import type { Product, ShopApp } from './types';
-import type { Cookie } from '@builder.io/qwik-city';
-import type { CookieOptions } from 'express';
-
-export const COOKIE_CART_ID_KEY = 'cartid';
-
-export const SHOP_CONTEXT = createContextId('shop_context');
-
-export const fetchFromShopify = async (body: unknown) =>
- await fetch(import.meta.env.PUBLIC_SHOPIFY_URL, {
- method: 'POST',
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- 'X-Shopify-Storefront-Access-Token': import.meta.env.PUBLIC_SHOPIFY_TOKEN,
- },
- body: JSON.stringify(body),
- });
-
-export const mapProducts = (data: { node: Product }[]) =>
- data
- .filter(({ node }) => node.availableForSale)
- .map(({ node }) => ({
- id: node.id,
- title: node.title,
- availableForSale: node.availableForSale,
- descriptionHtml: node.descriptionHtml,
- image: node.images.edges[0].node,
- variants: node.variants.edges.map(({ node }) => node),
- }));
-
-export const setCookie = (cookie: Cookie, value: string) => {
- const maxAge = 60 * 60 * 24 * 30;
- const options: CookieOptions = { maxAge, sameSite: 'strict', path: '/', secure: true };
- cookie.set(COOKIE_CART_ID_KEY, value, options);
-};
-
-export const deleteCookie = (name: string) => {
- document.cookie = `${name}=; expires=-1; Secure; SameSite=Strict; path=/`;
-};
-
-export function formatPrice(value = 0, currency: string) {
- return new Intl.NumberFormat('en-US', {
- style: 'currency',
- currency,
- }).format(value);
-}
diff --git a/packages/docs/src/routes/docs/(qwikcity)/advanced/complex-forms/index.mdx b/packages/docs/src/routes/docs/(qwikcity)/advanced/complex-forms/index.mdx
index 5ac6d8940bf..f71a730f9a1 100644
--- a/packages/docs/src/routes/docs/(qwikcity)/advanced/complex-forms/index.mdx
+++ b/packages/docs/src/routes/docs/(qwikcity)/advanced/complex-forms/index.mdx
@@ -24,7 +24,7 @@ Nested items can be created by separating the items with `.` (dot) in the name.
### Arrays
-Arrays, either top level or nested are created by specifying the zero-based index in the name. For example `person.pets.0` would be converted to `{ person: { pets: [ 'cat' ] } }`.
+Arrays, either top-level or nested are created by specifying the zero-based index in the name. For example `person.pets.0` would be converted to `{ person: { pets: [ 'cat' ] } }`.
### Example
@@ -52,7 +52,7 @@ The key to creating a complex form is in the naming of the inputs. Below would b
#### Output object
-The after submitting the form the data would be parsed in an object like this:
+After submitting the form the data would be parsed in an object like this:
```json
{
"person": [
diff --git a/packages/docs/src/routes/docs/deployments/bun/index.mdx b/packages/docs/src/routes/docs/deployments/bun/index.mdx
index a2835247ccb..b171e2f331a 100644
--- a/packages/docs/src/routes/docs/deployments/bun/index.mdx
+++ b/packages/docs/src/routes/docs/deployments/bun/index.mdx
@@ -20,15 +20,6 @@ curl -fsSL https://bun.sh/install | bash
For other platforms or if you run into issues with installation, up to date `bun` installation instructions can be found [on the bun website](https://bun.sh/docs/installation).
-If you run into the error `Something went wrong installing the "sharp" module` when using `bun` as a package manager, add the following code to your package.json, then remove the node_modules folder and any lockfiles such as bun.lockb or package-lock.json. Then run `bun install`.
-
-```json
-"trustedDependencies": [
- "sharp"
-]
-```
-This issue is currently being tracked [on the bun repository](https://github.com/oven-sh/bun/issues/3783).
-
To integrate the `bun` adapter, use the `add` command:
- For the [integrated HTTP server](https://bun.sh/docs/api/http):
diff --git a/starters/apps/base/package.json b/starters/apps/base/package.json
index b6cab10066c..3bafa473d56 100644
--- a/starters/apps/base/package.json
+++ b/starters/apps/base/package.json
@@ -30,10 +30,6 @@
"vite": "^4.5.2",
"vite-tsconfig-paths": "^4.2.1"
},
- "trustedDependencies": [
- "sharp"
- ],
- "trustedDependencies-annotation": "Needed for bun to allow running install scripts",
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0",
"npm": ">=10.0.0",
{post.title}
-{blogArticles[0].title}
-Stay Updated
-- Get the latest articles and insights delivered straight to your inbox. -
- - -Latest Articles
-
- {appShop.cart &&
- appShop.cart.lineItems.edges.map(({ node: lineItem }) => {
- return (
-
-
- -- -
- --------{lineItem.title}
-{lineItem.variant.title}
-- {formatPrice( - parseFloat(lineItem.variant.price.amount) * lineItem.quantity, - lineItem.variant.price.currencyCode - )} --- --- - -- -- --
- );
- })}
-
Shopping cart
-Subtotal
-- {formatPrice( - parseFloat(appShop.cart.totalPrice.amount), - appShop.cart.totalPrice.currencyCode - )} -
-🚛 Shipping will be calculated at checkout.
- { - deleteCookie(COOKIE_CART_ID_KEY); - })} - > - Checkout - -