Merge remote-tracking branch 'origin/main'

This commit is contained in:
Emil Gulamov 2024-04-02 23:45:34 +04:00
commit b817b83219
2 changed files with 62 additions and 60 deletions

View file

@ -85,24 +85,27 @@ ScrewFast is an open-source template designed for quick and efficient web projec
- Serves as a UI demonstration with no live back-end integration. - Serves as a UI demonstration with no live back-end integration.
- [x] **Starlight Documentation Theme Integration**: - [x] **Starlight Documentation Theme Integration**:
- A sleek, user-friendly, full-featured documentation theme, which enhances the readability and usability of our documentation. - A sleek, user-friendly, full-featured documentation theme, which enhances the readability and usability of our documentation.
- Offers a range of features such as site navigation, built-in search functionality, dark mode, syntax highlighting for code, and improved SEO. - Offers a range of features such as site navigation, built-in search functionality, dark mode, syntax highlighting for code, and improved SEO.
- Seamlessly integrates internationalization (i18n) to provide support for documentation in multiple languages, catering to a global audience. - Seamlessly integrates internationalization (i18n) to provide support for documentation in multiple languages, catering to a global audience.
- Designed to facilitate ease of use while offering a modern aesthetic in both light and dark themes to accommodate user preferences. - Designed to facilitate ease of use while offering a modern aesthetic in both light and dark themes to accommodate user preferences.
- [x] **Icon Set Component**: - [x] **Icon Set Component**:
- Convenient and reusable Icon component that allows adding icons simply by providing a name prop. - Convenient and reusable Icon component that allows adding icons simply by providing a name prop.
- Render any pre-defined icon SVG using `<Icon name="iconName" />` in your Astro components. - Render any pre-defined icon SVG using `<Icon name="iconName" />` in your Astro components.
- The Icon Component offers a centralized location for all SVG Icons across the project in one TypeScript file - allowing unified updates and easy maintenance. - The Icon Component offers a centralized location for all SVG Icons across the project in one TypeScript file - allowing unified updates and easy maintenance.
- **Note:** Users have the option to use other community integrations like [astro-icons](https://github.com/natemoo-re/astro-icon). However, the author decided to create a custom icon set component for managing custom icons. - **Note:** Developers have the option to use other community integrations like [astro-icons](https://github.com/natemoo-re/astro-icon). However, the author decided to create a custom icon set component for managing custom icons.
- [x] **Internationalization (i18n) Features**: - [x] **Internationalization (i18n) Features**:
- Integrates [Astros internationalization (i18n) features](https://docs.astro.build/en/guides/internationalization/). - Integrates [Astros internationalization (i18n) features](https://docs.astro.build/en/guides/internationalization/).
- Additionally, a custom LanguagePicker component has been developed to facilitate language selection. - Additionally, a custom LanguagePicker component has been developed to facilitate language selection.
- [x] **Dynamic Table of Contents (ToC) with Scroll Progress Indicator**:
- Enhances ease of navigation in insight posts by highlighting the relevant section in the ToC, and includes a progress indicator to visually represent scroll progress.
- Developers seeking alternatives might consider the [remark-toc](https://github.com/remarkjs/remark-toc) plugin.
### Planned Improvements ### Planned Improvements
- [ ] Implement a table of contents (ToC) sidebar for blog articles. - Currently, there are no planned improvements. We'll update this section as plans develop.
### Bug Fixes ### Bug Fixes
- Currently, there are no known bugs. If you encounter any issues, please report them on our [issues page](https://github.com/mearashadowfax/ScrewFast/issues). - Currently, there are no known bugs. If you encounter any issues, please report them on our [issues page](https://github.com/mearashadowfax/ScrewFast/issues).

View file

@ -82,6 +82,7 @@ const pageTitle: string = `${post.data.title} | ${SITE.title}`;
html { html {
scroll-behavior: smooth; scroll-behavior: smooth;
} }
article h2, article h2,
article h3, article h3,
article h4, article h4,
@ -91,21 +92,26 @@ const pageTitle: string = `${post.data.title} | ${SITE.title}`;
margin-top: 2.5rem; margin-top: 2.5rem;
scroll-margin-top: 3rem; scroll-margin-top: 3rem;
} }
h2 { h2 {
font-size: 1.5rem; font-size: 1.5rem;
line-height: 2rem; line-height: 2rem;
} }
h3 { h3 {
font-size: 1.25rem; font-size: 1.25rem;
line-height: 1.75rem; line-height: 1.75rem;
} }
h4 { h4 {
font-size: 1.125rem; font-size: 1.125rem;
line-height: 1.75rem; line-height: 1.75rem;
} }
p { p {
margin-top: 1.5rem; margin-top: 1.5rem;
} }
@keyframes grow-progress { @keyframes grow-progress {
from { from {
transform: scaleX(0); transform: scaleX(0);
@ -114,20 +120,24 @@ const pageTitle: string = `${post.data.title} | ${SITE.title}`;
transform: scaleX(1); transform: scaleX(1);
} }
} }
#progress { #progress {
transform-origin: 0 50%; transform-origin: 0 50%;
animation: grow-progress auto linear; animation: grow-progress auto linear;
animation-timeline: scroll(block root); animation-timeline: scroll(block root);
} }
#toc li { #toc li {
display: flex; display: flex;
align-items: center; align-items: center;
opacity: 0.8; opacity: 0.8;
transition: all 300ms var(--transition-cubic); transition: all 300ms var(--transition-cubic);
} }
#toc li.selected { #toc li.selected {
opacity: 1; opacity: 1;
} }
#toc li svg { #toc li svg {
width: 0; width: 0;
height: 0; height: 0;
@ -135,6 +145,7 @@ const pageTitle: string = `${post.data.title} | ${SITE.title}`;
height 400ms var(--transition-cubic), height 400ms var(--transition-cubic),
width 400ms var(--transition-cubic); width 400ms var(--transition-cubic);
} }
#toc li.selected svg { #toc li.selected svg {
width: 1.25rem; width: 1.25rem;
height: 1.25rem; height: 1.25rem;
@ -159,67 +170,55 @@ const pageTitle: string = `${post.data.title} | ${SITE.title}`;
}, },
}); });
const SVG_HTML_STRING = '<svg class="w-0 h-0" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="#fa5a15"><path stroke-linecap="round" stroke-linejoin="round" d="m12.75 15 3-3m0 0-3-3m3 3h-7.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"></svg>';
function setActiveLinkById(id: string | null) {
const listItems = document.querySelectorAll("#toc li");
listItems.forEach(item => item.classList.remove("selected"));
if (!id) return;
const activeLink = document.querySelector(`#toc a[href="#${id}"]`);
if (!activeLink) return;
const listItem = activeLink.parentElement;
listItem?.classList.add("selected");
}
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function () {
// The article element that contains the Markdown content // The article element that contains the Markdown content
const article: HTMLElement | null = document.querySelector("article"); const article: HTMLElement | null = document.querySelector("article");
// The ToC container <ul> element // The ToC container <ul> element
const tocList: HTMLElement | null = document.querySelector("#toc ul"); const tocList: HTMLElement | null = document.querySelector("#toc ul");
// Function to create and add an item to the ToC list const headings: NodeListOf<HTMLElement> | [] = article ? article.querySelectorAll("h1, h2, h3, h4, h5, h6") : [];
function addToC(heading: HTMLElement) {
const li = document.createElement("li");
li.className = "toc-level-" + heading.tagName.toLowerCase();
const tempDiv = document.createElement("div"); headings.forEach((heading, i) => {
tempDiv.innerHTML =
'<svg class="w-0 h-0" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="#fa5a15"><path stroke-linecap="round" stroke-linejoin="round" d="m12.75 15 3-3m0 0-3-3m3 3h-7.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"></svg>';
const svg = tempDiv.firstChild;
li.appendChild(svg as Node);
const link = document.createElement("a");
link.href = "#" + heading.id;
link.textContent = heading.textContent;
li.appendChild(link);
tocList?.appendChild(li);
return li;
}
// Helper function to toggle the 'selected' class
function setActiveLink(id: string) {
document.querySelectorAll("#toc li").forEach((li) => {
li.classList.remove("selected");
});
const activeLink = document.querySelector(`#toc a[href="#${id}"]`);
if (activeLink) {
const li: HTMLElement | null = activeLink.parentElement;
li?.classList.add("selected");
}
}
// Observe headings and add them to the ToC
let headings: NodeListOf<HTMLElement> | [] = article
? article.querySelectorAll("h1, h2, h3, h4, h5, h6")
: [];
headings.forEach((heading: Element, i: number) => {
if (heading instanceof HTMLElement) { if (heading instanceof HTMLElement) {
addToC(heading); const listItem = document.createElement("li");
listItem.className = "toc-level-" + heading.tagName.toLowerCase();
const tempDiv = document.createElement("div");
tempDiv.innerHTML = SVG_HTML_STRING;
const svg = tempDiv.firstChild;
listItem.appendChild(svg as Node);
const link = document.createElement("a");
link.href = "#" + heading.id;
link.textContent = heading.textContent;
listItem.appendChild(link);
tocList?.appendChild(listItem);
gsap.timeline({ gsap.timeline({
scrollTrigger: { scrollTrigger: {
trigger: heading, trigger: heading,
start: "top 20%", start: "top 20%",
end: () => end: () => `bottom top+=${i === headings.length - 1 ? 0 : (headings[i + 1] as HTMLElement).getBoundingClientRect().height}`,
`bottom top+=${i === headings.length - 1 ? 0 : headings[i + 1].getBoundingClientRect().height}`, onEnter: () => setActiveLinkById(heading.id),
onEnter: () => setActiveLink(heading.id), onLeaveBack: () => setActiveLinkById((headings[i - 1] as HTMLElement)?.id),
onLeaveBack: () =>
setActiveLink((headings[i - 1] || { id: null }).id),
}, },
}); });
} }