diff --git a/website/src/components/quickstartGuideCard/index.js b/website/src/components/quickstartGuideCard/index.js
index dc961f85a45..3d5769c3246 100644
--- a/website/src/components/quickstartGuideCard/index.js
+++ b/website/src/components/quickstartGuideCard/index.js
@@ -1,4 +1,4 @@
-import React from "react";
+import React, { useState, useEffect } from "react";
import Link from "@docusaurus/Link";
import styles from "./styles.module.css";
import getIconType from "../../utils/get-icon-type";
@@ -32,17 +32,51 @@ export default function QuickstartGuideCard({ frontMatter }) {
// Component that handles the information under the title on the quickstart guide page
export function QuickstartGuideTitle({ frontMatter }) {
- const { time_to_complete, tags, level, recently_updated } =
- frontMatter;
+ const { id, time_to_complete, tags, level, recently_updated } = frontMatter;
+ const [isFavorite, setIsFavorite] = useState(false);
+
+ useEffect(() => {
+ // Check if this guide is in favorites when component mounts
+ const favorites = JSON.parse(localStorage.getItem('favoriteGuides') || '[]');
+ setIsFavorite(favorites.includes(id));
+ }, [id]);
+
+ const toggleFavorite = () => {
+ const favorites = JSON.parse(localStorage.getItem('favoriteGuides') || '[]');
+
+ if (isFavorite) {
+ const newFavorites = favorites.filter(fav => fav !== id);
+ localStorage.setItem('favoriteGuides', JSON.stringify(newFavorites));
+ } else {
+ favorites.push(id);
+ localStorage.setItem('favoriteGuides', JSON.stringify(favorites));
+ }
+
+ setIsFavorite(!isFavorite);
+ };
return (
- {recently_updated && (
-
Updated
- )}
- {time_to_complete && (
-
{getSvgIcon('fa-clock')} {time_to_complete}
- )}
+
+
+
+
+ {recently_updated && (
+
Updated
+ )}
+ {time_to_complete && (
+
+ {getSvgIcon('fa-clock')} {time_to_complete}
+
+ )}
+
{(tags || level) && (
diff --git a/website/src/components/quickstartGuideCard/styles.module.css b/website/src/components/quickstartGuideCard/styles.module.css
index 55d24a96fa0..4df4a0aea77 100644
--- a/website/src/components/quickstartGuideCard/styles.module.css
+++ b/website/src/components/quickstartGuideCard/styles.module.css
@@ -119,6 +119,11 @@
padding-left: 0;
}
+.leftInfo {
+ display: flex;
+ align-items: center;
+}
+
.infoContainer .tag_container {
display: flex;
flex-wrap: wrap;
@@ -171,3 +176,33 @@
padding: 0;
}
}
+.favoriteButton {
+
+ top: 1.5rem;
+ right: 1.5rem;
+ background: none;
+ border: none;
+ cursor: pointer;
+ color: #ccc;
+ padding: 5px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.favoriteButton svg {
+ width: 20px;
+ height: 20px;
+ fill: currentColor;
+}
+
+.favoriteButton:hover {
+ color: var( --color-green-blue);
+}
+
+.favoriteButton.favorited {
+ color: #ffd700;
+}
+
+
+
diff --git a/website/src/components/quickstartGuideList/index.js b/website/src/components/quickstartGuideList/index.js
index 5813409929a..58d35efc0ce 100644
--- a/website/src/components/quickstartGuideList/index.js
+++ b/website/src/components/quickstartGuideList/index.js
@@ -65,6 +65,7 @@ function QuickstartList({ quickstartData }) {
const [selectedFilters, setSelectedFilters] = useState({});
const [searchInput, setSearchInput] = useState('');
const location = useLocation();
+ const [favorites, setFavorites] = useState([]);
// Replace individual filter states with a single object
const getFilterOptions = (filterKey) => {
@@ -198,6 +199,15 @@ function QuickstartList({ quickstartData }) {
}, {}) || {};
}, [filteredData, selectedFilters, quickstartData]);
+ // Add this useEffect to load favorites
+ useEffect(() => {
+ const favoriteIds = JSON.parse(localStorage.getItem('favoriteGuides') || '[]');
+ const favoriteGuides = quickstartData.filter(guide =>
+ favoriteIds.includes(guide.data.id)
+ );
+ setFavorites(favoriteGuides);
+ }, [quickstartData]);
+
return (
@@ -249,6 +259,12 @@ function QuickstartList({ quickstartData }) {
{Object.values(selectedFilters).every(selected => !selected?.length) ? (
// Show categorized view when no filters are selected
<>
+ {favorites.length > 0 && (
+
+ )}
{CONFIG?.categories?.map((category) => (
);
+ case icon.includes("fa-star"):
+ return (
+
+ );
default:
return "";
}