Kitap arama lsitesi z-index düzenlendi.
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
|||||||
CardActionArea,
|
CardActionArea,
|
||||||
CardContent,
|
CardContent,
|
||||||
CardMedia,
|
CardMedia,
|
||||||
|
ClickAwayListener,
|
||||||
Divider,
|
Divider,
|
||||||
Grid,
|
Grid,
|
||||||
LinearProgress,
|
LinearProgress,
|
||||||
@@ -43,6 +44,7 @@ const UploadStep = () => {
|
|||||||
const [searchError, setSearchError] = useState(null);
|
const [searchError, setSearchError] = useState(null);
|
||||||
const [selectedBookId, setSelectedBookId] = useState(bookMetadata?.id || null);
|
const [selectedBookId, setSelectedBookId] = useState(bookMetadata?.id || null);
|
||||||
const skipSearchRef = useRef(false);
|
const skipSearchRef = useRef(false);
|
||||||
|
const [showResults, setShowResults] = useState(false);
|
||||||
|
|
||||||
const onDrop = useCallback(
|
const onDrop = useCallback(
|
||||||
(acceptedFiles) => {
|
(acceptedFiles) => {
|
||||||
@@ -110,6 +112,7 @@ const UploadStep = () => {
|
|||||||
setSearchResults([]);
|
setSearchResults([]);
|
||||||
setSearchError(null);
|
setSearchError(null);
|
||||||
setSearching(false);
|
setSearching(false);
|
||||||
|
setShowResults(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
@@ -128,6 +131,7 @@ const UploadStep = () => {
|
|||||||
const items = Array.isArray(payload.items) ? payload.items : [];
|
const items = Array.isArray(payload.items) ? payload.items : [];
|
||||||
const normalized = items.map((item) => normalizeVolume(item));
|
const normalized = items.map((item) => normalizeVolume(item));
|
||||||
setSearchResults(normalized);
|
setSearchResults(normalized);
|
||||||
|
setShowResults(Boolean(normalized.length));
|
||||||
if (!normalized.length) {
|
if (!normalized.length) {
|
||||||
setSearchError('Bu başlıkla eşleşen bir kayıt bulunamadı.');
|
setSearchError('Bu başlıkla eşleşen bir kayıt bulunamadı.');
|
||||||
}
|
}
|
||||||
@@ -135,6 +139,7 @@ const UploadStep = () => {
|
|||||||
if (controller.signal.aborted) return;
|
if (controller.signal.aborted) return;
|
||||||
setSearchResults([]);
|
setSearchResults([]);
|
||||||
setSearchError(error.message || 'Google Books araması başarısız oldu.');
|
setSearchError(error.message || 'Google Books araması başarısız oldu.');
|
||||||
|
setShowResults(false);
|
||||||
} finally {
|
} finally {
|
||||||
if (!controller.signal.aborted) {
|
if (!controller.signal.aborted) {
|
||||||
setSearching(false);
|
setSearching(false);
|
||||||
@@ -164,10 +169,12 @@ const UploadStep = () => {
|
|||||||
setSelectedBookId(null);
|
setSelectedBookId(null);
|
||||||
setSearchResults([]);
|
setSearchResults([]);
|
||||||
setSearchError(null);
|
setSearchError(null);
|
||||||
|
setShowResults(false);
|
||||||
} else if (bookMetadata && bookMetadata.title !== value) {
|
} else if (bookMetadata && bookMetadata.title !== value) {
|
||||||
setBookMetadata(null);
|
setBookMetadata(null);
|
||||||
setSelectedBookId(null);
|
setSelectedBookId(null);
|
||||||
}
|
}
|
||||||
|
setShowResults(Boolean(value?.trim()));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSelectBook = (book) => {
|
const handleSelectBook = (book) => {
|
||||||
@@ -177,6 +184,7 @@ const UploadStep = () => {
|
|||||||
setBookTitle(book.title || '');
|
setBookTitle(book.title || '');
|
||||||
setSearchResults([]);
|
setSearchResults([]);
|
||||||
setSearchError(null);
|
setSearchError(null);
|
||||||
|
setShowResults(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectedBookSummary = useMemo(() => {
|
const selectedBookSummary = useMemo(() => {
|
||||||
@@ -200,17 +208,144 @@ const UploadStep = () => {
|
|||||||
{bookMetadata.authors?.length ? ` • ${bookMetadata.authors.join(', ')}` : ''}
|
{bookMetadata.authors?.length ? ` • ${bookMetadata.authors.join(', ')}` : ''}
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
<Box>
|
<Box sx={{ position: 'relative', zIndex: 1 }}>
|
||||||
<Typography variant="h6" gutterBottom>
|
<Typography variant="h6" gutterBottom>
|
||||||
Kitap adı
|
Kitap adı
|
||||||
</Typography>
|
</Typography>
|
||||||
<TextField
|
<ClickAwayListener onClickAway={() => setShowResults(false)}>
|
||||||
fullWidth
|
<Box sx={{ position: 'relative' }}>
|
||||||
placeholder="Örn. Yapay Zeka İmparatorluğu"
|
<TextField
|
||||||
value={bookTitle}
|
fullWidth
|
||||||
onChange={handleTitleChange}
|
placeholder="Örn. Yapay Zeka İmparatorluğu"
|
||||||
InputProps={{ sx: { borderRadius: 2 } }}
|
value={bookTitle}
|
||||||
/>
|
onChange={handleTitleChange}
|
||||||
|
onFocus={() => searchResults.length && setShowResults(true)}
|
||||||
|
InputProps={{ sx: { borderRadius: 2 } }}
|
||||||
|
/>
|
||||||
|
{showResults && searchResults.length > 0 && bookTitle?.trim() && (
|
||||||
|
<Paper
|
||||||
|
variant="outlined"
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: 'calc(100% + 8px)',
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
borderRadius: 1.2,
|
||||||
|
zIndex: 10,
|
||||||
|
maxHeight: 420,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
overflow: 'hidden',
|
||||||
|
boxShadow: (theme) => theme.shadows[6],
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="subtitle2" sx={{ px: 2, pt: 2, pb: 1, color: 'text.secondary' }}>
|
||||||
|
Google Books sonuçları
|
||||||
|
</Typography>
|
||||||
|
<Divider />
|
||||||
|
<Box sx={{ flex: 1, overflowY: 'auto', pr: 1.5 }}>
|
||||||
|
<Stack divider={<Divider />} spacing={0}>
|
||||||
|
{searchResults.map((book) => {
|
||||||
|
const detailLine = [
|
||||||
|
book.publisher,
|
||||||
|
book.publishedDate,
|
||||||
|
book.pageCount ? `${book.pageCount} sayfa` : null,
|
||||||
|
]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(' • ');
|
||||||
|
const ratingLine = [
|
||||||
|
book.averageRating ? `Puan ${book.averageRating}/5` : null,
|
||||||
|
book.ratingsCount ? `${book.ratingsCount} oy` : null,
|
||||||
|
book.language ? book.language.toUpperCase() : null,
|
||||||
|
]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(' • ');
|
||||||
|
const isSelected = selectedBookId === book.id;
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
key={book.id}
|
||||||
|
role="button"
|
||||||
|
onClick={() => handleSelectBook(book)}
|
||||||
|
sx={{
|
||||||
|
px: 2,
|
||||||
|
py: 2,
|
||||||
|
display: 'flex',
|
||||||
|
gap: 2,
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
cursor: 'pointer',
|
||||||
|
bgcolor: isSelected ? 'rgba(231,193,121,0.15)' : 'transparent',
|
||||||
|
transition: 'background-color 0.2s ease',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: 64,
|
||||||
|
height: 96,
|
||||||
|
borderRadius: 0.3,
|
||||||
|
overflow: 'hidden',
|
||||||
|
bgcolor: '#f0ece4',
|
||||||
|
flexShrink: 0,
|
||||||
|
border: '1px solid',
|
||||||
|
borderColor: 'divider',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{book.thumbnail ? (
|
||||||
|
<Box
|
||||||
|
component="img"
|
||||||
|
src={book.thumbnail}
|
||||||
|
alt={`${book.title} kapak görseli`}
|
||||||
|
sx={{ width: '100%', height: '100%', objectFit: 'cover' }}
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Stack alignItems="center" justifyContent="center" sx={{ height: '100%' }}>
|
||||||
|
<Typography variant="caption" color="text.secondary">
|
||||||
|
Kapak yok
|
||||||
|
</Typography>
|
||||||
|
</Stack>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Typography variant="subtitle1" sx={{ fontWeight: 600 }}>
|
||||||
|
{book.title}
|
||||||
|
</Typography>
|
||||||
|
{book.subtitle && (
|
||||||
|
<Typography variant="body2" color="text.secondary">
|
||||||
|
{book.subtitle}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
color="text.secondary"
|
||||||
|
sx={{ fontStyle: 'italic', mt: 0.5 }}
|
||||||
|
>
|
||||||
|
{book.authors?.length ? book.authors.join(', ') : 'Yazar bilgisi bulunamadı'}
|
||||||
|
</Typography>
|
||||||
|
{detailLine && (
|
||||||
|
<Typography variant="caption" color="text.secondary" display="block" mt={0.5}>
|
||||||
|
{detailLine}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
{ratingLine && (
|
||||||
|
<Typography variant="caption" color="text.secondary" display="block">
|
||||||
|
{ratingLine}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
{book.categories?.length > 0 && (
|
||||||
|
<Typography variant="caption" color="text.secondary" display="block" mt={0.5}>
|
||||||
|
{book.categories.join(', ')}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
</Paper>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</ClickAwayListener>
|
||||||
<Typography variant="body2" color="text.secondary" mt={1}>
|
<Typography variant="body2" color="text.secondary" mt={1}>
|
||||||
Google Books veritabanında arama yapmak için kitap adını yaz. Seçtiğin kaydın tüm meta bilgileri EPUB'a işlenecek.
|
Google Books veritabanında arama yapmak için kitap adını yaz. Seçtiğin kaydın tüm meta bilgileri EPUB'a işlenecek.
|
||||||
</Typography>
|
</Typography>
|
||||||
@@ -220,111 +355,6 @@ const UploadStep = () => {
|
|||||||
{searchError}
|
{searchError}
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
{searchResults.length > 0 && bookTitle?.trim() && (
|
|
||||||
<Paper variant="outlined" sx={{ mt: 2 }}>
|
|
||||||
<Typography variant="subtitle2" sx={{ px: 2, pt: 2, pb: 1, color: 'text.secondary' }}>
|
|
||||||
Google Books sonuçları
|
|
||||||
</Typography>
|
|
||||||
<Divider />
|
|
||||||
<Stack divider={<Divider />} spacing={0}>
|
|
||||||
{searchResults.map((book) => {
|
|
||||||
const detailLine = [
|
|
||||||
book.publisher,
|
|
||||||
book.publishedDate,
|
|
||||||
book.pageCount ? `${book.pageCount} sayfa` : null,
|
|
||||||
]
|
|
||||||
.filter(Boolean)
|
|
||||||
.join(' • ');
|
|
||||||
const ratingLine = [
|
|
||||||
book.averageRating ? `Puan ${book.averageRating}/5` : null,
|
|
||||||
book.ratingsCount ? `${book.ratingsCount} oy` : null,
|
|
||||||
book.language ? book.language.toUpperCase() : null,
|
|
||||||
]
|
|
||||||
.filter(Boolean)
|
|
||||||
.join(' • ');
|
|
||||||
const isSelected = selectedBookId === book.id;
|
|
||||||
return (
|
|
||||||
<Box
|
|
||||||
key={book.id}
|
|
||||||
role="button"
|
|
||||||
onClick={() => handleSelectBook(book)}
|
|
||||||
sx={{
|
|
||||||
px: 2,
|
|
||||||
py: 2,
|
|
||||||
display: 'flex',
|
|
||||||
gap: 2,
|
|
||||||
alignItems: 'flex-start',
|
|
||||||
cursor: 'pointer',
|
|
||||||
bgcolor: isSelected ? 'rgba(231,193,121,0.15)' : 'transparent',
|
|
||||||
transition: 'background-color 0.2s ease',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
width: 64,
|
|
||||||
height: 96,
|
|
||||||
borderRadius: 0.3,
|
|
||||||
overflow: 'hidden',
|
|
||||||
bgcolor: '#f0ece4',
|
|
||||||
flexShrink: 0,
|
|
||||||
border: '1px solid',
|
|
||||||
borderColor: 'divider',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{book.thumbnail ? (
|
|
||||||
<Box
|
|
||||||
component="img"
|
|
||||||
src={book.thumbnail}
|
|
||||||
alt={`${book.title} kapak görseli`}
|
|
||||||
sx={{ width: '100%', height: '100%', objectFit: 'cover' }}
|
|
||||||
loading="lazy"
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<Stack alignItems="center" justifyContent="center" sx={{ height: '100%' }}>
|
|
||||||
<Typography variant="caption" color="text.secondary">
|
|
||||||
Kapak yok
|
|
||||||
</Typography>
|
|
||||||
</Stack>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
<Box>
|
|
||||||
<Typography variant="subtitle1" sx={{ fontWeight: 600 }}>
|
|
||||||
{book.title}
|
|
||||||
</Typography>
|
|
||||||
{book.subtitle && (
|
|
||||||
<Typography variant="body2" color="text.secondary">
|
|
||||||
{book.subtitle}
|
|
||||||
</Typography>
|
|
||||||
)}
|
|
||||||
<Typography
|
|
||||||
variant="body2"
|
|
||||||
color="text.secondary"
|
|
||||||
sx={{ fontStyle: 'italic', mt: 0.5 }}
|
|
||||||
>
|
|
||||||
{book.authors?.length ? book.authors.join(', ') : 'Yazar bilgisi bulunamadı'}
|
|
||||||
</Typography>
|
|
||||||
{detailLine && (
|
|
||||||
<Typography variant="caption" color="text.secondary" display="block" mt={0.5}>
|
|
||||||
{detailLine}
|
|
||||||
</Typography>
|
|
||||||
)}
|
|
||||||
{ratingLine && (
|
|
||||||
<Typography variant="caption" color="text.secondary" display="block">
|
|
||||||
{ratingLine}
|
|
||||||
</Typography>
|
|
||||||
)}
|
|
||||||
{book.categories?.length > 0 && (
|
|
||||||
<Typography variant="caption" color="text.secondary" display="block" mt={0.5}>
|
|
||||||
{book.categories.join(', ')}
|
|
||||||
</Typography>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Stack>
|
|
||||||
</Paper>
|
|
||||||
)}
|
|
||||||
</Box>
|
</Box>
|
||||||
<Box {...getRootProps()} sx={dropzoneStyle}>
|
<Box {...getRootProps()} sx={dropzoneStyle}>
|
||||||
<input {...getInputProps()} />
|
<input {...getInputProps()} />
|
||||||
|
|||||||
Reference in New Issue
Block a user