From da5d220c09b88998b1d2bfdf5d2f3fb39e6b5c72 Mon Sep 17 00:00:00 2001 From: Kirtan Thakkar Date: Thu, 7 Nov 2024 14:13:07 +0530 Subject: [PATCH] feat: add toc to the blog sidebar --- 0001-changes-of-toc.patch | 448 ++++++++++++++++++ assets/css/main.css | 4 + blog/components/blog/blog-sidebar.vue | 13 +- blog/components/blog/blog-toc.vue | 274 +++++++++++ blog/pages/[type]/[slug].vue | 55 ++- content/pricing.json | 9 +- .../features/elasticsearch-compatibility.vue | 2 +- 7 files changed, 790 insertions(+), 15 deletions(-) create mode 100644 0001-changes-of-toc.patch create mode 100644 blog/components/blog/blog-toc.vue diff --git a/0001-changes-of-toc.patch b/0001-changes-of-toc.patch new file mode 100644 index 00000000..ac3fc14a --- /dev/null +++ b/0001-changes-of-toc.patch @@ -0,0 +1,448 @@ +From b3f048e1d74351fdfba2b15ea017a5dc06f4c5e8 Mon Sep 17 00:00:00 2001 +From: Riddhi Halani <75210944+Riddhi2303@users.noreply.github.com> +Date: Thu, 7 Nov 2024 13:58:21 +0530 +Subject: [PATCH] changes of toc + +--- + assets/css/main.css | 6 + + blog/components/blog/blog-sidebar.vue | 13 +- + blog/components/blog/blog-toc.vue | 274 ++++++++++++++++++ + blog/pages/[type]/[slug].vue | 55 +++- + .../features/elasticsearch-compatibility.vue | 2 +- + 5 files changed, 339 insertions(+), 11 deletions(-) + create mode 100644 blog/components/blog/blog-toc.vue + +diff --git a/assets/css/main.css b/assets/css/main.css +index d2e440a..8cb1a88 100644 +--- a/assets/css/main.css ++++ b/assets/css/main.css +@@ -15,6 +15,12 @@ + + } + ++html { ++ scroll-behavior: smooth; ++ scroll-padding-top: var(--nav-bar-top-margin); ++ ++} ++ + body { + font-family: "Roboto",Arial,sans-serif !important; + color: var(--theme-color-text-primary); +diff --git a/blog/components/blog/blog-sidebar.vue b/blog/components/blog/blog-sidebar.vue +index 68fe26a..ffa75aa 100644 +--- a/blog/components/blog/blog-sidebar.vue ++++ b/blog/components/blog/blog-sidebar.vue +@@ -203,16 +203,21 @@ const { type } = defineProps({ + const { data: authorsTemp } = await useAsyncData(`${type}-authors`, () => + queryContent(`/${getContentFolder(type)}/authors`).findOne() + ); +-const authors = authorsTemp?.value.authors; ++const authors = authorsTemp?.value.authoractiveTocIds; + + // get categories +-let { data: categories } = await useAsyncData(`${type}-categories`,() => getCategories(type)); ++let { data: categories } = await useAsyncData(`${type}-categories`, () => ++ getCategories(type) ++); + + // get tags +-let { data: tags } = await useAsyncData(`${type}-tags`,() => getTags(type)); ++let { data: tags } = await useAsyncData(`${type}-tags`, () => getTags(type)); + + // get recentArticles +-let { data: recentArticles } = await useAsyncData(`${type}-recent-articles`,() => getRecentArticles(type)); ++let { data: recentArticles } = await useAsyncData( ++ `${type}-recent-articles`, ++ () => getRecentArticles(type) ++); + + const formatDate = (date) => { + const options = { year: "numeric", month: "long", day: "numeric" }; +diff --git a/blog/components/blog/blog-toc.vue b/blog/components/blog/blog-toc.vue +new file mode 100644 +index 0000000..e02b24d +--- /dev/null ++++ b/blog/components/blog/blog-toc.vue +@@ -0,0 +1,274 @@ ++ ++ ++ ++ ++ +diff --git a/blog/pages/[type]/[slug].vue b/blog/pages/[type]/[slug].vue +index 85cddcd..fd7fe68 100644 +--- a/blog/pages/[type]/[slug].vue ++++ b/blog/pages/[type]/[slug].vue +@@ -48,10 +48,12 @@ + :alt="article.alt" + /> + +- ++
++ ++
+ +
+ +@@ -107,7 +109,12 @@ + + + +- ++ + + + +@@ -116,6 +123,9 @@ + const route = useRoute(); + const slug = route.params.slug; + const type = route.params.type; ++const activeSection = ref(new Set()); ++const lastActiveSection = ref(null); ++const nuxtContent = ref(null); + + const { data: article } = await useAsyncData(`${type}-${slug}`, () => + queryContent(`${getContentFolder(type)}/posts/${slug}`).findOne() +@@ -124,11 +134,44 @@ const { data: article } = await useAsyncData(`${type}-${slug}`, () => + const { data: authorsTemp } = await useAsyncData(() => + queryContent(`${getContentFolder(type)}/authors`).findOne() + ); ++ ++const observer = ref(null); ++const observerOptions = reactive({ ++ root: nuxtContent.value, ++ threshold: 0, ++}); ++ ++onMounted(() => { ++ observer.value = new IntersectionObserver((entries) => { ++ entries.forEach((entry) => { ++ const id = entry.target.getAttribute("id"); ++ if (entry.isIntersecting) { ++ activeSection.value.add(id); ++ lastActiveSection.value = id; ++ } else { ++ activeSection.value.delete(id); ++ } ++ }); ++ }, observerOptions); ++ ++ document ++ .querySelectorAll(".blog-content h2[id], .blog-content h3[id]") ++ .forEach((section) => { ++ observer.value?.observe(section); ++ }); ++}); ++ ++onUnmounted(() => { ++ observer.value?.disconnect(); ++}); ++ + const author = authorsTemp?.value?.authors?.find( + (a) => a.slug == article?.value?.author + ); + +-const postAuthors = article?.value?.authors.map((a) => authorsTemp?.value?.authors?.find((b) => b.slug == a)) ++const postAuthors = article?.value?.authors.map((a) => ++ authorsTemp?.value?.authors?.find((b) => b.slug == a) ++); + + const { data: prevNext } = await useAsyncData("prev-next-" + slug, () => + queryContent(`${getContentFolder(type)}/posts`) +diff --git a/pages/features/elasticsearch-compatibility.vue b/pages/features/elasticsearch-compatibility.vue +index 1e5d08c..43002ed 100644 +--- a/pages/features/elasticsearch-compatibility.vue ++++ b/pages/features/elasticsearch-compatibility.vue +@@ -7,7 +7,7 @@ + class="container mx-auto flex flex-col md:flex-row justify-between items-center py-4 space-y-4 md:space-y-0" + > +

{{ data.contactus.desc }}

+- ++ + + + +-- +2.46.0.windows.1 + diff --git a/assets/css/main.css b/assets/css/main.css index d2e440a8..bc42b82d 100644 --- a/assets/css/main.css +++ b/assets/css/main.css @@ -15,6 +15,10 @@ } +html { + scroll-padding-top: var(--nav-bar-top-margin); +} + body { font-family: "Roboto",Arial,sans-serif !important; color: var(--theme-color-text-primary); diff --git a/blog/components/blog/blog-sidebar.vue b/blog/components/blog/blog-sidebar.vue index 68fe26ae..ffa75aad 100644 --- a/blog/components/blog/blog-sidebar.vue +++ b/blog/components/blog/blog-sidebar.vue @@ -203,16 +203,21 @@ const { type } = defineProps({ const { data: authorsTemp } = await useAsyncData(`${type}-authors`, () => queryContent(`/${getContentFolder(type)}/authors`).findOne() ); -const authors = authorsTemp?.value.authors; +const authors = authorsTemp?.value.authoractiveTocIds; // get categories -let { data: categories } = await useAsyncData(`${type}-categories`,() => getCategories(type)); +let { data: categories } = await useAsyncData(`${type}-categories`, () => + getCategories(type) +); // get tags -let { data: tags } = await useAsyncData(`${type}-tags`,() => getTags(type)); +let { data: tags } = await useAsyncData(`${type}-tags`, () => getTags(type)); // get recentArticles -let { data: recentArticles } = await useAsyncData(`${type}-recent-articles`,() => getRecentArticles(type)); +let { data: recentArticles } = await useAsyncData( + `${type}-recent-articles`, + () => getRecentArticles(type) +); const formatDate = (date) => { const options = { year: "numeric", month: "long", day: "numeric" }; diff --git a/blog/components/blog/blog-toc.vue b/blog/components/blog/blog-toc.vue new file mode 100644 index 00000000..7b275a3c --- /dev/null +++ b/blog/components/blog/blog-toc.vue @@ -0,0 +1,274 @@ + + + + + diff --git a/blog/pages/[type]/[slug].vue b/blog/pages/[type]/[slug].vue index 85cddcd4..fd7fe689 100644 --- a/blog/pages/[type]/[slug].vue +++ b/blog/pages/[type]/[slug].vue @@ -48,10 +48,12 @@ :alt="article.alt" /> - +
+ +
@@ -107,7 +109,12 @@ - + @@ -116,6 +123,9 @@ const route = useRoute(); const slug = route.params.slug; const type = route.params.type; +const activeSection = ref(new Set()); +const lastActiveSection = ref(null); +const nuxtContent = ref(null); const { data: article } = await useAsyncData(`${type}-${slug}`, () => queryContent(`${getContentFolder(type)}/posts/${slug}`).findOne() @@ -124,11 +134,44 @@ const { data: article } = await useAsyncData(`${type}-${slug}`, () => const { data: authorsTemp } = await useAsyncData(() => queryContent(`${getContentFolder(type)}/authors`).findOne() ); + +const observer = ref(null); +const observerOptions = reactive({ + root: nuxtContent.value, + threshold: 0, +}); + +onMounted(() => { + observer.value = new IntersectionObserver((entries) => { + entries.forEach((entry) => { + const id = entry.target.getAttribute("id"); + if (entry.isIntersecting) { + activeSection.value.add(id); + lastActiveSection.value = id; + } else { + activeSection.value.delete(id); + } + }); + }, observerOptions); + + document + .querySelectorAll(".blog-content h2[id], .blog-content h3[id]") + .forEach((section) => { + observer.value?.observe(section); + }); +}); + +onUnmounted(() => { + observer.value?.disconnect(); +}); + const author = authorsTemp?.value?.authors?.find( (a) => a.slug == article?.value?.author ); -const postAuthors = article?.value?.authors.map((a) => authorsTemp?.value?.authors?.find((b) => b.slug == a)) +const postAuthors = article?.value?.authors.map((a) => + authorsTemp?.value?.authors?.find((b) => b.slug == a) +); const { data: prevNext } = await useAsyncData("prev-next-" + slug, () => queryContent(`${getContentFolder(type)}/posts`) diff --git a/content/pricing.json b/content/pricing.json index daf67af8..dc7b63f1 100644 --- a/content/pricing.json +++ b/content/pricing.json @@ -76,8 +76,7 @@ "features": [ "Multi-tenancy", "Export logs data", - "Template based alert destinations", - "Email support" + "Template based alert destinations" ], "btnText": "Get started", "btnLink": "https://cloud.openobserve.ai" @@ -98,7 +97,8 @@ "Query Volume ($0.01/GB)", "Functions execution ($0.05/1M records)", "60 days retention for logs and traces", - "Unlimited users" + "Unlimited users", + "Email support" ], "sublabel": "Everything in Pro Plan, plus:", "features": [ @@ -123,6 +123,7 @@ "Custom Retention", "SLAs", "Phone support", + "Email support", "", "" ], @@ -303,7 +304,7 @@ "title": "Email support", "developer": false, "pro": false, - "business": false, + "business": true, "enterprise": true }, { diff --git a/pages/features/elasticsearch-compatibility.vue b/pages/features/elasticsearch-compatibility.vue index 1e5d08c1..43002ed3 100644 --- a/pages/features/elasticsearch-compatibility.vue +++ b/pages/features/elasticsearch-compatibility.vue @@ -7,7 +7,7 @@ class="container mx-auto flex flex-col md:flex-row justify-between items-center py-4 space-y-4 md:space-y-0" >

{{ data.contactus.desc }}

- +