Compare commits
17 Commits
1b8c390ba6
...
master
Author | SHA1 | Date | |
---|---|---|---|
3938ba0d99 | |||
c6c7eaf7fc | |||
46c2932861 | |||
bc11b363c4 | |||
ca45be57fb | |||
ba69990860 | |||
c555f1af07 | |||
5a1d8073b5 | |||
a73a6220f5 | |||
d7845ad4aa | |||
3492009582 | |||
4fafa3a172 | |||
b8697e601f | |||
c53ad08818 | |||
04578e06be | |||
8980fe3986 | |||
21cc79ea7a |
21
.gitea/workflows/deploy.yaml
Normal file
21
.gitea/workflows/deploy.yaml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
on: [push]
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
deployments: write
|
||||||
|
name: Deploy to Cloudflare Pages
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
# Run your project's build step
|
||||||
|
- name: Build
|
||||||
|
run: npm install && npm run build
|
||||||
|
- name: Publish
|
||||||
|
uses: https://github.com/cloudflare/pages-action@f0a1cd58cd66095dee69bfa18fa5efd1dde93bca
|
||||||
|
with:
|
||||||
|
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
|
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
|
projectName: 'rafa-page' # e.g. 'my-project'
|
||||||
|
directory: 'dist' # e.g. 'dist'
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -19,3 +19,4 @@ yarn-error.log*
|
|||||||
|
|
||||||
# Local Netlify folder
|
# Local Netlify folder
|
||||||
.netlify
|
.netlify
|
||||||
|
.astro
|
||||||
|
@ -1,16 +1,20 @@
|
|||||||
|
import { defineConfig } from "astro/config";
|
||||||
import tailwind from "@astrojs/tailwind";
|
import tailwind from "@astrojs/tailwind";
|
||||||
import svelte from "@astrojs/svelte";
|
import svelte from "@astrojs/svelte";
|
||||||
import { defineConfig } from "astro/config";
|
|
||||||
import sitemap from "@astrojs/sitemap";
|
import sitemap from "@astrojs/sitemap";
|
||||||
|
|
||||||
import mdx from "@astrojs/mdx";
|
import mdx from "@astrojs/mdx";
|
||||||
|
import partytown from "@astrojs/partytown";
|
||||||
|
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
site: "https://rafa.page",
|
site: "https://rafa.page/",
|
||||||
integrations: [tailwind({
|
integrations: [tailwind({
|
||||||
config: {
|
config: {
|
||||||
applyBaseStyles: false,
|
applyBaseStyles: false
|
||||||
}
|
}
|
||||||
}), svelte(), sitemap(), mdx()]
|
}), svelte(), sitemap(), mdx(), partytown({
|
||||||
|
config: {
|
||||||
|
forward: ["dataLayer.push"]
|
||||||
|
}
|
||||||
|
})]
|
||||||
});
|
});
|
8
netlify.toml
Normal file
8
netlify.toml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
[dev]
|
||||||
|
framework = "astro"
|
||||||
|
|
||||||
|
[[redirects]]
|
||||||
|
from="/blog/optimizeing-shopify-theme"
|
||||||
|
to="/blog/optimizeing-shopify-theme-1"
|
||||||
|
status=301
|
||||||
|
force = true
|
24
package.json
24
package.json
@ -9,11 +9,23 @@
|
|||||||
"preview": "astro preview"
|
"preview": "astro preview"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@astrojs/mdx": "^0.9.0",
|
"@astrojs/mdx": "^0.17.0",
|
||||||
"@astrojs/sitemap": "^1.0.0",
|
"@astrojs/sitemap": "^1.0.1",
|
||||||
"@astrojs/svelte": "^1.0.0",
|
"@astrojs/svelte": "^2.0.2",
|
||||||
"@astrojs/tailwind": "^1.0.0",
|
"@astrojs/tailwind": "^3.0.1",
|
||||||
"astro": "^1.0.3",
|
"@notionhq/client": "^2.2.0",
|
||||||
"svelte": "^3.49.0"
|
"astro": "^2.0.14",
|
||||||
|
"marked": "^4.1.0",
|
||||||
|
"notion-to-md": "^2.5.5",
|
||||||
|
"postcss": "^8.4.21",
|
||||||
|
"rollup": "^3.17.2",
|
||||||
|
"svelte": "^3.49.0",
|
||||||
|
"tailwindcss": "^3.2.7",
|
||||||
|
"typescript": "^4.9.5",
|
||||||
|
"vite": "^4.1.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@astrojs/partytown": "^1.2.0",
|
||||||
|
"@astrojs/rss": "^2.4.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
4079
pnpm-lock.yaml
generated
4079
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
126
src/content/blog/optimizeing-shopify-theme-1.mdx
Normal file
126
src/content/blog/optimizeing-shopify-theme-1.mdx
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
---
|
||||||
|
layout: ../../layouts/main.astro
|
||||||
|
date: 2022-08-18
|
||||||
|
title: Optimizing performance of an old Shopify Theme (Part 1)
|
||||||
|
description:
|
||||||
|
This blog post discusses tips and recommendations for optimizing and improving the performance of an old Shopify theme. It covers topics such as Web Vitals, server optimization, and code optimization. The author provides an initial analysis and shares the process they follow for optimizing the code. The post concludes with the mention of a Part 2 that provides practical steps for optimizing a Shopify theme.
|
||||||
|
exerpt:
|
||||||
|
Some tips and recommendations for optimizing and boosting performance of an
|
||||||
|
old Shopify theme.
|
||||||
|
image: https://images.unsplash.com/photo-1506818144585-74b29c980d4b?crop=entropy&cs=tinysrgb&fm=jpg&ixid=MnwzNTMzMzl8MHwxfGFsbHx8fHx8fHx8fDE2NjA3OTI2NjA&ixlib=rb-1.2.1&q=80&w=350&ar=16:9&fit=crop
|
||||||
|
---
|
||||||
|
|
||||||
|
# Optimizing an old Shopify Theme (Part 1)
|
||||||
|
|
||||||
|
<img
|
||||||
|
alt="Optimizing an old Shopify Theme"
|
||||||
|
class="cover"
|
||||||
|
src="https://images.unsplash.com/photo-1506818144585-74b29c980d4b?crop=entropy&cs=tinysrgb&fm=jpg&ixid=MnwzNTMzMzl8MHwxfGFsbHx8fHx8fHx8fDE2NjA3OTI2NjA&ixlib=rb-1.2.1&q=80&w=300&ar=5:2&fit=crop"
|
||||||
|
srcset="https://images.unsplash.com/photo-1506818144585-74b29c980d4b?crop=entropy&cs=tinysrgb&fm=jpg&ixid=MnwzNTMzMzl8MHwxfGFsbHx8fHx8fHx8fDE2NjA3OTI2NjA&ixlib=rb-1.2.1&q=80&w=300&ar=5:2&fit=crop 300w,
|
||||||
|
https://images.unsplash.com/photo-1506818144585-74b29c980d4b?crop=entropy&cs=tinysrgb&fm=jpg&ixid=MnwzNTMzMzl8MHwxfGFsbHx8fHx8fHx8fDE2NjA3OTI2NjA&ixlib=rb-1.2.1&q=80&w=500&ar=5:2&fit=crop 500w,
|
||||||
|
https://images.unsplash.com/photo-1506818144585-74b29c980d4b?crop=entropy&cs=tinysrgb&fm=jpg&ixid=MnwzNTMzMzl8MHwxfGFsbHx8fHx8fHx8fDE2NjA3OTI2NjA&ixlib=rb-1.2.1&q=80&w=800&ar=5:2&fit=crop 800w,
|
||||||
|
https://images.unsplash.com/photo-1506818144585-74b29c980d4b?crop=entropy&cs=tinysrgb&fm=jpg&ixid=MnwzNTMzMzl8MHwxfGFsbHx8fHx8fHx8fDE2NjA3OTI2NjA&ixlib=rb-1.2.1&q=80&w=1024&ar=5:2&fit=crop 1024w"
|
||||||
|
sizes="(max-width: 310px) 300px,
|
||||||
|
(max-width: 510px) 500px,
|
||||||
|
(max-width: 810px) 800px,
|
||||||
|
1024px"
|
||||||
|
/>
|
||||||
|
|
||||||
|
## Some tips and recommendations for optimizing and boosting the performance of an old Shopify theme.
|
||||||
|
|
||||||
|
At [Acromático Development](https://acromatico.dev/), we are always helping our clients optimize their Shopify stores, not only the UX and UI but also the performance and speed of the site. Optimizing a Shopify theme is not a simple task; it has been a long learning path that continues to evolve and improve as we test and try new methodologies.
|
||||||
|
|
||||||
|
In this first blog post, I want to share some of the things I've learned during this process. That way, maybe I can help others navigate through some of the challenging parts of successfully optimizing a Shopify theme.
|
||||||
|
|
||||||
|
### Web Vitals and Shopify Themes
|
||||||
|
|
||||||
|
If you are reading this post, it is because you've probably been trying to find
|
||||||
|
ways to optimize your store theme or a client theme. Shopify shows an average
|
||||||
|
score for the theme by running three pages through Google Lightspeed daily.
|
||||||
|
These three pages are the home page, product page, and collection page.
|
||||||
|
|
||||||
|
If you run these pages via pagespeed.web.dev, you'll notice that the score is
|
||||||
|
given by the result of some Google indicators called Web Vitals. The most
|
||||||
|
important Web Vitals are:
|
||||||
|
|
||||||
|
1. **Largest Contentful Paint (LCP):** This is an important, user-centric metric for
|
||||||
|
measuring perceived load speed because it marks the point in the page load
|
||||||
|
timeline when the page's main content has likely loaded. A fast LCP helps
|
||||||
|
reassure the user that the page is useful.
|
||||||
|
|
||||||
|
[Philip Walton. "Largest Contentful Paint" web.dev, Aug 17, 2022.](https://web.dev/i18n/en/lcp/)
|
||||||
|
|
||||||
|
2. **Cumulative Layout Shift (CLS):** This is a measure of the largest burst of
|
||||||
|
layout shift scores for every unexpected layout shift that occurs during the
|
||||||
|
entire lifespan of a page.
|
||||||
|
|
||||||
|
[Philip Walton. "Cumulative Layout Shift" web.dev, Aug 17, 2022.](https://web.dev/i18n/en/cls/)
|
||||||
|
|
||||||
|
3. **First Contentful Paint (FCP):** This is an important, user-centric metric for
|
||||||
|
measuring perceived load speed because it marks the first point in the page
|
||||||
|
load timeline where the user can see anything on the screen. A fast FCP helps
|
||||||
|
reassure the user that something is happening.
|
||||||
|
|
||||||
|
[Philip Walton. "First Contentful Paint" web.dev, Aug 17, 2022.](https://web.dev/i18n/en/fcp/)
|
||||||
|
|
||||||
|
4. **Time to First Byte (TTFB):** This is a foundational metric for measuring
|
||||||
|
connection setup time and web server responsiveness in both the lab and the
|
||||||
|
field. It helps identify when a web server is too slow to respond to
|
||||||
|
requests. In the case of navigation requests—that is, requests for an HTML
|
||||||
|
document—it precedes every other meaningful loading performance metric.
|
||||||
|
|
||||||
|
[Jeremy Wagner. "Time to First Byte" web.dev, Jul 26, 2022.](https://web.dev/ttfb/)
|
||||||
|
|
||||||
|
|
||||||
|
Some of these metrics can be optimized by making changes in the theme code, while some
|
||||||
|
others, like TTFB, have to do with the server and how fast it renders and sends the
|
||||||
|
initial HTML to the client.
|
||||||
|
|
||||||
|
### Initial Analysis
|
||||||
|
|
||||||
|
Let's start by (in a really broad sense) differentiating the optimizations that can be done on a site. We started by separating them into two main areas:
|
||||||
|
|
||||||
|
1. **Optimizing the Server:** Changes that have to do with where you are hosting the page, such as having a fast and reliable CDN, having all the correct caching policies, how fast the server responds, how close the server is located to the end user, etc. This part is nearly impossible to optimize for a Shopify theme since all this part is controlled by Shopify itself.
|
||||||
|
|
||||||
|
Additionally, the amount of Liquid code the server has to render can affect the speed of response of the server. If there's one thing to take care of in this section, it is the amount of complicated Liquid code you are using in your theme.
|
||||||
|
|
||||||
|
2. **Optimizing the Code:** Changes that have to be done on the code of the theme. This is where most of our efforts will be focused. Things like preconnecting to 3rd party servers, preloading assets, removing unused code, optimizing images, and orchestrating CSS and JavaScript loading times are the things we are going to focus on in this section.
|
||||||
|
|
||||||
|
### Optimizing the Code
|
||||||
|
|
||||||
|
I know there are many ways to approach the optimization of the different parts of the code, but this is the process I follow. I hope that it makes sense for the majority of the cases. For this example, I will use one of our client's themes (we have previous authorization to use this theme as an example). The store is called [Lycklig Party Shop](https://lycklig.com.mx/) and they sell party supplies. They have been on Shopify since 2016, and the theme has been the same since the start of the store.
|
||||||
|
|
||||||
|
### Running the first control tests
|
||||||
|
|
||||||
|
I use two tools to measure the progress that was achieved with the optimization: Google Page Speed Insights and Web Page Test. Both tools are great. Google Page Speed Insights is required since one of the main goals of optimizing a Shopify store is to rank better in Google searches by having better Web Vitals. Web Page Test is a professional tool for those looking to have a deeper look into optimizing a site.
|
||||||
|
|
||||||
|
Webpage Test Report:
|
||||||
|
[Report](https://www.webpagetest.org/result/220819_BiDc6R_B5K/).
|
||||||
|
|
||||||
|
PageSpeed Insights Report:
|
||||||
|
|
||||||
|
<div class="image__container">
|
||||||
|
<img
|
||||||
|
alt="Lycklig Not Optimized Page Speed Insights Report"
|
||||||
|
style="aspect-ratio: 968/895;"
|
||||||
|
src="https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_300/v1660926662/Rafa%20Blog/lycklig-initial-test_jz8jly.png"
|
||||||
|
srcset="https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_300/v1660926662/Rafa%20Blog/lycklig-initial-test_jz8jly.png 300w,
|
||||||
|
https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_500/v1660926662/Rafa%20Blog/lycklig-initial-test_jz8jly.png 500w,
|
||||||
|
https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_760/v1660926662/Rafa%20Blog/lycklig-initial-test_jz8jly.png 760w,
|
||||||
|
https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_968/v1660926662/Rafa%20Blog/lycklig-initial-test_jz8jly.png 968w"
|
||||||
|
sizes="(max-width: 310px) 300px,
|
||||||
|
(max-width: 510px) 500px,
|
||||||
|
(max-width: 768px) 760px,
|
||||||
|
(max-width: 1024px) 500px,
|
||||||
|
968px"
|
||||||
|
/>
|
||||||
|
<small>Lycklig Not Optimized Page Speed Insights Report</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
We can see in both cases that the theme is not as well optimized. By looking at the main Web Vitals, we can see that the main areas of opportunity are the LCP and CLS. As mentioned before, this is mostly due to all the heavy assets the site has to download and render or execute. Additionally, the CLS is affected by the way the page renders either the images or dynamic content loaded with JavaScript.
|
||||||
|
|
||||||
|
Most Shopify themes have the same or similar problems, with the main areas where the templates suffer being the LCP and CLS. Some others have poor FCP and TTFB due to the improper usage of liquid when building the theme. There is too much liquid that takes a long time to render on the server, and the usage of legacy liquid code like `{% include 'name_of_file' %}` instead of `{% render 'name_of_file' %}` slows down the initial response time.
|
||||||
|
|
||||||
|
Shopify has a CDN layer that caches the pages, but the caching policy cannot be too long since there is a lot of dynamic content on an e-commerce site.
|
||||||
|
|
||||||
|
This is Part 1 of this blog series. If you want to learn about the practical steps to optimize a Shopify theme, please read [Part 2](https://www.notion.so/blog/optimizing-shopify-theme-2) of this blog entry.
|
@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
layout: ../../layouts/main.astro
|
layout: ../../layouts/main.astro
|
||||||
date: 2022-08-18
|
date: 2022-08-18
|
||||||
title: Optimizing performance of an old Shopify Theme
|
title: Optimizing performance of an old Shopify Theme (Part 2)
|
||||||
description:
|
description:
|
||||||
Some tips and recommendations for optimizing and boosting performance of an
|
Some tips and recommendations for optimizing and boosting performance of an
|
||||||
old Shopify theme.
|
old Shopify theme.
|
||||||
@ -11,7 +11,7 @@ exerpt:
|
|||||||
image: https://images.unsplash.com/photo-1506818144585-74b29c980d4b?crop=entropy&cs=tinysrgb&fm=jpg&ixid=MnwzNTMzMzl8MHwxfGFsbHx8fHx8fHx8fDE2NjA3OTI2NjA&ixlib=rb-1.2.1&q=80&w=350&ar=16:9&fit=crop
|
image: https://images.unsplash.com/photo-1506818144585-74b29c980d4b?crop=entropy&cs=tinysrgb&fm=jpg&ixid=MnwzNTMzMzl8MHwxfGFsbHx8fHx8fHx8fDE2NjA3OTI2NjA&ixlib=rb-1.2.1&q=80&w=350&ar=16:9&fit=crop
|
||||||
---
|
---
|
||||||
|
|
||||||
# Optimizing an old Shopify Theme
|
# Optimizing an old Shopify Theme (Part 2)
|
||||||
|
|
||||||
<img
|
<img
|
||||||
alt="Optimizing an old Shopify Theme"
|
alt="Optimizing an old Shopify Theme"
|
||||||
@ -30,71 +30,14 @@ image: https://images.unsplash.com/photo-1506818144585-74b29c980d4b?crop=entropy
|
|||||||
## Some tips and recommendations for optimizing and boosting performance of an old Shopify theme.
|
## Some tips and recommendations for optimizing and boosting performance of an old Shopify theme.
|
||||||
|
|
||||||
At <a href="https://acromatico.dev" target="_blank">Acromático Development</a>
|
At <a href="https://acromatico.dev" target="_blank">Acromático Development</a>
|
||||||
we are allways helping our clients optimize their Shopify stores, not only the
|
we are always helping our clients optimize their Shopify stores, not only the UX
|
||||||
UX and UI, but also the performance and speed of the site. Optimizing a Shopify
|
and UI, but also the performance and speed of the site. Optimizing a Shopify
|
||||||
theme is not a simple task, it has been a long learning path that continues
|
theme is not a simple task, it has been a long learning path that continues
|
||||||
evolving and improving as we test and try new methodologies.
|
evolving and improving as we test and try new methodologies.
|
||||||
|
|
||||||
In this first blog post I want to share some of the things I've learned during
|
This is a continuation of the Optimizing an old Shopify Theme series, if you
|
||||||
this process, that way maybe I can help other jump through some of the hard
|
want to read about the initial analysis done to know what to look for in a
|
||||||
parts of successfully optimizing a Shopify theme.
|
theme, check out the [part 1](/blog/optimizeing-shopify-theme-1) of this series.
|
||||||
|
|
||||||
### Initial Analysis
|
|
||||||
|
|
||||||
Let's start by (in a really broad sense) diferenciating the optimizations that
|
|
||||||
can be done on a Site. We started by separating them in two main areas:
|
|
||||||
|
|
||||||
1. **Optimizing the Server:** Changes that have to do with where you are hosting
|
|
||||||
the page, things like having a fast and reliable CDN, having all the correct
|
|
||||||
catching policies, how fast the server responds, how near to the end user the
|
|
||||||
server is located, etc. This part is nearly imposible to optimize for a
|
|
||||||
Shopify theme since all this part is controlled by Shopify itself.
|
|
||||||
2. **Optimizing the Code:** Changes that have to be done on the code of the
|
|
||||||
theme, here's where most of our efforts will be focused. Things like
|
|
||||||
preconnecting to 3rd party servers, preloading assets, removing unused code,
|
|
||||||
optimizing images and orchestating CSS and JavaScript loading times are the
|
|
||||||
things we are going to focus on this section.
|
|
||||||
|
|
||||||
### Optimizing the Code
|
|
||||||
|
|
||||||
I know there are many ways to aproach the optimization the differents parts of
|
|
||||||
the code, but this is the process I follow, hope that it makes sense for the
|
|
||||||
mayority of the cases. For this example I will use one of our client's themes
|
|
||||||
(we have previus authorisation to use this theme as an example), the store is
|
|
||||||
calles <a href="https://lycklig.com.mx" target="_blank">Lycklig Party Shop</a>
|
|
||||||
and they sell party supplies. They have been in Shopify since 2016 and the theme
|
|
||||||
has been the same sinse the start of the store.
|
|
||||||
|
|
||||||
#### Running the first control tests
|
|
||||||
|
|
||||||
I use two tools to measure the progress that was achieved with the optimization.
|
|
||||||
Google Page Speed Insights and Web Page Test. Both tools are great, Google Page
|
|
||||||
Speed Insights is required since one of the main goals of optimizing a Shopify
|
|
||||||
store is to rank better in Google searches. Web Page Test is a professional tool
|
|
||||||
for those looking to optimize in depth their site.
|
|
||||||
|
|
||||||
Webpage Test Report:
|
|
||||||
[Report](https://www.webpagetest.org/result/220819_BiDc6R_B5K/).
|
|
||||||
|
|
||||||
PageSpeed Insights Report:
|
|
||||||
|
|
||||||
<div class="image__container">
|
|
||||||
<img
|
|
||||||
alt="Lycklig Not Optimized Page Speed Insights Report"
|
|
||||||
style="aspect-ratio: 968/895;"
|
|
||||||
src="https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_300/v1660926662/Rafa%20Blog/lycklig-initial-test_jz8jly.png"
|
|
||||||
srcset="https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_300/v1660926662/Rafa%20Blog/lycklig-initial-test_jz8jly.png 300w,
|
|
||||||
https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_500/v1660926662/Rafa%20Blog/lycklig-initial-test_jz8jly.png 500w,
|
|
||||||
https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_760/v1660926662/Rafa%20Blog/lycklig-initial-test_jz8jly.png 760w,
|
|
||||||
https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_968/v1660926662/Rafa%20Blog/lycklig-initial-test_jz8jly.png 968w"
|
|
||||||
sizes="(max-width: 310px) 300px,
|
|
||||||
(max-width: 510px) 500px,
|
|
||||||
(max-width: 768px) 760px,
|
|
||||||
(max-width: 1024px) 500px,
|
|
||||||
968px"
|
|
||||||
/>
|
|
||||||
<small>Lycklig Not Optimized Page Speed Insights Report</small>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
#### Preconnecting to 3rd party servers and preloading known assets
|
#### Preconnecting to 3rd party servers and preloading known assets
|
||||||
|
|
||||||
@ -160,20 +103,20 @@ them by total time to load we can see the next result:
|
|||||||
|
|
||||||
<div class="image__container">
|
<div class="image__container">
|
||||||
<img
|
<img
|
||||||
alt="Lycklig Not Optimized Page Speed Insights Report"
|
alt="Lycklig JS Download"
|
||||||
style="aspect-ratio: 968/895;"
|
style="aspect-ratio: 4/3;"
|
||||||
src="https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_300/v1660926662/Rafa%20Blog/lycklig-initial-test_jz8jly.png"
|
src="https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_300/v1661395344/Rafa%20Blog/lycklig-js-download_siplp5.png"
|
||||||
srcset="https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_300/v1660926662/Rafa%20Blog/lycklig-initial-test_jz8jly.png 300w,
|
srcset="https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_300/v1661395344/Rafa%20Blog/lycklig-js-download_siplp5.png 300w,
|
||||||
https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_500/v1660926662/Rafa%20Blog/lycklig-initial-test_jz8jly.png 500w,
|
https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_500/v1661395344/Rafa%20Blog/lycklig-js-download_siplp5.png 500w,
|
||||||
https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_760/v1660926662/Rafa%20Blog/lycklig-initial-test_jz8jly.png 760w,
|
https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_760/v1661395344/Rafa%20Blog/lycklig-js-download_siplp5.png 760w,
|
||||||
https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_968/v1660926662/Rafa%20Blog/lycklig-initial-test_jz8jly.png 968w"
|
https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_968/v1661395344/Rafa%20Blog/lycklig-js-download_siplp5.png 968w"
|
||||||
sizes="(max-width: 310px) 300px,
|
sizes="(max-width: 310px) 300px,
|
||||||
(max-width: 510px) 500px,
|
(max-width: 510px) 500px,
|
||||||
(max-width: 768px) 760px,
|
(max-width: 768px) 760px,
|
||||||
(max-width: 1024px) 500px,
|
(max-width: 1024px) 500px,
|
||||||
968px"
|
968px"
|
||||||
/>
|
/>
|
||||||
<small>Lycklig Not Optimized Page Speed Insights Report</small>
|
<small>Lycklig JS Downloaded by Theme</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
There are 5 super slow scripts:
|
There are 5 super slow scripts:
|
||||||
@ -186,31 +129,115 @@ There are 5 super slow scripts:
|
|||||||
- https://cdn.shopify.com/s/trekkie.storefront.ebdc6f6e0c97d8f5d6a7dac9bc6ab298fff7cf1b.min.js
|
- https://cdn.shopify.com/s/trekkie.storefront.ebdc6f6e0c97d8f5d6a7dac9bc6ab298fff7cf1b.min.js
|
||||||
```
|
```
|
||||||
|
|
||||||
All of themm are basic scripts with the exception of modernizr. Lets go ahead
|
All of themm are essential scripts with the exception of modernizr. Lets go
|
||||||
and remove modernizr file from the `theam.liquid` file and check that there are
|
ahead and remove modernizr file from the `theam.liquid` file and check that
|
||||||
no errors.
|
there are no errors.
|
||||||
|
|
||||||
We got an error in the `theme.js` file. Lets see if we can fix it by removing
|
We got an error in the `theme.js` file. Lets see if we can fix it by removing
|
||||||
any reference to modernizr.
|
any reference to modernizr.
|
||||||
|
|
||||||
<div class="image__container">
|
<div class="image__container">
|
||||||
<img
|
<img
|
||||||
alt="Lycklig Not Optimized Page Speed Insights Report"
|
alt="Lycklig Modernizr Error"
|
||||||
style="aspect-ratio: 968/895;"
|
style="aspect-ratio: 22/5;"
|
||||||
src="https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_300/v1660926662/Rafa%20Blog/lycklig-initial-test_jz8jly.png"
|
src="https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_300/v1661395373/Rafa%20Blog/lycklig-modernizr_mcanhk.png"
|
||||||
srcset="https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_300/v1660926662/Rafa%20Blog/lycklig-initial-test_jz8jly.png 300w,
|
srcset="https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_300/v1661395373/Rafa%20Blog/lycklig-modernizr_mcanhk.png 300w,
|
||||||
https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_500/v1660926662/Rafa%20Blog/lycklig-initial-test_jz8jly.png 500w,
|
https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_500/v1661395373/Rafa%20Blog/lycklig-modernizr_mcanhk.png 500w,
|
||||||
https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_760/v1660926662/Rafa%20Blog/lycklig-initial-test_jz8jly.png 760w,
|
https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_760/v1661395373/Rafa%20Blog/lycklig-modernizr_mcanhk.png 760w,
|
||||||
https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_968/v1660926662/Rafa%20Blog/lycklig-initial-test_jz8jly.png 968w"
|
https://res.cloudinary.com/acromatico-development/image/upload/c_scale,f_auto,w_968/v1661395373/Rafa%20Blog/lycklig-modernizr_mcanhk.png 968w"
|
||||||
sizes="(max-width: 310px) 300px,
|
sizes="(max-width: 310px) 300px,
|
||||||
(max-width: 510px) 500px,
|
(max-width: 510px) 500px,
|
||||||
(max-width: 768px) 760px,
|
(max-width: 768px) 760px,
|
||||||
(max-width: 1024px) 500px,
|
(max-width: 1024px) 500px,
|
||||||
968px"
|
968px"
|
||||||
/>
|
/>
|
||||||
<small>Lycklig Not Optimized Page Speed Insights Report</small>
|
<small>Lycklig Modernizr Error</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
We found a `Modernizr` instance being referenced in diferent parts of the file.
|
We found a `Modernizr` instance being referenced in diferent parts of the file.
|
||||||
We just carefully deleted them and the error was gone. If this had become a
|
We just carefully deleted them and the error was gone. The problem was that all
|
||||||
larger prioblem we woud have gonne back to not removing the modernizr file.
|
the icons of the theme changed to text 👎. This has become a larger prioblem so
|
||||||
|
we will go back to not removing the modernizr file.
|
||||||
|
|
||||||
|
#### Images Optimization and Elements with Layout Shifts
|
||||||
|
|
||||||
|
By looking at the
|
||||||
|
[Web Vitals Webpage Test Report](https://www.webpagetest.org/vitals.php?test=220819_BiDc6R_B5K&run=3#cls)
|
||||||
|
we can see diferent elements that produce layout shifts. The main one is the
|
||||||
|
announcement bar. Lets add a fix height to the announcement bar to fix that
|
||||||
|
issue.
|
||||||
|
|
||||||
|
As well the main logo appears from no where and moves the size of the header. We
|
||||||
|
can add an aspect ratio property to the logo to fix that by adding
|
||||||
|
`aspect-ratio: 10/3;` to the logo style tag.
|
||||||
|
|
||||||
|
Something we noted in the code was that all the images of the theme have lazy
|
||||||
|
loading added, even the initially rendered ones. We removed all the lazuy
|
||||||
|
loading added to the initial images. as well we added a `srcset` attribute and a
|
||||||
|
`sizes` attribute to the images and even some images where still rendered with
|
||||||
|
the CSS `background-image` property, we changed that to be an `img` tag.
|
||||||
|
|
||||||
|
This is the code to render the images of the slider before the changes:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<style>
|
||||||
|
@media screen and (max-width: 1024px) and (max-height: 768px) {
|
||||||
|
.hero__image--{{ block.id }} {
|
||||||
|
background-image: url('{{ block.settings.image | img_url: '1024x1024' | format: 'jpg' }}');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media screen and (min-width: 1025px), screen and (min-height: 769px) {
|
||||||
|
.hero__image--{{ block.id }} {
|
||||||
|
background-image: url('{{ block.settings.image | img_url: '2048x2048' | format: 'jpg' }}');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="hero__image hero__image--{{ block.id }}"
|
||||||
|
data-image="{{ block.settings.image | img_url: '1024x1024' | format: 'jpg' }}"
|
||||||
|
></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
After we changed the code it looked like this:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="hero__image hero__image--{{ block.id }}">
|
||||||
|
<img
|
||||||
|
srcset="{{ block.settings.image | img_url: '320x320' }} 320w,
|
||||||
|
{{ block.settings.image | img_url: '480x480' }} 480w,
|
||||||
|
{{ block.settings.image | img_url: '800x800' }} 800w,
|
||||||
|
{{ block.settings.image | img_url: '1024x1024' }} 1024w,
|
||||||
|
{{ block.settings.image | img_url: '2048x2048' }} 2048w"
|
||||||
|
sizes="(max-width: 320px) 320px,
|
||||||
|
(max-width: 480px) 480px,
|
||||||
|
(max-width: 800px) 800px,
|
||||||
|
(max-width: 1024px) 1024px,
|
||||||
|
2048px"
|
||||||
|
src="{{ block.settings.image | img_url: '2048x2048' }}"
|
||||||
|
loading="lazy"
|
||||||
|
width="2048"
|
||||||
|
height="2048"
|
||||||
|
alt="{{ block.settings.image.alt | escape }}"
|
||||||
|
class=""
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### The Final Results
|
||||||
|
|
||||||
|
Over all we think the theme was all ready well optimized, changes where minor
|
||||||
|
and the most relevant change had to do with the slider images. There are other
|
||||||
|
areas of improvement like removing modernizr and jquery from the base libraries
|
||||||
|
the theme uses but that is considered a huge change in which case it would be
|
||||||
|
better to consider migrating to a newer theme.
|
||||||
|
|
||||||
|
The final reports made in Web Page Test ands Google Page Speed Insights are
|
||||||
|
available here:
|
||||||
|
|
||||||
|
- [Web Page Test Report](https://www.webpagetest.org/result/220825_BiDc5H_AXN/)
|
||||||
|
- [Google Page Speed Insights](https://pagespeed.web.dev/report?url=https%3A%2F%2Fwww.lycklig.com.mx%2F)
|
||||||
|
|
||||||
|
Hope this entry helps you optimizing your Shopify Themes, this same concept can
|
||||||
|
be applied to any web page with the difference of the usage of liquid and maybe
|
||||||
|
having more control over the scripts that are being loaded in the page.
|
16
src/content/config.ts
Normal file
16
src/content/config.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { z, defineCollection } from "astro:content";
|
||||||
|
|
||||||
|
const blogCollection = defineCollection({
|
||||||
|
schema: z.object({
|
||||||
|
layout: z.enum(['../../layouts/main.astro']).optional(),
|
||||||
|
date: z.date(),
|
||||||
|
title: z.string(),
|
||||||
|
description: z.string(),
|
||||||
|
exerpt: z.string(),
|
||||||
|
image: z.string()
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const collections = {
|
||||||
|
'blog': blogCollection,
|
||||||
|
};
|
@ -49,16 +49,16 @@
|
|||||||
"url": "https://github.com/acromatico-development",
|
"url": "https://github.com/acromatico-development",
|
||||||
"icon": "github"
|
"icon": "github"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "Instagram",
|
|
||||||
"url": "https://www.instagram.com/acromatico.dev",
|
|
||||||
"icon": "instagram"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "Discord",
|
"name": "Discord",
|
||||||
"url": "https://discord.gg/NswUaFSG",
|
"url": "https://discord.gg/NswUaFSG",
|
||||||
"icon": "discord"
|
"icon": "discord"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Instagram",
|
||||||
|
"url": "https://www.instagram.com/acromatico.dev",
|
||||||
|
"icon": "instagram"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "LinkedIn",
|
"name": "LinkedIn",
|
||||||
"url": "https://www.linkedin.com/company/acromatico",
|
"url": "https://www.linkedin.com/company/acromatico",
|
||||||
|
2
src/env.d.ts
vendored
Normal file
2
src/env.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/// <reference path="../.astro/types.d.ts" />
|
||||||
|
/// <reference types="astro/client" />
|
@ -5,91 +5,110 @@ import "../styles/base.css";
|
|||||||
const profileName = profileData.name;
|
const profileName = profileData.name;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
frontmatter,
|
frontmatter,
|
||||||
title: titleProp,
|
title: titleProp,
|
||||||
description: descriptionProp,
|
description: descriptionProp,
|
||||||
blog,
|
image: imageProp,
|
||||||
|
blog,
|
||||||
|
hasMainTitle,
|
||||||
} = Astro.props;
|
} = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png" />
|
<link rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png" />
|
||||||
<link rel="apple-touch-icon" sizes="60x60" href="/apple-icon-60x60.png" />
|
<link rel="apple-touch-icon" sizes="60x60" href="/apple-icon-60x60.png" />
|
||||||
<link rel="apple-touch-icon" sizes="72x72" href="/apple-icon-72x72.png" />
|
<link rel="apple-touch-icon" sizes="72x72" href="/apple-icon-72x72.png" />
|
||||||
<link rel="apple-touch-icon" sizes="76x76" href="/apple-icon-76x76.png" />
|
<link rel="apple-touch-icon" sizes="76x76" href="/apple-icon-76x76.png" />
|
||||||
<link rel="apple-touch-icon" sizes="114x114" href="/apple-icon-114x114.png"
|
<link
|
||||||
/>
|
rel="apple-touch-icon"
|
||||||
<link rel="apple-touch-icon" sizes="120x120" href="/apple-icon-120x120.png"
|
sizes="114x114"
|
||||||
/>
|
href="/apple-icon-114x114.png"
|
||||||
<link rel="apple-touch-icon" sizes="144x144" href="/apple-icon-144x144.png"
|
/>
|
||||||
/>
|
<link
|
||||||
<link rel="apple-touch-icon" sizes="152x152" href="/apple-icon-152x152.png"
|
rel="apple-touch-icon"
|
||||||
/>
|
sizes="120x120"
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png"
|
href="/apple-icon-120x120.png"
|
||||||
/>
|
/>
|
||||||
<link
|
<link
|
||||||
rel="icon"
|
rel="apple-touch-icon"
|
||||||
type="image/png"
|
sizes="144x144"
|
||||||
sizes="192x192"
|
href="/apple-icon-144x144.png"
|
||||||
href="/android-icon-192x192.png"
|
/>
|
||||||
/>
|
<link
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
rel="apple-touch-icon"
|
||||||
<link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png" />
|
sizes="152x152"
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
href="/apple-icon-152x152.png"
|
||||||
<link rel="manifest" href="/manifest.json" />
|
/>
|
||||||
<meta name="msapplication-TileColor" content="#ffffff" />
|
<link
|
||||||
<meta name="msapplication-TileImage" content="/ms-icon-144x144.png" />
|
rel="apple-touch-icon"
|
||||||
<meta name="theme-color" content="#ffffff" />
|
sizes="180x180"
|
||||||
<meta name="viewport" content="width=device-width" />
|
href="/apple-icon-180x180.png"
|
||||||
<title>
|
/>
|
||||||
{
|
<link
|
||||||
frontmatter?.title
|
rel="icon"
|
||||||
? `${frontmatter?.title} | ${profileName} Blog`
|
type="image/png"
|
||||||
: titleProp
|
sizes="192x192"
|
||||||
? `${titleProp} | ${profileName} Blog`
|
href="/android-icon-192x192.png"
|
||||||
: `${profileName} | Links`
|
/>
|
||||||
}
|
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
||||||
</title>
|
<link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png" />
|
||||||
<meta
|
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
||||||
name="description"
|
<link rel="manifest" href="/manifest.json" />
|
||||||
content={frontmatter?.description
|
<meta name="msapplication-TileColor" content="#ffffff" />
|
||||||
? frontmatter.description
|
<meta name="msapplication-TileImage" content="/ms-icon-144x144.png" />
|
||||||
: descriptionProp
|
<meta name="theme-color" content="#ffffff" />
|
||||||
? descriptionProp
|
<meta name="viewport" content="width=device-width" />
|
||||||
: profileData.description}
|
<title>
|
||||||
/>
|
{
|
||||||
<meta name="robots" content="index, follow" />
|
frontmatter?.title
|
||||||
<meta property="og:type" content="website" />
|
? `${frontmatter?.title} | ${profileName} Blog`
|
||||||
<meta
|
: titleProp
|
||||||
property="og:title"
|
? `${titleProp} | ${profileName} Blog`
|
||||||
content={frontmatter?.title
|
: `${profileName} | Links`
|
||||||
? `${frontmatter?.title} | ${profileName} Blog`
|
}
|
||||||
: titleProp
|
</title>
|
||||||
? `${titleProp} | ${profileName} Blog`
|
<meta
|
||||||
: `${profileName} | Links`}
|
name="description"
|
||||||
/>
|
content={frontmatter?.description
|
||||||
<meta
|
? frontmatter.description
|
||||||
property="og:description"
|
: descriptionProp
|
||||||
content={frontmatter?.description
|
? descriptionProp
|
||||||
? frontmatter.description
|
: profileData.description}
|
||||||
: descriptionProp
|
/>
|
||||||
? descriptionProp
|
<meta name="robots" content="index, follow" />
|
||||||
: profileData.description}
|
<meta property="og:type" content="website" />
|
||||||
/>
|
<meta
|
||||||
<meta
|
property="og:title"
|
||||||
property="og:image"
|
content={frontmatter?.title
|
||||||
content={frontmatter?.image
|
? `${frontmatter?.title} | ${profileName} Blog`
|
||||||
? frontmatter?.image
|
: titleProp
|
||||||
: "https://res.cloudinary.com/acromatico-development/image/upload/c_fill,f_auto,h_1200,w_1200/v1641392022/Rafa%20Page/6575E4EB-3F86-47E7-A315-9CD51E5279EB_mm7ctf"}
|
? `${titleProp} | ${profileName} Blog`
|
||||||
/>
|
: `${profileName} | Links`}
|
||||||
<meta property="og:url" content={Astro.url} />
|
/>
|
||||||
<link rel="canonical" href={Astro.url} />
|
<meta
|
||||||
|
property="og:description"
|
||||||
|
content={frontmatter?.description
|
||||||
|
? frontmatter.description
|
||||||
|
: descriptionProp
|
||||||
|
? descriptionProp
|
||||||
|
: profileData.description}
|
||||||
|
/>
|
||||||
|
<meta
|
||||||
|
property="og:image"
|
||||||
|
content={frontmatter?.image
|
||||||
|
? frontmatter?.image
|
||||||
|
: imageProp
|
||||||
|
? imageProp
|
||||||
|
: "https://res.cloudinary.com/acromatico-development/image/upload/c_fill,f_auto,h_1200,w_1200/v1641392022/Rafa%20Page/6575E4EB-3F86-47E7-A315-9CD51E5279EB_mm7ctf"}
|
||||||
|
/>
|
||||||
|
<meta property="og:url" content={Astro.url} />
|
||||||
|
<link rel="canonical" href={Astro.url} />
|
||||||
|
|
||||||
<script
|
<script
|
||||||
type="application/ld+json"
|
type="application/ld+json"
|
||||||
set:html={`
|
set:html={`
|
||||||
{
|
{
|
||||||
"@context": "https://schema.org",
|
"@context": "https://schema.org",
|
||||||
"@type": "WebSite",
|
"@type": "WebSite",
|
||||||
@ -97,11 +116,11 @@ const {
|
|||||||
"url": "https://rafa.page"
|
"url": "https://rafa.page"
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
></script>
|
></script>
|
||||||
|
|
||||||
<script
|
<script
|
||||||
type="application/ld+json"
|
type="application/ld+json"
|
||||||
set:html={`{
|
set:html={`{
|
||||||
"@context": "https://schema.org",
|
"@context": "https://schema.org",
|
||||||
"@type": "Person",
|
"@type": "Person",
|
||||||
"name": "Rafael González Vázquez",
|
"name": "Rafael González Vázquez",
|
||||||
@ -113,13 +132,13 @@ const {
|
|||||||
],
|
],
|
||||||
"image": "https://res.cloudinary.com/acromatico-development/image/upload/c_fill,f_auto,h_1200,w_1200/v1641392022/Rafa%20Page/6575E4EB-3F86-47E7-A315-9CD51E5279EB_mm7ctf"
|
"image": "https://res.cloudinary.com/acromatico-development/image/upload/c_fill,f_auto,h_1200,w_1200/v1641392022/Rafa%20Page/6575E4EB-3F86-47E7-A315-9CD51E5279EB_mm7ctf"
|
||||||
}`}
|
}`}
|
||||||
></script>
|
></script>
|
||||||
|
|
||||||
{
|
{
|
||||||
frontmatter && (
|
(frontmatter || imageProp) && (
|
||||||
<script
|
<script
|
||||||
type="application/ld+json"
|
type="application/ld+json"
|
||||||
set:html={`
|
set:html={`
|
||||||
{
|
{
|
||||||
"@context": "https://schema.org",
|
"@context": "https://schema.org",
|
||||||
"@type": "NewsArticle",
|
"@type": "NewsArticle",
|
||||||
@ -127,12 +146,12 @@ const {
|
|||||||
"@type": "WebPage",
|
"@type": "WebPage",
|
||||||
"@id": "${Astro.url}"
|
"@id": "${Astro.url}"
|
||||||
},
|
},
|
||||||
"headline": "${frontmatter.title}",
|
"headline": "${frontmatter?.title || titleProp}",
|
||||||
"image": [
|
"image": [
|
||||||
"${frontmatter.image}"
|
"${frontmatter?.image || imageProp}"
|
||||||
],
|
],
|
||||||
"datePublished": "${frontmatter.date}",
|
"datePublished": "${frontmatter?.date || ""}",
|
||||||
"dateModified": "${frontmatter.date}",
|
"dateModified": "${frontmatter?.date || ""}",
|
||||||
"author": {
|
"author": {
|
||||||
"@type": "Person",
|
"@type": "Person",
|
||||||
"name": "Rafael González Vázquez",
|
"name": "Rafael González Vázquez",
|
||||||
@ -140,78 +159,88 @@ const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-45FLVCCPTZ"
|
<script type="text/partytown" src="https://www.googletagmanager.com/gtag/js?id=G-45FLVCCPTZ"
|
||||||
></script>
|
></script>
|
||||||
<script>
|
<script
|
||||||
// @ts-ignore
|
type="text/partytown"
|
||||||
window.dataLayer = window.dataLayer || [];
|
set:html={`
|
||||||
function gtag() {
|
window.dataLayer = window.dataLayer || [];
|
||||||
// @ts-ignore
|
function gtag() {
|
||||||
dataLayer.push(arguments);
|
dataLayer.push(arguments);
|
||||||
}
|
}
|
||||||
// @ts-ignore
|
gtag("js", new Date());
|
||||||
gtag("js", new Date());
|
gtag("config", "G-45FLVCCPTZ");
|
||||||
// @ts-ignore
|
`}
|
||||||
gtag("config", "G-45FLVCCPTZ");
|
></script>
|
||||||
</script>
|
</head>
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class={`bg-white dark:bg-gray-900`}>
|
<body class={`bg-white dark:bg-gray-900`}>
|
||||||
<header class="w-full flex flex-col justify-center items-center pt-10">
|
<header class="w-full flex flex-col justify-center items-center pt-10">
|
||||||
<img
|
<img
|
||||||
class="w-1/3 md:w-52 rounded-full border-4 border-gray-900 dark:border-white aspect-square"
|
class="w-1/3 md:w-52 rounded-full border-4 border-gray-900 dark:border-white aspect-square"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
src="https://res.cloudinary.com/acromatico-development/image/upload/c_fill,f_auto,h_50,w_50/v1641392022/Rafa%20Page/6575E4EB-3F86-47E7-A315-9CD51E5279EB_mm7ctf"
|
src="https://res.cloudinary.com/acromatico-development/image/upload/c_fill,f_auto,h_50,w_50/v1641392022/Rafa%20Page/6575E4EB-3F86-47E7-A315-9CD51E5279EB_mm7ctf"
|
||||||
sizes="(max-width: 640px) 50vw,
|
sizes="(max-width: 640px) 50vw,
|
||||||
208px"
|
208px"
|
||||||
srcset="https://res.cloudinary.com/acromatico-development/image/upload/c_fill,f_auto,h_50,w_50/v1641392022/Rafa%20Page/6575E4EB-3F86-47E7-A315-9CD51E5279EB_mm7ctf 50w,
|
srcset="https://res.cloudinary.com/acromatico-development/image/upload/c_fill,f_auto,h_50,w_50/v1641392022/Rafa%20Page/6575E4EB-3F86-47E7-A315-9CD51E5279EB_mm7ctf 50w,
|
||||||
https://res.cloudinary.com/acromatico-development/image/upload/c_fill,f_auto,h_100,w_100/v1641392022/Rafa%20Page/6575E4EB-3F86-47E7-A315-9CD51E5279EB_mm7ctf 100w,
|
https://res.cloudinary.com/acromatico-development/image/upload/c_fill,f_auto,h_100,w_100/v1641392022/Rafa%20Page/6575E4EB-3F86-47E7-A315-9CD51E5279EB_mm7ctf 100w,
|
||||||
https://res.cloudinary.com/acromatico-development/image/upload/c_fill,f_auto,h_200,w_200/v1641392022/Rafa%20Page/6575E4EB-3F86-47E7-A315-9CD51E5279EB_mm7ctf 200w,
|
https://res.cloudinary.com/acromatico-development/image/upload/c_fill,f_auto,h_200,w_200/v1641392022/Rafa%20Page/6575E4EB-3F86-47E7-A315-9CD51E5279EB_mm7ctf 200w,
|
||||||
https://res.cloudinary.com/acromatico-development/image/upload/c_fill,f_auto,h_600,w_600/v1641392022/Rafa%20Page/6575E4EB-3F86-47E7-A315-9CD51E5279EB_mm7ctf 600w,
|
https://res.cloudinary.com/acromatico-development/image/upload/c_fill,f_auto,h_600,w_600/v1641392022/Rafa%20Page/6575E4EB-3F86-47E7-A315-9CD51E5279EB_mm7ctf 600w,
|
||||||
https://res.cloudinary.com/acromatico-development/image/upload/c_fill,f_auto,h_900,w_900/v1641392022/Rafa%20Page/6575E4EB-3F86-47E7-A315-9CD51E5279EB_mm7ctf 900w,
|
https://res.cloudinary.com/acromatico-development/image/upload/c_fill,f_auto,h_900,w_900/v1641392022/Rafa%20Page/6575E4EB-3F86-47E7-A315-9CD51E5279EB_mm7ctf 900w,
|
||||||
https://res.cloudinary.com/acromatico-development/image/upload/c_fill,f_auto,h_1200,w_1200/v1641392022/Rafa%20Page/6575E4EB-3F86-47E7-A315-9CD51E5279EB_mm7ctf 1200w,
|
https://res.cloudinary.com/acromatico-development/image/upload/c_fill,f_auto,h_1200,w_1200/v1641392022/Rafa%20Page/6575E4EB-3F86-47E7-A315-9CD51E5279EB_mm7ctf 1200w,
|
||||||
https://res.cloudinary.com/acromatico-development/image/upload/c_fill,f_auto,h_1500,w_1500/v1641392022/Rafa%20Page/6575E4EB-3F86-47E7-A315-9CD51E5279EB_mm7ctf 1500w"
|
https://res.cloudinary.com/acromatico-development/image/upload/c_fill,f_auto,h_1500,w_1500/v1641392022/Rafa%20Page/6575E4EB-3F86-47E7-A315-9CD51E5279EB_mm7ctf 1500w"
|
||||||
alt="Rafael González"
|
alt="Rafael González"
|
||||||
/>
|
/>
|
||||||
<h1
|
|
||||||
class="font-mono text-center font-bold underline underline-offset-8 uppercase text-4xl my-4 tracking-wide dark:text-white"
|
{
|
||||||
>
|
hasMainTitle || frontmatter?.title ? (
|
||||||
{profileName}
|
<a href="/">
|
||||||
</h1>
|
<h2 class="font-mono text-center font-bold underline underline-offset-8 uppercase text-4xl my-4 tracking-wide dark:text-white">
|
||||||
<p
|
{profileName} Blog
|
||||||
class="font-mono text-center text-l my-4 sm:mt-4 sm:mb-0 mx-auto w-11/12 max-w-5xl tracking-wide dark:text-white"
|
</h2>
|
||||||
>
|
</a>
|
||||||
{profileData.description}
|
) : (
|
||||||
</p>
|
<a href="/">
|
||||||
<a href="/main.vcf" target="_blank" rel="noopener" class="md:hidden"
|
<h1 class="font-mono text-center font-bold underline underline-offset-8 uppercase text-4xl my-4 tracking-wide dark:text-white">
|
||||||
><button
|
{profileName}
|
||||||
class="mt-4 p-4 bg-black text-white dark:text-black dark:bg-white border-2 border-black rounded-md font-bold uppercase tracking-wide"
|
</h1>
|
||||||
>Agregar a Contactos
|
</a>
|
||||||
</button>
|
)
|
||||||
</a>
|
}
|
||||||
</header>
|
<p
|
||||||
<main
|
class="font-mono text-center text-l my-4 sm:mt-4 sm:mb-0 mx-auto w-11/12 max-w-5xl tracking-wide dark:text-white"
|
||||||
class={`font-mono text-l my-16 sm:mb-8 mx-auto w-11/12 max-w-5xl tracking-wide dark:text-white ${
|
>
|
||||||
blog || frontmatter ? "blog" : ""
|
{profileData.description}
|
||||||
}`}
|
</p>
|
||||||
>
|
<a href="/main.vcf" target="_blank" rel="noopener" class="md:hidden"
|
||||||
<slot />
|
><button
|
||||||
</main>
|
class="mt-4 p-4 bg-black text-white dark:text-black dark:bg-white border-2 border-black rounded-md font-bold uppercase tracking-wide"
|
||||||
<footer class="px-3 py-8">
|
>Agregar a Contactos
|
||||||
<p class="dark:text-white text-center">
|
</button>
|
||||||
Powered by <a
|
</a>
|
||||||
class="underline"
|
</header>
|
||||||
href="https://acromatico.dev"
|
<main
|
||||||
target="_blank"
|
class={`font-mono text-l my-16 sm:mb-8 mx-auto w-11/12 max-w-5xl tracking-wide dark:text-white ${
|
||||||
rel="noopener"
|
blog || frontmatter || imageProp ? "blog" : ""
|
||||||
>Acromático Development
|
}`}
|
||||||
</a>
|
>
|
||||||
</p>
|
<slot />
|
||||||
</footer>
|
</main>
|
||||||
</body>
|
<footer class="px-3 py-8">
|
||||||
|
<p class="dark:text-white text-center">
|
||||||
|
Powered by <a
|
||||||
|
class="underline"
|
||||||
|
href="https://acromatico.dev"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>Acromático Development
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
16
src/pages/blog/[slug].astro
Normal file
16
src/pages/blog/[slug].astro
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
import { getCollection } from 'astro:content';
|
||||||
|
// 1. Generate a new path for every collection entry
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
const blogEntries = await getCollection('blog');
|
||||||
|
return blogEntries.map(entry => ({
|
||||||
|
params: { slug: entry.slug }, props: { entry },
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
// 2. When it's time to render, you can get the entry directly from the prop
|
||||||
|
const { entry } = Astro.props;
|
||||||
|
const { Content } = await entry.render();
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<Content />
|
@ -1,12 +1,15 @@
|
|||||||
---
|
---
|
||||||
import MainLayout from "../layouts/main.astro";
|
import MainLayout from "../../layouts/main.astro";
|
||||||
const posts = await Astro.glob("../pages/blog/*.mdx");
|
import {getCollection} from "astro:content";
|
||||||
|
const posts = await getCollection("blog");
|
||||||
|
|
||||||
|
console.log(posts[0].slug);
|
||||||
|
|
||||||
const postByDate = posts
|
const postByDate = posts
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
return (
|
return (
|
||||||
new Date(b.frontmatter.date).getTime() -
|
new Date(b.data.date).getTime() -
|
||||||
new Date(a.frontmatter.date).getTime()
|
new Date(a.data.date).getTime()
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.reverse();
|
.reverse();
|
||||||
@ -21,18 +24,18 @@ const postByDate = posts
|
|||||||
<section class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
<section class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||||
{
|
{
|
||||||
postByDate.map((post) => (
|
postByDate.map((post) => (
|
||||||
<a href={`${post.url}`} class="">
|
<a href={`/blog/${post.slug}`} class="">
|
||||||
<article class="border-2 border-gray-800 dark:border-gray-200 dark:text-gray-200 dark:hover:text-white text-gray-800 hover:text-black">
|
<article class="border-2 border-gray-800 dark:border-gray-200 dark:text-gray-200 dark:hover:text-white text-gray-800 hover:text-black">
|
||||||
<img src={post.frontmatter.image} />
|
<img src={post.data.image} />
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<h3 class="mb-4 uppercase">
|
<h3 class="mb-4 uppercase">
|
||||||
{post.frontmatter.title}
|
{post.data.title}
|
||||||
</h3>
|
</h3>
|
||||||
<p class="text-s mb-2">
|
<p class="text-s mb-2">
|
||||||
{post.frontmatter.exerpt}
|
{post.data.exerpt}
|
||||||
</p>
|
</p>
|
||||||
<p class="text-s text-gray-600 dark:text-gray-400 text-sm">
|
<p class="text-s text-gray-600 dark:text-gray-400 text-sm">
|
||||||
{new Date(post.frontmatter.date).toLocaleDateString("es-US")}
|
{new Date(post.data.date).toLocaleDateString("es-US")}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
85
src/pages/church/[id].astro
Normal file
85
src/pages/church/[id].astro
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
---
|
||||||
|
import MainLayout from "../../layouts/main.astro";
|
||||||
|
import { Client } from "@notionhq/client";
|
||||||
|
import { NotionToMarkdown } from "notion-to-md";
|
||||||
|
import {marked} from "marked";
|
||||||
|
|
||||||
|
const notion = new Client({
|
||||||
|
auth: "secret_AXxqx7iaGrcuAcG5ib9l6smC0jqaEeLDb6G1jtUwI5i",
|
||||||
|
});
|
||||||
|
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
const pageId = "87ff5ccc453349de8aa5ae32833817e3";
|
||||||
|
|
||||||
|
const notionPagesContent = await (
|
||||||
|
await fetch(
|
||||||
|
`https://api.notion.com/v1/blocks/${pageId}/children?page_size=100`,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer secret_AXxqx7iaGrcuAcG5ib9l6smC0jqaEeLDb6G1jtUwI5i`,
|
||||||
|
"Notion-Version": "2022-02-22",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
).json();
|
||||||
|
|
||||||
|
const pages = notionPagesContent.results.filter(
|
||||||
|
(page) => page.type === "child_page"
|
||||||
|
);
|
||||||
|
|
||||||
|
return pages.map((page) => ({
|
||||||
|
params: {
|
||||||
|
id: page.id,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
const { id } = Astro.params;
|
||||||
|
|
||||||
|
const pageData = await (
|
||||||
|
await fetch(`https://api.notion.com/v1/pages/${id}`, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer secret_AXxqx7iaGrcuAcG5ib9l6smC0jqaEeLDb6G1jtUwI5i`,
|
||||||
|
"Notion-Version": "2022-02-22",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
).json();
|
||||||
|
|
||||||
|
const n2m = new NotionToMarkdown({ notionClient: notion });
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const mdblocks = await n2m.pageToMarkdown(id);
|
||||||
|
const mdString = n2m.toMarkdownString(mdblocks);
|
||||||
|
const generalString = mdString.replace(/(\r\n|\n|\r)/gm, " ").replace(/(-|#)/gm, "").replaceAll(" ", " ");
|
||||||
|
const mdArray = mdString.split("\n");
|
||||||
|
|
||||||
|
for (let i = 0; i < mdArray.length; i++) {
|
||||||
|
if (mdArray[i].includes("https://www.youtube.com")) {
|
||||||
|
const videoId = mdArray[i].split("watch?v=")[1].split("&")[0];
|
||||||
|
mdArray[i] = '<iframe id="' + videoId + '" type="text/html" width="720" height="405" src="https://www.youtube.com/embed/' + videoId + '" frameborder="0" allowfullscreen></iframe>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mdGood = mdArray.join("\n");
|
||||||
|
|
||||||
|
const htmlData = marked.parse(mdGood);
|
||||||
|
|
||||||
|
const title = pageData.properties.title.title[0].plain_text.split(" | ").splice(0, pageData.properties.title.title[0].plain_text.split(" | ").length - 1).join(" - ");
|
||||||
|
const description = generalString.substring(0, 250);
|
||||||
|
console.log(pageData.cover)
|
||||||
|
const image = pageData.cover.external.url;
|
||||||
|
---
|
||||||
|
|
||||||
|
<MainLayout
|
||||||
|
title={title}
|
||||||
|
description={description}
|
||||||
|
image={image}
|
||||||
|
blog={false}
|
||||||
|
hasMainTitle={true}
|
||||||
|
>
|
||||||
|
<div class="relative w-full aspect-video flex justify-center items-center mb-4">
|
||||||
|
<img src={image} alt={title} class="w-full h-full object-cover absolute top-0 left-0">
|
||||||
|
<h1 class="z-10 text-white px-8 text-sm md:text-xl m-0">{title}</h1>
|
||||||
|
</div>
|
||||||
|
<div set:html={htmlData}></div>
|
||||||
|
</MainLayout>
|
57
src/pages/church/index.astro
Normal file
57
src/pages/church/index.astro
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
---
|
||||||
|
import MainLayout from "../../layouts/main.astro";
|
||||||
|
|
||||||
|
const pageId = "87ff5ccc453349de8aa5ae32833817e3";
|
||||||
|
|
||||||
|
const notionPageData = await (
|
||||||
|
await fetch(`https://api.notion.com/v1/pages/${pageId}`, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer secret_AXxqx7iaGrcuAcG5ib9l6smC0jqaEeLDb6G1jtUwI5i`,
|
||||||
|
"Notion-Version": "2022-02-22",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
).json();
|
||||||
|
|
||||||
|
const notionPageContent = await (
|
||||||
|
await fetch(
|
||||||
|
`https://api.notion.com/v1/blocks/${pageId}/children?page_size=100`,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer secret_AXxqx7iaGrcuAcG5ib9l6smC0jqaEeLDb6G1jtUwI5i`,
|
||||||
|
"Notion-Version": "2022-02-22",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
).json();
|
||||||
|
|
||||||
|
const title = notionPageData.properties.title.title[0].plain_text;
|
||||||
|
|
||||||
|
const pages = notionPageContent.results.filter(
|
||||||
|
(page) => page.type === "child_page"
|
||||||
|
);
|
||||||
|
---
|
||||||
|
|
||||||
|
<MainLayout
|
||||||
|
title={title}
|
||||||
|
description="Aquí pordrás encontrar una lista de todas las notas de clases que he dado y sermones que he escuchado."
|
||||||
|
blog={false}
|
||||||
|
>
|
||||||
|
<h1 class="text-4xl text-center uppercase font-bold mb-8">
|
||||||
|
Nots de Clases y Sermones de Rafa
|
||||||
|
</h1>
|
||||||
|
<h2 class="text-3xl font-bold mb-4">{title}</h2>
|
||||||
|
<section class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||||
|
{
|
||||||
|
pages.map((page) => (
|
||||||
|
<div>
|
||||||
|
<a href={`/church/${page.id}`}>
|
||||||
|
|
||||||
|
<h3 class="text-xl">
|
||||||
|
{page.child_page.title}
|
||||||
|
</h3>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</section>
|
||||||
|
</MainLayout>
|
@ -38,7 +38,7 @@ for (let link of profileData.profesionalLinks) {
|
|||||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 w-11/12 max-w-5xl my-2 mx-auto">
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 w-11/12 max-w-5xl my-2 mx-auto">
|
||||||
|
|
||||||
{personalLinks.map(perLink => (
|
{personalLinks.map(perLink => (
|
||||||
<Icon client:load perLink={perLink} profileName={profileName} />
|
<Icon client:load perLink={perLink} profileName={profileName} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<h2 class="font-mono font-bold uppercase text-xl my-14 mx-auto tracking-wide w-11/12 max-w-5xl dark:text-white">
|
<h2 class="font-mono font-bold uppercase text-xl my-14 mx-auto tracking-wide w-11/12 max-w-5xl dark:text-white">
|
||||||
|
21
src/pages/rss.xml.ts
Normal file
21
src/pages/rss.xml.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import rss from "@astrojs/rss";
|
||||||
|
import type { APIRoute } from "astro";
|
||||||
|
import { getCollection } from "astro:content";
|
||||||
|
|
||||||
|
export const get: APIRoute = async function get({ site }: any) {
|
||||||
|
const posts = await getCollection("blog");
|
||||||
|
const items = posts.map(({ data: { image, title, exerpt, date }, slug }) => ({
|
||||||
|
title,
|
||||||
|
exerpt,
|
||||||
|
link: `${site}${slug}`,
|
||||||
|
pubDate: new Date(date),
|
||||||
|
}));
|
||||||
|
|
||||||
|
return rss({
|
||||||
|
title: 'Rafael González | Blog',
|
||||||
|
description: 'Blog personal de Rafael González, tecnología, e-commerce y más.',
|
||||||
|
site: site.toString(),
|
||||||
|
customData: `<language>es-mx</language>`,
|
||||||
|
items
|
||||||
|
});
|
||||||
|
}
|
@ -3,7 +3,7 @@
|
|||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
@layer utilities {
|
@layer components {
|
||||||
main.blog h1 {
|
main.blog h1 {
|
||||||
@apply text-4xl font-bold mb-8 text-center uppercase;
|
@apply text-4xl font-bold mb-8 text-center uppercase;
|
||||||
}
|
}
|
||||||
@ -28,6 +28,10 @@
|
|||||||
@apply list-disc mb-8 ml-8;
|
@apply list-disc mb-8 ml-8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main.blog li p {
|
||||||
|
@apply mb-0;
|
||||||
|
}
|
||||||
|
|
||||||
main.blog li:not(:last-child) {
|
main.blog li:not(:last-child) {
|
||||||
@apply mb-4;
|
@apply mb-4;
|
||||||
}
|
}
|
||||||
@ -86,4 +90,14 @@
|
|||||||
main.blog pre .language-id {
|
main.blog pre .language-id {
|
||||||
@apply w-full;
|
@apply w-full;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main.blog iframe {
|
||||||
|
@apply w-full mb-8;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 768px) {
|
||||||
|
main.blog h1 {
|
||||||
|
@apply text-lg m-0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
7
tsconfig.json
Normal file
7
tsconfig.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
// Note: No change needed if you use "astro/tsconfigs/strict" or "astro/tsconfigs/strictest"
|
||||||
|
"extends": "astro/tsconfigs/base",
|
||||||
|
"compilerOptions": {
|
||||||
|
"strictNullChecks": true
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user