Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 159 additions & 0 deletions components/pages/posts/PostsPageFooter.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
<script lang="ts" setup>
import type { PropType } from 'vue'
import type { Domain } from '~/assets/js/domain'
import type { ITag } from '~/assets/js/tag.dto'
import { normalizeStringForTitle } from '~/assets/js/SeoHelper'

const props = defineProps({
selectedBooru: {
type: Object as PropType<Domain>,
required: true
},
selectedTags: {
type: Array as PropType<ITag[]>,
default: () => []
},
selectedFilters: {
type: Object,
default: () => ({})
},
postsCount: {
type: Number,
default: 0
}
})

const { booruList } = useBooruList()

// Filter out the current booru to show related sites
const relatedBoorus = computed(() => {
return booruList.value.filter((booru) => booru.domain !== props.selectedBooru.domain).slice(0, 4)
})

// Computed properties for formatted tag displays
const formattedTags = computed(() => {
if (!props.selectedTags.length) {
return ['Anime']
}

// Filter out excluded tags (those with a minus prefix)
return props.selectedTags.filter((tag) => !tag.name.startsWith('-')).map((tag) => normalizeStringForTitle(tag.name))
})

const formattedTagsString = computed(() => formattedTags.value.join(', '))

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


const formattedRelatedTags = computed(() => {
return hardcodedRelatedTags.map((tag) => normalizeStringForTitle(tag))
})
</script>

<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">

<article class="prose prose-sm dark:prose-invert max-w-none">
<h2>Rule 34 {{ formattedTagsString }} hentai images and videos</h2>

<section>
<h3 v-if="selectedTags.length > 0">
Exclusive {{ formattedTagsString }} Rule 34 gallery from {{ selectedBooru.domain }}
</h3>
<p>
Browse our extensive collection of high-quality
{{ formattedTagsString }} hentai, Rule 34, and anime parody artwork from {{ selectedBooru.domain }}. Our
optimized platform provides real-time access to the latest lewd images, porn videos, and adult gifs directly
from popular sources, with advanced filtering and search capabilities for the ultimate browsing experience.
<template v-if="selectedTags.length > 0">
Our library includes {{ selectedFilters.rating || 'explicit' }} rated adult media with
{{ selectedFilters.sort ? `sorting by ${selectedFilters.sort}` : 'the most popular uploads' }}.
</template>
All Rule 34 images and videos are sourced directly from {{ selectedBooru.domain }}, ensuring the highest
quality and most accurate tagging. Discover {{ postsCount > 0 ? postsCount + '+ ' : '' }}
{{ selectedBooru.domain }} {{ formattedTagsString }} hentai illustrations, porn gifs, and XXX animations in
one convenient location.
</p>
</section>

<section>
<h3>Why choose R34.app for {{ formattedTagsString }} hentai and Rule 34</h3>
<ul>
<li>Real-time adult image and porn video updates from original sources like {{ selectedBooru.domain }}</li>
<li>Instant access to new Rule 34 artwork and anime parodies as they appear</li>
<li>Mobile-optimized interface for on-the-go hentai viewing</li>
<li>Advanced filtering system with precise tag searching for Rule 34 content</li>
<li>Direct access to multiple porn booru sites in one place</li>
</ul>
</section>

<section>
<h3>Top {{ formattedTagsString }} related hentai tags</h3>
<p>Explore these popular Rule 34 and adult anime related tags across all booru sites:</p>

<nav class="flex flex-wrap gap-2">
<NuxtLink
v-for="(tag, index) in hardcodedRelatedTags"
:key="tag"
:to="`/posts/${selectedBooru.domain}?tags=${encodeURIComponent(tag)}`"
class="text-primary text-sm hover:underline"
:title="`Browse ${formattedRelatedTags[index]} hentai and Rule 34 images`"
>
{{ formattedRelatedTags[index] }}
</NuxtLink>
</nav>
</section>

<section>
<h3>More {{ formattedTagsString }} hentai sources</h3>
<p>
Expand your Rule 34 browsing experience with these alternative adult booru sites that offer similar lewd
artwork:
</p>

<nav>
<ul class="flex list-none flex-wrap gap-2">
<li
v-for="booru in relatedBoorus"
:key="booru.domain"
>
<NuxtLink
:to="`/posts/${booru.domain}${selectedTags.length ? '?tags=' + selectedTags.map((t) => encodeURIComponent(t.name)).join('|') : ''}`"
:title="`Browse ${formattedTagsString} Rule 34 hentai on ${booru.domain}`"
>
{{ booru.domain }}
</NuxtLink>
</li>
</ul>
</nav>
</section>

<section>
<h3>{{ formattedTagsString }} Rule 34 updates - always fresh hentai artwork</h3>
<p>
As a dedicated hentai viewer application, R34.app doesn't host adult media - we connect directly to
{{ selectedBooru.domain }} and other popular Rule 34 sources. This means you're always seeing the newest
{{ formattedTagsString }} porn images and adult videos in real-time, without any delay. New hentai artwork
is refreshed instantly as it appears on the original sites, ensuring you never miss new additions to your
favorite parody tags and anime categories.
</p>
</section>

<section>
<h3>
How to find the best {{ formattedTagsString }} hentai videos and porn gifs on {{ selectedBooru.domain }}
</h3>
<p>
Looking for the highest quality
{{ formattedTagsString.toLowerCase() }} hentai and Rule 34 parody artwork? Use our advanced search and
filtering options to discover exactly what you want. Sort adult images and XXX videos by rating, date, or
popularity to find the newest and best-rated uploads. Our comprehensive Rule 34 tagging system allows for
precise searches, ensuring you find exactly the lewd illustrations, porn gifs, and explicit videos you're
looking for, the moment they're uploaded to {{ selectedBooru.domain }} and other popular adult sources.
</p>
</section>
</article>
</ShowMore>
</footer>
</template>
9 changes: 9 additions & 0 deletions pages/posts/[domain].vue
Original file line number Diff line number Diff line change
Expand Up @@ -1064,5 +1064,14 @@
</div>
</div>
</section>

<PostsPageFooter
v-if="!isPending && !isError && allRows.length > 0"
:selected-booru="selectedBooru"
:selected-tags="selectedTags"
:selected-filters="selectedFilters"
:posts-count="allRows.length"
:page-title="titleForBody"
/>
Comment on lines +1067 to +1075
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"
/>

</main>
</template>