Skip to content

feat: add seo footer#71

Merged
AlejandroAkbal merged 2 commits intomainfrom
feat/SEO-optimization
Apr 24, 2025
Merged

feat: add seo footer#71
AlejandroAkbal merged 2 commits intomainfrom
feat/SEO-optimization

Conversation

@AlejandroAkbal
Copy link
Copy Markdown
Member

@AlejandroAkbal AlejandroAkbal commented Apr 24, 2025

Summary by CodeRabbit

  • New Features
    • Introduced a dynamic footer on the posts page showing information about selected tags, filters, and booru sources.
    • Footer highlights real-time updates, advanced search tips, popular related tags, and alternative booru links for improved navigation and content discovery.
    • Footer appears only after posts have loaded, ensuring a smooth browsing experience.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 24, 2025

Walkthrough

A new Vue component, PostsPageFooter.vue, was introduced, designed to serve as a dynamic footer for post listing pages. This component accepts several props related to the currently selected booru, tags, filters, and post count, and uses these to render tailored content, including tag and booru information, related tags, and alternative booru links. The footer is integrated into the main posts page ([domain].vue), where it is conditionally displayed after the main content, provided the page is not in a loading state, there is no error, and posts are available.

Changes

File(s) Change Summary
components/pages/posts/PostsPageFooter.vue Introduced a new Vue component with TypeScript, handling props, computed properties, and dynamic rendering of footer content based on selected booru, tags, and filters.
pages/posts/[domain].vue Integrated the new PostsPageFooter component at the end of the main content, passing relevant props and rendering it conditionally when not loading, no error, and posts exist.

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
Loading

Poem

In the warren of posts, a footer appears,
With tags and boorus, it brings bunny cheers!
Fresh links to explore, and filters to try,
Related tags hopping, just give them a fly.
When the loading is done, the footer will show—
A rabbit’s delight, at the page’s new glow!
🐇✨


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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 38ee007 and e9a24fb.

📒 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 ShowMore component 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.

@AlejandroAkbal AlejandroAkbal force-pushed the feat/SEO-optimization branch from 22c19f8 to 909dc92 Compare April 24, 2025 12:48
@AlejandroAkbal AlejandroAkbal merged commit 63a2ef0 into main Apr 24, 2025
1 check was pending
@AlejandroAkbal AlejandroAkbal deleted the feat/SEO-optimization branch April 24, 2025 12:51
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 22c19f8 and 909dc92.

📒 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 encodeURIComponent to handle special characters in tag names, and NuxtLink for 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 vue

Length 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].vue you’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">
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 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']
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 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.

Comment thread pages/posts/[domain].vue
Comment on lines +1067 to +1075

<PostsPageFooter
v-if="!isPending && !isError && allRows.length > 0"
:selected-booru="selectedBooru"
:selected-tags="selectedTags"
:selected-filters="selectedFilters"
:posts-count="allRows.length"
:page-title="titleForBody"
/>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
<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: ''
}
})
Suggested change
<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"
/>

@coderabbitai coderabbitai Bot mentioned this pull request May 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant