UniveralList
This commit is contained in:
114
biljeske/SKELETON_LIST_VIEW.md
Normal file
114
biljeske/SKELETON_LIST_VIEW.md
Normal file
@@ -0,0 +1,114 @@
|
||||
## Skeleton za List View
|
||||
|
||||
```jsx
|
||||
// src/components/common/UniversalList.jsx
|
||||
import { h } from 'preact';
|
||||
import { useEffect, useState } from 'preact/hooks';
|
||||
import { useStore } from '@nanostores/preact';
|
||||
import { getBaseUrl } from '../lib/nav';
|
||||
import LoadingSpinner from './LoadingSpinner.jsx';
|
||||
|
||||
export default function UniversalList({ store, setter, fetchMethod, limit, baseName, children }) {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const list = useStore(store);
|
||||
|
||||
// Ako je baseName poslan, dohvati URL, inače ostavi undefined
|
||||
const baseUrl = baseName ? getBaseUrl(baseName) : undefined;
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchData() {
|
||||
if (list.length > 0) {
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
const data = await fetchMethod();
|
||||
setter(data || []);
|
||||
} catch (error) {
|
||||
console.error("Greška pri dohvatu:", error);
|
||||
setter([]);
|
||||
} finally {
|
||||
setTimeout(() => setLoading(false), 1000);
|
||||
}
|
||||
}
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
if (loading) return <LoadingSpinner text="Učitavanje..." />;
|
||||
|
||||
const displayList = limit ? list.slice(0, limit) : list;
|
||||
|
||||
return (
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{/* children funkcija sada prima item i opcionalni baseUrl */}
|
||||
{displayList.map(item => children(item, baseUrl))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Loading komponenta
|
||||
|
||||
```jsx
|
||||
// src/components/common/LoadingSpinner.jsx
|
||||
import { h } from 'preact';
|
||||
|
||||
export default function LoadingSpinner({ text = "Učitavanje podataka..." }) {
|
||||
return (
|
||||
<div class="flex items-center justify-center p-12 text-gray-500">
|
||||
<div class="animate-spin mr-3 h-5 w-5 border-2 border-gray-400 border-t-transparent rounded-full"></div>
|
||||
{text}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Komponenta FleetStrojeviLista.jsx koristi Skeleton
|
||||
|
||||
```jsx
|
||||
/// src/components/fleet/FleetStrojeviLista.jsx
|
||||
import { h } from 'preact';
|
||||
import UniversalList from '../common/UniversalList.jsx';
|
||||
import { strojevi, setStrojevi } from '../stores/fleetStore';
|
||||
import { getStrojevi } from '../lib/api';
|
||||
|
||||
export default function FleetStrojeviLista({ limit = 10 }) {
|
||||
return (
|
||||
<UniversalList
|
||||
store={strojevi}
|
||||
setter={setStrojevi}
|
||||
fetchMethod={getStrojevi}
|
||||
baseName="Registrirani strojevi"
|
||||
limit={limit}
|
||||
>
|
||||
{(s, baseUrl) => (
|
||||
<div key={s.id} class="p-6 border border-gray-200 rounded-2xl bg-white shadow-sm hover:shadow-md transition-shadow">
|
||||
<div class="flex justify-between items-start mb-4">
|
||||
<h3 class="text-xl font-black text-gray-900">{s.naziv}</h3>
|
||||
<span class="px-2 py-1 bg-blue-100 text-blue-800 text-xs font-bold rounded-full uppercase">
|
||||
{s.tip_human_readable}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<ul class="text-sm text-gray-600 space-y-1 mb-4">
|
||||
<li><strong>Marka/Model:</strong> {s.marka} {s.model_stroja}</li>
|
||||
<li><strong>Serijski br:</strong> {s.serijski_broj}</li>
|
||||
<li><strong>Vlasnik:</strong> {s.vlasnik_naziv}</li>
|
||||
<li><strong>Radni sati:</strong> {s.radni_sati} h</li>
|
||||
{s.registracija && <li><strong>Reg:</strong> {s.registracija}</li>}
|
||||
</ul>
|
||||
|
||||
<a
|
||||
href={`${baseUrl}/${s.id}`}
|
||||
class="block text-center w-full py-2 bg-gray-900 text-white rounded-lg hover:bg-gray-700 transition"
|
||||
>
|
||||
Pregled detalja
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</UniversalList>
|
||||
);
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user