feat: add seo footer#71
Conversation
WalkthroughA new Vue component, Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant PostsPage
participant PostsPageFooter
User->>PostsPage: Visit posts page
PostsPage->>PostsPage: Load booru, tags, filters, posts
PostsPage->>PostsPageFooter: Pass selectedBooru, selectedTags, selectedFilters, postsCount
PostsPageFooter->>PostsPageFooter: Compute related boorus, tags, links
PostsPageFooter-->>User: Render dynamic footer with links and info
Poem
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
components/pages/posts/PostsPageFooter.vue (2)
47-51: Consider making related tags dynamic rather than hardcoded.The hardcoded related tags list ("highres", "animated", "cum", "pov", "1girl", "1boy") might be too specific for certain content types. Consider implementing a more dynamic approach based on actual tag popularity or relevance to the currently selected tags.
-// Hardcoded related tags based on common combinations -// These would be general enough to exist on most booru sites -const hardcodedRelatedTags = ['highres', 'animated', 'cum', 'pov', '1girl', '1boy'] +// Get related tags based on popular combinations or relevance to selected tags +const relatedTags = computed(() => { + // If no selected tags, return general popular tags + if (!props.selectedTags.length) { + return ['highres', 'animated', '1girl', '1boy', 'school_uniform', 'smile'] + } + + // In a real implementation, you might fetch related tags from an API + // based on the currently selected tags + // For now, return a mix of general tags and ones relevant to selection + return ['highres', 'animated', 'cum', 'pov', '1girl', '1boy'] +}) + +const formattedRelatedTags = computed(() => { + return relatedTags.value.map((tag) => normalizeStringForTitle(tag)) +})
95-105: Inconsistent tag handling in navigation links.When linking to related tags, the current selected tags aren't preserved, unlike in the related boorus section (lines 115-129). Consider preserving the current tags when navigating to related tags for a more consistent user experience.
<NuxtLink v-for="(tag, index) in hardcodedRelatedTags" :key="tag" - :to="`/posts/${selectedBooru.domain}?tags=${encodeURIComponent(tag)}`" + :to="`/posts/${selectedBooru.domain}?tags=${[...selectedTags.map(t => encodeURIComponent(t.name)), encodeURIComponent(tag)].join('|')}`" class="text-primary text-sm hover:underline" :title="`Browse ${formattedRelatedTags[index]} ${formattedTagsString} hentai and Rule 34 images`" > {{ formattedRelatedTags[index] }} </NuxtLink>pages/posts/[domain].vue (1)
1069-1070: Consider additional conditional rendering cases.Currently, the footer is only hidden during loading (
!isPending). Consider whether it should also be hidden in error states or when there are no results to avoid showing SEO content that might not match the user's current view.<PostsPageFooter - v-if="!isPending" + v-if="!isPending && !isError && allRows.length > 0" :selected-booru="selectedBooru" :selected-tags="selectedTags" :selected-filters="selectedFilters" :posts-count="allRows.length" :page-title="titleForBody" />
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
components/pages/posts/PostsPageFooter.vue(1 hunks)pages/posts/[domain].vue(1 hunks)
🔇 Additional comments (4)
components/pages/posts/PostsPageFooter.vue (3)
1-52: Script implementation looks clean and well-structured.The component is well-typed with proper props definition and computed properties. Good work on filtering out excluded tags and computing formatted tag strings. The computed properties help maintain clean template code.
58-76: Well-structured SEO content with dynamic values.The section effectively incorporates selected tags, filters, and booru information to create contextually relevant content. The conditional rendering based on selected tags (line 69-72) is a good touch for customizing content.
54-159: Good structural organization of SEO content.The footer is well-organized with multiple sections addressing different aspects (description, benefits, related tags, alternative sources, updates, etc.). Using the
ShowMorecomponent with a height limit is a smart way to manage the amount of content displayed initially.pages/posts/[domain].vue (1)
1067-1075: Good integration of the SEO footer component.The PostsPageFooter is properly integrated with conditional rendering based on loading state and receives all the necessary props from the parent component. This ensures the footer only appears when content is ready to be displayed.
22c19f8 to
909dc92
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
components/pages/posts/PostsPageFooter.vue(1 hunks)pages/posts/[domain].vue(1 hunks)
🔇 Additional comments (5)
components/pages/posts/PostsPageFooter.vue (4)
7-24: Props are well-defined with proper types and defaults.The component has a clear props structure with appropriate TypeScript types, required flags, and default values.
58-76: Good use of dynamic content templating.The headings and paragraphs appropriately use the computed properties to create contextual content based on the selected tags and booru domain. The conditional rendering based on selected tags is also implemented well.
95-105: Proper URL encoding in navigation links.The implementation correctly uses
encodeURIComponentto handle special characters in tag names, andNuxtLinkfor internal navigation with descriptive title attributes. This is good for both usability and SEO.
115-129:Details
✅ Verification successful
Ensure URL structure consistency.
The implementation of related booru links correctly preserves all selected tags when navigating to another booru domain. However, the tag separator used is a pipe (
|), which should be consistent with how tags are normally separated in the application's URL structure.
🏁 Script executed:
#!/bin/bash # Verify how tag separators are handled in the application's URL structure # Look for URL generation functions that handle multiple tags rg -A 10 "tags.*join" --type js --type ts --type vueLength of output: 82
🏁 Script executed:
#!/bin/bash set -e # Search for where the tags parameter is generated or consumed rg -n "\?tags=" -g "*.{vue,js,ts}" rg -n "\.split" -g "*.{vue,js,ts}" rg -n "join(" -g "*.{vue,js,ts}"Length of output: 22694
No changes needed for tag separators
The application already uses “|” to separate multiple tags (e.g. in
pages/posts/[domain].vueyou’ll find.split('|')), and the new footer links follow that same convention. No update is required here.pages/posts/[domain].vue (1)
1068-1074: Good conditional rendering implementation.The footer is conditionally rendered only when content is available and not in loading or error states, which is a good practice to avoid showing the footer in inappropriate contexts.
|
|
||
| <template> | ||
| <footer class="border-base-300/30 mt-5 border-t pt-8"> | ||
| <ShowMore :max-height-in-rem="16"> |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
SEO optimization through content expansion.
The use of ShowMore with a height limit means much of the SEO content may be hidden by default. While this allows for a clean UI, search engines might not value hidden content as much. Consider adjusting the max height to ensure critical SEO content is visible by default.
-<ShowMore :max-height-in-rem="16">
+<ShowMore :max-height-in-rem="24">|
|
||
| // Hardcoded related tags based on common combinations | ||
| // These would be general enough to exist on most booru sites | ||
| const hardcodedRelatedTags = ['highres', 'animated', 'cum', 'big_breasts', '1girl', '1boy'] |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Consider implementing a dynamic approach for related tags.
The hardcoded related tags might not be relevant for all content scenarios. Consider implementing a more dynamic approach that derives related tags based on the current content or popular co-occurrences with the selected tags.
-// Hardcoded related tags based on common combinations
-// These would be general enough to exist on most booru sites
-const hardcodedRelatedTags = ['highres', 'animated', 'cum', 'big_breasts', '1girl', '1boy']
+// Dynamic related tags based on popular combinations
+const relatedTags = computed(() => {
+ // If no selected tags, return general popular tags
+ if (!props.selectedTags.length) {
+ return ['highres', 'animated', 'cum', 'big_breasts', '1girl', '1boy']
+ }
+
+ // Otherwise, return tags commonly used with the selected tags
+ // This could be implemented by fetching from an API or using a predefined mapping
+ return getRelatedTagsForSelection(props.selectedTags)
+})Committable suggestion skipped: line range outside the PR's diff.
|
|
||
| <PostsPageFooter | ||
| v-if="!isPending && !isError && allRows.length > 0" | ||
| :selected-booru="selectedBooru" | ||
| :selected-tags="selectedTags" | ||
| :selected-filters="selectedFilters" | ||
| :posts-count="allRows.length" | ||
| :page-title="titleForBody" | ||
| /> |
There was a problem hiding this comment.
Prop mismatch between component usage and definition.
The component is being passed a page-title prop, but this prop isn't defined in the PostsPageFooter.vue component. Vue will ignore undefined props but this inconsistency should be resolved.
Either add the prop definition to the component:
// In PostsPageFooter.vue
const props = defineProps({
// other props...
+ pageTitle: {
+ type: String,
+ default: ''
+ }
})Or remove the prop from this usage:
<PostsPageFooter
v-if="!isPending && !isError && allRows.length > 0"
:selected-booru="selectedBooru"
:selected-tags="selectedTags"
:selected-filters="selectedFilters"
:posts-count="allRows.length"
- :page-title="titleForBody"
/>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <PostsPageFooter | |
| v-if="!isPending && !isError && allRows.length > 0" | |
| :selected-booru="selectedBooru" | |
| :selected-tags="selectedTags" | |
| :selected-filters="selectedFilters" | |
| :posts-count="allRows.length" | |
| :page-title="titleForBody" | |
| /> | |
| // In PostsPageFooter.vue | |
| const props = defineProps({ | |
| // other props... | |
| pageTitle: { | |
| type: String, | |
| default: '' | |
| } | |
| }) |
| <PostsPageFooter | |
| v-if="!isPending && !isError && allRows.length > 0" | |
| :selected-booru="selectedBooru" | |
| :selected-tags="selectedTags" | |
| :selected-filters="selectedFilters" | |
| :posts-count="allRows.length" | |
| :page-title="titleForBody" | |
| /> | |
| <PostsPageFooter | |
| v-if="!isPending && !isError && allRows.length > 0" | |
| :selected-booru="selectedBooru" | |
| :selected-tags="selectedTags" | |
| :selected-filters="selectedFilters" | |
| :posts-count="allRows.length" | |
| /> |
Summary by CodeRabbit