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
17 changes: 10 additions & 7 deletions app/Services/ComputerScienceResourceService.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use App\Exceptions\Resources\ResourceAlreadyCreatedException;
use App\Exceptions\Resources\ResourceInvalidTabException;
use App\Models\ComputerScienceResource;
use App\Models\NewsPost;
use App\Models\ResourceEdits;
use App\Models\ResourceReview;
use App\Services\SortingManagers\ResourceSortingManager;
Expand All @@ -18,6 +17,7 @@

class ComputerScienceResourceService
{
// TODO: Make a service for ComputerScienceResources
public function __construct(
protected CommentService $commentService,
protected UpvoteService $upvoteService,
Expand All @@ -36,19 +36,22 @@ public function __construct(
*/
public function getIndexData(Request $request): array
{
$query = ComputerScienceResource::query();
$resources_query = ComputerScienceResource::query();

// Apply filters and sorting through the dedicated filter service
$filters = $request->query();
$query = $this->filterService->applyFilters($query, $filters);
$resources_query = $this->filterService->applyFilters($resources_query, $filters);

$resources = $query->paginate(20)->appends($request->query());
$resources = $resources_query->paginate(20)->appends($request->query());

$news = NewsPost::limit(10)->get();
// TODO (TEMP): will replace with user activity or something

$hot_resources_query = ComputerScienceResource::query()->with(['tags', 'votes', 'upvoteSummary', 'reviewSummary', 'commentsCountRelationship']);
$hot_resources = $this->resourceSortingManager->applySort($hot_resources_query, 'hot')->limit(10)->get();

return [
'resources' => $resources,
'news_posts' => $news,
'hot_resources' => $hot_resources,
];
}

Expand Down Expand Up @@ -152,7 +155,7 @@ function () use ($computerScienceResource, $sortBy, $request) {
function () use ($computerScienceResource, $sortBy, $request) {
try {
$query = ResourceEdits::whereBelongsTo($computerScienceResource);
$query = $this->resourceSortingManager->applySort($query, $sortBy, ResourceEdits::class);
$query = $this->resourceSortingManager->applySort($query, $sortBy);

return $query->with('user')->paginate(10)->appends($request->query());
} catch (Throwable $e) {
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 7 additions & 7 deletions resources/js/Components/News/NewsDialog.vue
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<script setup>
import DialogModal from '@/Components/DialogModal.vue';
import NewsItem from "@/Components/NewsItem.vue";
import TrendingResourceItem from "@/Components/TrendingResourceItem.vue";
import { Icon } from "@iconify/vue";

defineProps({
show: {
type: Boolean,
required: true
},
newsItems: {
resourceItems: {
type: Array,
required: true
}
Expand All @@ -21,18 +21,18 @@ defineEmits(['close']);
<DialogModal :show="show" @close="$emit('close')" max-width="lg">
<template #title>
<div class="bg-secondary dark:bg-gray-700 -m-6 p-6 mb-0 flex items-center gap-2">
<Icon icon="mdi:newspaper" class="w-6 h-6 text-primary dark:text-white" />
<h2 class="text-xl font-bold text-primary dark:text-white">Latest News</h2>
<Icon icon="mdi:trending-up" class="w-6 h-6 text-primary dark:text-white" />
<h2 class="text-xl font-bold text-primary dark:text-white">Trending Resources</h2>
</div>
</template>

<template #content>
<div class="divide-y divide-secondary dark:divide-gray-700 -mx-6">
<div class="space-y-0 max-h-[60vh] overflow-y-auto">
<NewsItem
v-for="(news, index) in newsItems"
<TrendingResourceItem
v-for="(resource, index) in resourceItems"
:key="index"
:news="news"
:resource="resource"
class="px-6 hover:bg-secondary/50 dark:hover:bg-gray-700/50 transition-colors duration-200"
/>
</div>
Expand Down
32 changes: 16 additions & 16 deletions resources/js/Components/News/NewsSection.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<script setup>
import { ref } from "vue";
import NewsItem from "@/Components/NewsItem.vue";
import TrendingResourceItem from "@/Components/TrendingResourceItem.vue";
import NewsDialog from "@/Components/News/NewsDialog.vue";
import { Icon } from "@iconify/vue";
import EmptyState from "../EmptyState.vue";

const props = defineProps({
newsPosts: {
hotResources: {
type: Array,
required: true,
},
Expand All @@ -16,41 +16,41 @@ const showNewsDialog = ref(false);
</script>

<template>
<!-- News Section - Desktop -->
<!-- Trending Resources Section - Desktop -->
<aside
class="hidden h-fit lg:block w-1/4 bg-white dark:bg-gray-800 overflow-hidden shadow-xl sm:rounded-lg p-6"
>
<div
class="bg-secondary dark:bg-gray-700 -m-6 p-4 mb-0 flex items-center gap-2"
>
<Icon
icon="mdi:newspaper"
icon="mdi:trending-up"
class="w-6 h-6 text-primary dark:text-white"
/>
<h2 class="font-bold text-primary dark:text-white">Latest News</h2>
<h2 class="font-bold text-primary dark:text-white">Trending Resources</h2>
</div>
<div class="space-y-4" v-if="newsPosts.length > 0">
<NewsItem
v-for="(news, index) in newsPosts"
<div class="space-y-4" v-if="hotResources.length > 0">
<TrendingResourceItem
v-for="(resource, index) in hotResources"
:key="index"
:news="news"
:resource="resource"
/>
</div>
<EmptyState class="mt-6" v-else icon="mdi-newspaper" title="No Recent News" />
<EmptyState class="mt-6" v-else icon="mdi:trending-up" title="No Trending Resources" />
</aside>

<!-- News Button - Mobile -->
<!-- Trending Resources Button - Mobile -->
<button
class="fixed bottom-4 right-4 lg:hidden bg-primary text-white rounded-full p-4 shadow-lg hover:bg-primaryDark focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary z-50"
@click="showNewsDialog = true"
>
<Icon icon="mdi:newspaper" class="w-6 h-6" />
<Icon icon="mdi:trending-up" class="w-6 h-6" />
</button>

<!-- News Dialog for Mobile -->
<NewsDialog
<!-- Trending Resources Dialog for Mobile -->
<!-- <NewsDialog
:show="showNewsDialog"
:news-items="newsPosts"
:resource-items="hotResources"
@close="showNewsDialog = false"
/>
/> -->
</template>
27 changes: 0 additions & 27 deletions resources/js/Components/NewsItem.vue

This file was deleted.

41 changes: 41 additions & 0 deletions resources/js/Components/TrendingResourceItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<script setup>
import { Link } from '@inertiajs/vue3';

defineProps({
resource: {
type: Object,
required: true,
},
});
</script>

<template>
<Link :href="route('resources.show', { slug: resource.slug }) || '#'" target="_blank" rel="noopener noreferrer">
<div class="my-4 border hover:bg-gray-50 dark:hover:bg-gray-700 p-2 rounded-sm transition-colors cursor-pointer">
<div class="flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400 mb-1">
<span v-if="resource.upvotes_count || resource.vote_score" class="flex items-center gap-1">
<svg class="w-4 h-4 text-orange-500" fill="currentColor" viewBox="0 0 20 20">
<path d="M2 10.5a1.5 1.5 0 113 0v6a1.5 1.5 0 01-3 0v-6zM6 10.333v5.43a2 2 0 001.106 1.79l.05.025A4 4 0 008.943 18h5.416a2 2 0 001.962-1.608l1.2-6A2 2 0 0015.56 8H12V4a2 2 0 00-2-2 1 1 0 00-1 1v.667a4 4 0 01-.8 2.4L6.8 7.933a4 4 0 00-.8 2.4z" />
</svg>
{{ resource.upvotes_count || resource.vote_score }}
</span>
</div>

<h3 class="font-bold mb-2 text-md dark:text-white line-clamp-2">
{{ resource.name }}
</h3>

<img
v-if="resource.image_url"
:src="resource.image_url"
:alt="resource.name"
class="w-full h-32 object-cover rounded mb-2"
/>

<p class="text-sm text-gray-600 dark:text-gray-300 line-clamp-3 mb-2">
{{ resource.excerpt || resource.description }}
</p>

</div>
</Link>
</template>
5 changes: 3 additions & 2 deletions resources/js/Pages/Resources/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import ResourcesTable from "@/Components/Resources/ResourcesTable.vue";
import NewsSection from "@/Components/News/NewsSection.vue";
const props = defineProps({
resources: Object,
news_posts: Array,
hot_resources: Array,
});

</script>
Expand Down Expand Up @@ -36,7 +36,8 @@ const props = defineProps({
<ResourcesTable :resources="props.resources" />
</section>

<NewsSection :news-posts="news_posts" />
<!-- Trending Resources Section -->
<NewsSection :hot-resources="props.hot_resources" />
</div>
</div>
</AppLayout>
Expand Down