mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-20 07:26:19 +00:00
🆙 Cleanup
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
import { FC, useCallback, useEffect, useState } from 'react';
|
||||
import { FaSearch } from 'react-icons/fa';
|
||||
import { Column, Text } from '../../../common';
|
||||
import { LayoutFurniIconImageView } from '../../../common/layout/LayoutFurniIconImageView';
|
||||
import { Button, Column, Flex, Text } from '../../../common';
|
||||
import { FurniItem } from '../../../hooks/furni-editor';
|
||||
|
||||
interface FurniEditorSearchViewProps
|
||||
@@ -14,8 +12,6 @@ interface FurniEditorSearchViewProps
|
||||
onSelect: (id: number) => void;
|
||||
}
|
||||
|
||||
const inputClass = 'text-[14px] border border-[#c5cdd6] rounded px-2 py-1.5 bg-white focus:outline-none focus:border-[#1e7295] transition-colors w-full';
|
||||
|
||||
export const FurniEditorSearchView: FC<FurniEditorSearchViewProps> = props =>
|
||||
{
|
||||
const { items, total, page, loading, onSearch, onSelect } = props;
|
||||
@@ -41,122 +37,97 @@ export const FurniEditorSearchView: FC<FurniEditorSearchViewProps> = props =>
|
||||
|
||||
return (
|
||||
<Column gap={ 1 } className="h-full">
|
||||
{ /* Search Bar */ }
|
||||
<div className="flex gap-2 items-end">
|
||||
<div className="flex-1">
|
||||
<label className="text-[12px] text-[#1e7295] uppercase font-bold mb-0.5 block">Search</label>
|
||||
<Flex gap={ 1 } alignItems="end">
|
||||
<Column gap={ 0 } className="flex-1">
|
||||
<Text small bold>Search</Text>
|
||||
<input
|
||||
type="text"
|
||||
className={ inputClass }
|
||||
className="form-control form-control-sm"
|
||||
placeholder="ID, name or sprite ID..."
|
||||
value={ query }
|
||||
onChange={ e => setQuery(e.target.value) }
|
||||
onKeyDown={ handleKeyDown }
|
||||
/>
|
||||
</div>
|
||||
<div className="w-[100px]">
|
||||
<label className="text-[12px] text-[#1e7295] uppercase font-bold mb-0.5 block">Type</label>
|
||||
<select className={ inputClass } value={ typeFilter } onChange={ e => setTypeFilter(e.target.value) }>
|
||||
</Column>
|
||||
<Column gap={ 0 } className="w-[80px]">
|
||||
<Text small bold>Type</Text>
|
||||
<select
|
||||
className="form-select form-select-sm"
|
||||
value={ typeFilter }
|
||||
onChange={ e => setTypeFilter(e.target.value) }
|
||||
>
|
||||
<option value="">All</option>
|
||||
<option value="s">Floor</option>
|
||||
<option value="i">Wall</option>
|
||||
<option value="s">Floor (s)</option>
|
||||
<option value="i">Wall (i)</option>
|
||||
</select>
|
||||
</div>
|
||||
<button
|
||||
className="flex items-center gap-1.5 px-4 py-1.5 rounded text-[13px] font-bold bg-[#1e7295] text-white hover:bg-[#185d79] transition-colors cursor-pointer disabled:opacity-50"
|
||||
disabled={ loading }
|
||||
onClick={ handleSearch }
|
||||
>
|
||||
<FaSearch className="text-[11px]" /> { loading ? '...' : 'Search' }
|
||||
</button>
|
||||
</div>
|
||||
</Column>
|
||||
<Button variant="primary" disabled={ loading } onClick={ handleSearch }>
|
||||
{ loading ? '...' : 'Search' }
|
||||
</Button>
|
||||
</Flex>
|
||||
|
||||
{ /* Results counter */ }
|
||||
{ total > 0 &&
|
||||
<div className="text-[13px] text-[#4a5568]">
|
||||
<b className="text-[#1e7295]">{ total }</b> items found { totalPages > 1 && <span>- Page <b>{ page }</b>/{ totalPages }</span> }
|
||||
</div>
|
||||
}
|
||||
|
||||
{ /* Results Table */ }
|
||||
<div className="flex-1 overflow-auto border border-[#c5cdd6] rounded bg-white">
|
||||
{ loading &&
|
||||
<div className="flex items-center justify-center py-8">
|
||||
<div className="text-[14px] text-[#4a5568] animate-pulse">Loading...</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
{ !loading && items.length === 0 &&
|
||||
<div className="flex items-center justify-center py-8 text-[14px] text-[#4a5568]">
|
||||
No items found
|
||||
</div>
|
||||
}
|
||||
|
||||
{ !loading && items.length > 0 &&
|
||||
<table className="w-full text-[14px]">
|
||||
<thead>
|
||||
<tr className="bg-[#f0f4f7] sticky top-0 text-[12px] text-[#1e7295] uppercase font-bold">
|
||||
<th className="px-2 py-2 text-center w-[44px]"></th>
|
||||
<th className="px-2 py-2 text-left w-[55px]">ID</th>
|
||||
<th className="px-2 py-2 text-left w-[60px]">Sprite</th>
|
||||
<th className="px-2 py-2 text-left">Name</th>
|
||||
<th className="px-2 py-2 text-left">Public Name</th>
|
||||
<th className="px-2 py-2 text-center w-[60px]">Type</th>
|
||||
<th className="px-2 py-2 text-left">Interaction</th>
|
||||
<Column gap={ 0 } className="flex-1 overflow-auto border border-[#ccc] rounded bg-white">
|
||||
<table className="w-full text-xs">
|
||||
<thead>
|
||||
<tr className="bg-[#e8e8e8] sticky top-0">
|
||||
<th className="px-2 py-1 text-left">ID</th>
|
||||
<th className="px-2 py-1 text-left">Sprite</th>
|
||||
<th className="px-2 py-1 text-left">Name</th>
|
||||
<th className="px-2 py-1 text-left">Public Name</th>
|
||||
<th className="px-2 py-1 text-center">Type</th>
|
||||
<th className="px-2 py-1 text-left">Interaction</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{ items.map(item => (
|
||||
<tr
|
||||
key={ item.id }
|
||||
className="cursor-pointer hover:bg-[#d4edfa] border-b border-[#eee] transition-colors"
|
||||
onClick={ () => onSelect(item.id) }
|
||||
>
|
||||
<td className="px-2 py-1 font-mono">{ item.id }</td>
|
||||
<td className="px-2 py-1 font-mono">{ item.spriteId }</td>
|
||||
<td className="px-2 py-1 truncate max-w-[120px]">{ item.itemName }</td>
|
||||
<td className="px-2 py-1 truncate max-w-[120px]">{ item.publicName }</td>
|
||||
<td className="px-2 py-1 text-center">
|
||||
<span className={ `px-1 rounded text-white text-[10px] ${ item.type === 's' ? 'bg-[#1e7295]' : 'bg-[#6b7280]' }` }>
|
||||
{ item.type === 's' ? 'Floor' : 'Wall' }
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-2 py-1 text-[10px]">{ item.interactionType || '-' }</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{ items.map(item => (
|
||||
<tr
|
||||
key={ item.id }
|
||||
className="cursor-pointer hover:bg-[#e8f4fb] border-b border-[#f0f0f0] transition-colors"
|
||||
onClick={ () => onSelect(item.id) }
|
||||
>
|
||||
<td className="px-2 py-1 text-center">
|
||||
<div className="w-[34px] h-[34px] flex items-center justify-center mx-auto">
|
||||
<LayoutFurniIconImageView productType={ item.type } productClassId={ item.spriteId } />
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2 py-1 font-mono text-[14px] text-[#1e7295] font-bold">{ item.id }</td>
|
||||
<td className="px-2 py-1 font-mono text-[14px] text-[#4a5568]">{ item.spriteId }</td>
|
||||
<td className="px-2 py-1 text-[14px] text-[#2d3748] truncate max-w-[130px]">{ item.itemName }</td>
|
||||
<td className="px-2 py-1 text-[14px] text-[#2d3748] truncate max-w-[130px]">{ item.publicName }</td>
|
||||
<td className="px-2 py-1 text-center">
|
||||
<span className={ `px-2 py-0.5 rounded text-white text-[11px] font-bold ${ item.type === 's' ? 'bg-[#1e7295]' : 'bg-[#718096]' }` }>
|
||||
{ item.type === 's' ? 'Floor' : 'Wall' }
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-2 py-1 text-[14px] text-[#4a5568]">{ item.interactionType || '-' }</td>
|
||||
</tr>
|
||||
)) }
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
</div>
|
||||
)) }
|
||||
{ items.length === 0 && !loading &&
|
||||
<tr>
|
||||
<td colSpan={ 6 } className="px-2 py-4 text-center text-[#999]">No items found</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</Column>
|
||||
|
||||
{ /* Pagination */ }
|
||||
{ totalPages > 1 &&
|
||||
<div className="flex justify-between items-center">
|
||||
<div className="text-[13px] text-[#4a5568]">
|
||||
Page <b>{ page }</b> of <b>{ totalPages }</b>
|
||||
</div>
|
||||
<div className="flex gap-1.5">
|
||||
<button
|
||||
className="px-3 py-1.5 rounded text-[13px] font-bold bg-[#edf2f7] hover:bg-[#e2e8f0] text-[#4a5568] transition-colors cursor-pointer disabled:opacity-40"
|
||||
<Flex gap={ 1 } justifyContent="between" alignItems="center">
|
||||
<Text small variant="gray">
|
||||
{ total } items - Page { page }/{ totalPages }
|
||||
</Text>
|
||||
<Flex gap={ 1 }>
|
||||
<Button
|
||||
variant="secondary"
|
||||
disabled={ page <= 1 }
|
||||
onClick={ () => onSearch(query, typeFilter, page - 1) }
|
||||
>
|
||||
Prev
|
||||
</button>
|
||||
<button
|
||||
className="px-3 py-1.5 rounded text-[13px] font-bold bg-[#edf2f7] hover:bg-[#e2e8f0] text-[#4a5568] transition-colors cursor-pointer disabled:opacity-40"
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
disabled={ page >= totalPages }
|
||||
onClick={ () => onSearch(query, typeFilter, page + 1) }
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Button>
|
||||
</Flex>
|
||||
</Flex>
|
||||
}
|
||||
</Column>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user