Add package.json for project setup and implement visual effects for new articles in ArticleCard component. Enhance Articles view to track and highlight new articles during updates.
This commit is contained in:
40
package.json
Normal file
40
package.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "wallamonitor",
|
||||
"version": "1.0.0",
|
||||
"description": "Scripts genéricos para Wallamonitor",
|
||||
"scripts": {
|
||||
"deploy:remote": "ssh root@10.10.11.5 'cd /root/wallabicher && git pull && docker compose build && docker compose up -d'",
|
||||
"deploy:remote:pull": "ssh root@10.10.11.5 'cd /root/wallabicher && git pull'",
|
||||
"deploy:remote:build": "ssh root@10.10.11.5 'cd /root/wallabicher && docker compose build'",
|
||||
"deploy:remote:up": "ssh root@10.10.11.5 'cd /root/wallabicher && docker compose up -d'",
|
||||
"deploy:remote:down": "ssh root@10.10.11.5 'cd /root/wallabicher && docker compose down'",
|
||||
"deploy:remote:logs": "ssh root@10.10.11.5 'cd /root/wallabicher && docker compose logs -f'",
|
||||
"deploy:remote:status": "ssh root@10.10.11.5 'cd /root/wallabicher && docker compose ps'",
|
||||
"ssh:remote": "ssh root@10.10.11.5",
|
||||
"docker:build": "docker compose build",
|
||||
"docker:up": "docker compose up -d",
|
||||
"docker:down": "docker compose down",
|
||||
"docker:logs": "docker compose logs -f",
|
||||
"docker:ps": "docker compose ps",
|
||||
"docker:restart": "docker compose restart",
|
||||
"docker:clean": "docker compose down -v && docker system prune -f",
|
||||
"backend:dev": "cd web/backend && npm run dev",
|
||||
"backend:start": "cd web/backend && npm start",
|
||||
"frontend:dev": "cd web/frontend && npm run dev",
|
||||
"frontend:build": "cd web/frontend && npm run build",
|
||||
"frontend:preview": "cd web/frontend && npm run preview",
|
||||
"install:all": "cd web/backend && npm install && cd ../frontend && npm install",
|
||||
"git:status": "git status",
|
||||
"git:pull": "git pull",
|
||||
"git:push": "git push",
|
||||
"git:commit": "git add . && git commit -m"
|
||||
},
|
||||
"keywords": [
|
||||
"wallamonitor",
|
||||
"scripts",
|
||||
"deployment"
|
||||
],
|
||||
"author": "",
|
||||
"license": "MIT"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
<template>
|
||||
<div class="card hover:shadow-lg transition-shadow">
|
||||
<div
|
||||
class="card hover:shadow-lg transition-all duration-300"
|
||||
:class="{
|
||||
'highlight-new': isNew,
|
||||
'bg-primary-50 dark:bg-primary-900/20 border-primary-300 dark:border-primary-700': isNew
|
||||
}"
|
||||
>
|
||||
<div class="flex flex-col sm:flex-row gap-3 sm:gap-4">
|
||||
<!-- Imagen del artículo -->
|
||||
<div class="flex-shrink-0 self-center sm:self-start">
|
||||
@@ -142,6 +148,10 @@ const props = defineProps({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isNew: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['remove', 'added']);
|
||||
@@ -223,3 +233,44 @@ onUnmounted(() => {
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@keyframes highlight-pulse {
|
||||
0% {
|
||||
background-color: rgb(239 246 255);
|
||||
box-shadow: 0 0 0 0 rgb(59 130 246 / 0.7), 0 4px 6px -1px rgb(0 0 0 / 0.1);
|
||||
}
|
||||
50% {
|
||||
background-color: rgb(219 234 254);
|
||||
box-shadow: 0 0 20px 5px rgb(59 130 246 / 0.5), 0 10px 15px -3px rgb(0 0 0 / 0.1);
|
||||
}
|
||||
100% {
|
||||
background-color: rgb(239 246 255);
|
||||
box-shadow: 0 0 0 0 rgb(59 130 246 / 0), 0 4px 6px -1px rgb(0 0 0 / 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes highlight-pulse-dark {
|
||||
0% {
|
||||
background-color: rgb(30 58 138 / 0.3);
|
||||
box-shadow: 0 0 0 0 rgb(96 165 250 / 0.7), 0 4px 6px -1px rgb(0 0 0 / 0.3);
|
||||
}
|
||||
50% {
|
||||
background-color: rgb(30 64 175 / 0.5);
|
||||
box-shadow: 0 0 20px 5px rgb(96 165 250 / 0.5), 0 10px 15px -3px rgb(0 0 0 / 0.3);
|
||||
}
|
||||
100% {
|
||||
background-color: rgb(30 58 138 / 0.15);
|
||||
box-shadow: 0 0 0 0 rgb(96 165 250 / 0), 0 4px 6px -1px rgb(0 0 0 / 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
.highlight-new {
|
||||
animation: highlight-pulse 2s ease-out;
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.dark .highlight-new {
|
||||
animation: highlight-pulse-dark 2s ease-out;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -213,6 +213,7 @@
|
||||
v-for="article in filteredArticles"
|
||||
:key="`${article.platform}-${article.id}`"
|
||||
:article="article"
|
||||
:is-new="newArticleIds.has(`${article.platform}-${article.id}`)"
|
||||
/>
|
||||
|
||||
<div v-if="!searchQuery" class="flex justify-center space-x-2 mt-6">
|
||||
@@ -275,6 +276,10 @@ const searchTimeout = ref(null);
|
||||
const POLL_INTERVAL = 30000; // 30 segundos
|
||||
const SEARCH_DEBOUNCE = 500; // 500ms de debounce para búsqueda
|
||||
|
||||
// Rastreo de artículos nuevos para efectos visuales
|
||||
const existingArticleIds = ref(new Set());
|
||||
const newArticleIds = ref(new Set());
|
||||
|
||||
// Facets obtenidos del backend
|
||||
const facets = ref({
|
||||
platforms: [],
|
||||
@@ -335,9 +340,24 @@ async function loadFacets() {
|
||||
|
||||
|
||||
async function loadArticles(reset = true, silent = false) {
|
||||
// Guardar IDs existentes antes de cargar (para detectar artículos nuevos en polling)
|
||||
let previousIds = new Set();
|
||||
if (silent && reset) {
|
||||
// Para polling automático, guardar los IDs de los artículos actuales antes de resetear
|
||||
allArticles.value.forEach(article => {
|
||||
previousIds.add(`${article.platform}-${article.id}`);
|
||||
});
|
||||
} else if (!reset) {
|
||||
// Para cargar más, usar los IDs ya existentes
|
||||
previousIds = new Set(existingArticleIds.value);
|
||||
}
|
||||
|
||||
if (reset) {
|
||||
offset.value = 0;
|
||||
allArticles.value = [];
|
||||
if (!silent) {
|
||||
// Solo limpiar si no es polling silencioso
|
||||
newArticleIds.value.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (!silent) {
|
||||
@@ -362,6 +382,31 @@ async function loadArticles(reset = true, silent = false) {
|
||||
filtered = filtered.filter(a => a.platform === selectedPlatform.value);
|
||||
}
|
||||
|
||||
// Si es polling silencioso, detectar artículos nuevos comparando con los anteriores
|
||||
if (silent && reset && previousIds.size > 0) {
|
||||
newArticleIds.value.clear(); // Limpiar IDs anteriores
|
||||
filtered.forEach(article => {
|
||||
const articleId = `${article.platform}-${article.id}`;
|
||||
if (!previousIds.has(articleId)) {
|
||||
newArticleIds.value.add(articleId);
|
||||
}
|
||||
});
|
||||
// Limpiar IDs de artículos nuevos después de 5 segundos
|
||||
if (newArticleIds.value.size > 0) {
|
||||
setTimeout(() => {
|
||||
newArticleIds.value.clear();
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
// Actualizar el Set de IDs existentes
|
||||
if (reset) {
|
||||
existingArticleIds.value.clear();
|
||||
}
|
||||
filtered.forEach(article => {
|
||||
existingArticleIds.value.add(`${article.platform}-${article.id}`);
|
||||
});
|
||||
|
||||
if (reset) {
|
||||
allArticles.value = filtered;
|
||||
offset.value = limit;
|
||||
|
||||
Reference in New Issue
Block a user