diff --git a/.sqlx/query-05d7a87d04e669dc8ed1a1152be390d5abfdd0cf202744c65597aec1f2f03ff1.json b/.sqlx/query-05d7a87d04e669dc8ed1a1152be390d5abfdd0cf202744c65597aec1f2f03ff1.json deleted file mode 100644 index 01fef587..00000000 --- a/.sqlx/query-05d7a87d04e669dc8ed1a1152be390d5abfdd0cf202744c65597aec1f2f03ff1.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "db_name": "SQLite", - "query": "SELECT DISTINCT minter_did FROM nfts WHERE minter_did IS NOT NULL", - "describe": { - "columns": [ - { - "name": "minter_did", - "ordinal": 0, - "type_info": "Blob" - } - ], - "parameters": { - "Right": 0 - }, - "nullable": [ - true - ] - }, - "hash": "05d7a87d04e669dc8ed1a1152be390d5abfdd0cf202744c65597aec1f2f03ff1" -} diff --git a/.sqlx/query-0df4d6f44db6d5a751b180496df02a627dc5d84bec1519e0779dc61c13ab0a26.json b/.sqlx/query-06597c3a99e3ac6448ef9ab5f46f7e80b9e84294af7b626712e4f13a7f23468b.json similarity index 57% rename from .sqlx/query-0df4d6f44db6d5a751b180496df02a627dc5d84bec1519e0779dc61c13ab0a26.json rename to .sqlx/query-06597c3a99e3ac6448ef9ab5f46f7e80b9e84294af7b626712e4f13a7f23468b.json index ce3643a2..93bef207 100644 --- a/.sqlx/query-0df4d6f44db6d5a751b180496df02a627dc5d84bec1519e0779dc61c13ab0a26.json +++ b/.sqlx/query-06597c3a99e3ac6448ef9ab5f46f7e80b9e84294af7b626712e4f13a7f23468b.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "\n SELECT `collection_id`, `did_id`, `metadata_collection_id`, `visible`, `name`, `icon`\n FROM `collections` INDEXED BY `col_name`\n ORDER BY `visible` DESC, `is_named` DESC, `name` ASC, `collection_id` ASC\n LIMIT ? OFFSET ?\n ", + "query": "\n SELECT \n collection_id, \n did_id, \n metadata_collection_id, \n visible, \n name, \n icon,\n COUNT(*) OVER() as total_count\n FROM collections INDEXED BY col_name\n ORDER BY visible DESC, is_named DESC, name ASC, collection_id ASC\n LIMIT ? OFFSET ?\n ", "describe": { "columns": [ { @@ -32,6 +32,11 @@ "name": "icon", "ordinal": 5, "type_info": "Text" + }, + { + "name": "total_count", + "ordinal": 6, + "type_info": "Integer" } ], "parameters": { @@ -43,8 +48,9 @@ false, false, true, - true + true, + false ] }, - "hash": "0df4d6f44db6d5a751b180496df02a627dc5d84bec1519e0779dc61c13ab0a26" + "hash": "06597c3a99e3ac6448ef9ab5f46f7e80b9e84294af7b626712e4f13a7f23468b" } diff --git a/.sqlx/query-fd9f732f3a7ed809b9d4c2ededebdeeb3765c89c9fc78576f447c646c46f445c.json b/.sqlx/query-b4ad9892410265bb0a06e51d8de8eb35e1c2bcfb1a276f633cf2493f2038231f.json similarity index 51% rename from .sqlx/query-fd9f732f3a7ed809b9d4c2ededebdeeb3765c89c9fc78576f447c646c46f445c.json rename to .sqlx/query-b4ad9892410265bb0a06e51d8de8eb35e1c2bcfb1a276f633cf2493f2038231f.json index e1af1b05..a7091555 100644 --- a/.sqlx/query-fd9f732f3a7ed809b9d4c2ededebdeeb3765c89c9fc78576f447c646c46f445c.json +++ b/.sqlx/query-b4ad9892410265bb0a06e51d8de8eb35e1c2bcfb1a276f633cf2493f2038231f.json @@ -1,10 +1,10 @@ { "db_name": "SQLite", - "query": "\n SELECT COUNT(*) AS `count` FROM `collections`\n WHERE `visible` = 1\n ", + "query": "SELECT COUNT(*) FROM collections", "describe": { "columns": [ { - "name": "count", + "name": "COUNT(*)", "ordinal": 0, "type_info": "Integer" } @@ -16,5 +16,5 @@ false ] }, - "hash": "fd9f732f3a7ed809b9d4c2ededebdeeb3765c89c9fc78576f447c646c46f445c" + "hash": "b4ad9892410265bb0a06e51d8de8eb35e1c2bcfb1a276f633cf2493f2038231f" } diff --git a/.sqlx/query-c28c5534fa54f929c81d02b31276dfb5d621da40c7adc621a055e9b72d4dae30.json b/.sqlx/query-c28c5534fa54f929c81d02b31276dfb5d621da40c7adc621a055e9b72d4dae30.json new file mode 100644 index 00000000..15255bd1 --- /dev/null +++ b/.sqlx/query-c28c5534fa54f929c81d02b31276dfb5d621da40c7adc621a055e9b72d4dae30.json @@ -0,0 +1,26 @@ +{ + "db_name": "SQLite", + "query": "\n WITH distinct_dids AS (\n SELECT DISTINCT minter_did \n FROM nfts \n WHERE minter_did IS NOT NULL\n )\n SELECT \n minter_did,\n COUNT(*) OVER() AS total_count\n FROM distinct_dids\n LIMIT ? OFFSET ?\n ", + "describe": { + "columns": [ + { + "name": "minter_did", + "ordinal": 0, + "type_info": "Blob" + }, + { + "name": "total_count", + "ordinal": 1, + "type_info": "Integer" + } + ], + "parameters": { + "Right": 2 + }, + "nullable": [ + true, + false + ] + }, + "hash": "c28c5534fa54f929c81d02b31276dfb5d621da40c7adc621a055e9b72d4dae30" +} diff --git a/.sqlx/query-cc24879f9012f1e056cc0fcfc664437aee6a72b858918c0ca70776ef36b50f33.json b/.sqlx/query-cc24879f9012f1e056cc0fcfc664437aee6a72b858918c0ca70776ef36b50f33.json new file mode 100644 index 00000000..cb6292ba --- /dev/null +++ b/.sqlx/query-cc24879f9012f1e056cc0fcfc664437aee6a72b858918c0ca70776ef36b50f33.json @@ -0,0 +1,20 @@ +{ + "db_name": "SQLite", + "query": "SELECT COUNT(*) FROM collections WHERE visible = 1", + "describe": { + "columns": [ + { + "name": "COUNT(*)", + "ordinal": 0, + "type_info": "Integer" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + false + ] + }, + "hash": "cc24879f9012f1e056cc0fcfc664437aee6a72b858918c0ca70776ef36b50f33" +} diff --git a/.sqlx/query-db46b3d7d5af874af5981ec8beb210085a115f7d5900802ade79722b0c4ed560.json b/.sqlx/query-dbfe6794b0d552111c01cec93995a4af753cbee36b430767e372debb5df15ce4.json similarity index 56% rename from .sqlx/query-db46b3d7d5af874af5981ec8beb210085a115f7d5900802ade79722b0c4ed560.json rename to .sqlx/query-dbfe6794b0d552111c01cec93995a4af753cbee36b430767e372debb5df15ce4.json index 46774271..f6b8b549 100644 --- a/.sqlx/query-db46b3d7d5af874af5981ec8beb210085a115f7d5900802ade79722b0c4ed560.json +++ b/.sqlx/query-dbfe6794b0d552111c01cec93995a4af753cbee36b430767e372debb5df15ce4.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "\n SELECT `collection_id`, `did_id`, `metadata_collection_id`, `visible`, `name`, `icon`\n FROM `collections` INDEXED BY `col_name`\n WHERE `visible` = 1\n ORDER BY `is_named` DESC, `name` ASC, `collection_id` ASC\n LIMIT ? OFFSET ?\n ", + "query": "\n SELECT \n collection_id, \n did_id, \n metadata_collection_id, \n visible, \n name, \n icon,\n COUNT(*) OVER() as total_count\n FROM collections INDEXED BY col_name\n WHERE visible = 1\n ORDER BY name IS NOT NULL DESC, name ASC, collection_id ASC\n LIMIT ? OFFSET ?\n ", "describe": { "columns": [ { @@ -32,6 +32,11 @@ "name": "icon", "ordinal": 5, "type_info": "Text" + }, + { + "name": "total_count", + "ordinal": 6, + "type_info": "Integer" } ], "parameters": { @@ -43,8 +48,9 @@ false, false, true, - true + true, + false ] }, - "hash": "db46b3d7d5af874af5981ec8beb210085a115f7d5900802ade79722b0c4ed560" + "hash": "dbfe6794b0d552111c01cec93995a4af753cbee36b430767e372debb5df15ce4" } diff --git a/crates/sage-api/src/requests/data.rs b/crates/sage-api/src/requests/data.rs index 44966e62..f8fe0ac9 100644 --- a/crates/sage-api/src/requests/data.rs +++ b/crates/sage-api/src/requests/data.rs @@ -91,12 +91,16 @@ pub struct GetDidsResponse { #[derive(Debug, Clone, Copy, Serialize, Deserialize)] #[cfg_attr(feature = "tauri", derive(specta::Type))] -pub struct GetMinterDidIds {} +pub struct GetMinterDidIds { + pub offset: u32, + pub limit: u32, +} #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "tauri", derive(specta::Type))] pub struct GetMinterDidIdsResponse { pub did_ids: Vec, + pub total: u32, } #[derive(Debug, Clone, Copy, Serialize, Deserialize)] @@ -147,6 +151,7 @@ pub struct GetNftCollections { #[cfg_attr(feature = "tauri", derive(specta::Type))] pub struct GetNftCollectionsResponse { pub collections: Vec, + pub total: u32, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -182,6 +187,7 @@ pub struct GetNfts { #[cfg_attr(feature = "tauri", derive(specta::Type))] pub struct GetNftsResponse { pub nfts: Vec, + pub total: u32, } #[derive(Debug, Clone, Copy, Serialize, Deserialize)] diff --git a/crates/sage-database/src/lib.rs b/crates/sage-database/src/lib.rs index b2367658..2a53a2e2 100644 --- a/crates/sage-database/src/lib.rs +++ b/crates/sage-database/src/lib.rs @@ -73,6 +73,21 @@ impl Database { Ok(()) } + + /// Count collections, optionally including hidden ones + pub async fn count_collections(&self, include_hidden: bool) -> Result { + let count: i64 = if include_hidden { + sqlx::query_scalar!("SELECT COUNT(*) FROM collections") + .fetch_one(&self.pool) + .await? + } else { + sqlx::query_scalar!("SELECT COUNT(*) FROM collections WHERE visible = 1") + .fetch_one(&self.pool) + .await? + }; + + Ok(count) + } } #[derive(Debug)] diff --git a/crates/sage-database/src/primitives/nfts.rs b/crates/sage-database/src/primitives/nfts.rs index 15b25c2c..464cd1c1 100644 --- a/crates/sage-database/src/primitives/nfts.rs +++ b/crates/sage-database/src/primitives/nfts.rs @@ -48,6 +48,24 @@ pub struct NftSearchParams { pub name: Option, } +#[derive(sqlx::FromRow)] +struct NftSearchRow { + #[sqlx(flatten)] + nft: NftSql, + total_count: i32, +} + +#[derive(sqlx::FromRow)] +struct CollectionSearchSql { + collection_id: Vec, + did_id: Vec, + metadata_collection_id: String, + visible: bool, + name: Option, + icon: Option, + total_count: i64, +} + pub fn calculate_collection_id(did_id: Bytes32, json_collection_id: &str) -> Bytes32 { let mut hasher = Sha256::new(); hasher.update(hex::encode(did_id)); @@ -72,8 +90,12 @@ impl Database { fetch_nft_data(&self.pool, hash).await } - pub async fn distinct_minter_dids(&self) -> Result>> { - distinct_minter_dids(&self.pool).await + pub async fn distinct_minter_dids( + &self, + limit: u32, + offset: u32, + ) -> Result<(Vec>, u32)> { + distinct_minter_dids(&self.pool, limit, offset).await } pub async fn search_nfts( @@ -81,7 +103,7 @@ impl Database { params: NftSearchParams, limit: u32, offset: u32, - ) -> Result> { + ) -> Result<(Vec, u32)> { search_nfts(&self.pool, params, limit, offset).await } @@ -89,24 +111,20 @@ impl Database { collection(&self.pool, collection_id).await } - pub async fn collection_count(&self) -> Result { - collection_count(&self.pool).await - } - - pub async fn visible_collection_count(&self) -> Result { - visible_collection_count(&self.pool).await - } - pub async fn collections_visible_named( &self, limit: u32, offset: u32, - ) -> Result> { - collections_visible_named(&self.pool, offset, limit).await + ) -> Result<(Vec, u32)> { + collections_visible_named(&self.pool, limit, offset).await } - pub async fn collections_named(&self, limit: u32, offset: u32) -> Result> { - collections_named(&self.pool, offset, limit).await + pub async fn collections_named( + &self, + limit: u32, + offset: u32, + ) -> Result<(Vec, u32)> { + collections_named(&self.pool, limit, offset).await } pub async fn nft_row(&self, launcher_id: Bytes32) -> Result> { @@ -386,75 +404,91 @@ async fn collection( async fn collections_visible_named( conn: impl SqliteExecutor<'_>, - offset: u32, limit: u32, -) -> Result> { - sqlx::query_as!( - CollectionSql, - " - SELECT `collection_id`, `did_id`, `metadata_collection_id`, `visible`, `name`, `icon` - FROM `collections` INDEXED BY `col_name` - WHERE `visible` = 1 - ORDER BY `is_named` DESC, `name` ASC, `collection_id` ASC + offset: u32, +) -> Result<(Vec, u32)> { + let rows = sqlx::query_as!( + CollectionSearchSql, + r#" + SELECT + collection_id, + did_id, + metadata_collection_id, + visible, + name, + icon, + COUNT(*) OVER() as total_count + FROM collections INDEXED BY col_name + WHERE visible = 1 + ORDER BY name IS NOT NULL DESC, name ASC, collection_id ASC LIMIT ? OFFSET ? - ", + "#, limit, offset ) .fetch_all(conn) - .await? - .into_iter() - .map(into_row) - .collect() + .await?; + + let total = rows.first().map(|r| r.total_count as u32).unwrap_or(0); + let collections = rows + .into_iter() + .map(|row| { + into_row(CollectionSql { + collection_id: row.collection_id, + did_id: row.did_id, + metadata_collection_id: row.metadata_collection_id, + visible: row.visible, + name: row.name, + icon: row.icon, + }) + }) + .collect::>>()?; + + Ok((collections, total)) } async fn collections_named( conn: impl SqliteExecutor<'_>, - offset: u32, limit: u32, -) -> Result> { - sqlx::query_as!( - CollectionSql, - " - SELECT `collection_id`, `did_id`, `metadata_collection_id`, `visible`, `name`, `icon` - FROM `collections` INDEXED BY `col_name` - ORDER BY `visible` DESC, `is_named` DESC, `name` ASC, `collection_id` ASC + offset: u32, +) -> Result<(Vec, u32)> { + let rows = sqlx::query_as!( + CollectionSearchSql, + r#" + SELECT + collection_id, + did_id, + metadata_collection_id, + visible, + name, + icon, + COUNT(*) OVER() as total_count + FROM collections INDEXED BY col_name + ORDER BY visible DESC, is_named DESC, name ASC, collection_id ASC LIMIT ? OFFSET ? - ", + "#, limit, offset ) .fetch_all(conn) - .await? - .into_iter() - .map(into_row) - .collect() -} - -async fn collection_count(conn: impl SqliteExecutor<'_>) -> Result { - let row = sqlx::query!( - " - SELECT COUNT(*) AS `count` FROM `collections` - WHERE `visible` = 1 - " - ) - .fetch_one(conn) .await?; - Ok(row.count.try_into()?) -} - -async fn visible_collection_count(conn: impl SqliteExecutor<'_>) -> Result { - let row = sqlx::query!( - " - SELECT COUNT(*) AS `count` FROM `collections` - WHERE `visible` = 1 - " - ) - .fetch_one(conn) - .await?; - - Ok(row.count.try_into()?) + let total = rows.first().map(|r| r.total_count as u32).unwrap_or(0); + let collections = rows + .into_iter() + .map(|row| { + into_row(CollectionSql { + collection_id: row.collection_id, + did_id: row.did_id, + metadata_collection_id: row.metadata_collection_id, + visible: row.visible, + name: row.name, + icon: row.icon, + }) + }) + .collect::>>()?; + + Ok((collections, total)) } async fn insert_nft_uri(conn: impl SqliteExecutor<'_>, uri: String, hash: Bytes32) -> Result<()> { @@ -553,14 +587,37 @@ async fn delete_nft_data(conn: impl SqliteExecutor<'_>, hash: Bytes32) -> Result Ok(()) } -async fn distinct_minter_dids(conn: impl SqliteExecutor<'_>) -> Result>> { - let rows = sqlx::query!("SELECT DISTINCT minter_did FROM nfts WHERE minter_did IS NOT NULL") - .fetch_all(conn) - .await?; +async fn distinct_minter_dids( + conn: impl SqliteExecutor<'_>, + limit: u32, + offset: u32, +) -> Result<(Vec>, u32)> { + let rows = sqlx::query!( + r#" + WITH distinct_dids AS ( + SELECT DISTINCT minter_did + FROM nfts + WHERE minter_did IS NOT NULL + ) + SELECT + minter_did, + COUNT(*) OVER() AS total_count + FROM distinct_dids + LIMIT ? OFFSET ? + "#, + limit, + offset + ) + .fetch_all(conn) + .await?; - rows.into_iter() + let total_count = rows.first().map(|row| row.total_count as u32).unwrap_or(0); + let dids = rows + .into_iter() .map(|row| row.minter_did.map(|bytes| to_bytes32(&bytes)).transpose()) - .collect() + .collect::>>()?; + + Ok((dids, total_count)) } async fn fetch_nft_data(conn: impl SqliteExecutor<'_>, hash: Bytes32) -> Result> { @@ -789,7 +846,7 @@ async fn search_nfts( params: NftSearchParams, limit: u32, offset: u32, -) -> Result> { +) -> Result<(Vec, u32)> { let mut conditions = vec!["is_owned = 1"]; // Group filtering (Collection/DID) @@ -870,7 +927,7 @@ async fn search_nfts( WHERE name MATCH ? || '*' ORDER BY rank ) - SELECT nfts.* + SELECT nfts.*, COUNT(*) OVER() as total_count FROM nfts INDEXED BY {index} INNER JOIN matched_names ON nfts.launcher_id = matched_names.launcher_id WHERE {where_clause} @@ -880,7 +937,7 @@ async fn search_nfts( } else { format!( r#" - SELECT * + SELECT *, COUNT(*) OVER() as total_count FROM nfts INDEXED BY {index} WHERE {where_clause} {order_by} @@ -889,7 +946,7 @@ async fn search_nfts( }; // Execute query with bindings - let mut query = sqlx::query_as::<_, NftSql>(&query); + let mut query = sqlx::query_as::<_, NftSearchRow>(&query); // Bind name search if present if let Some(name_search) = params.name { @@ -909,7 +966,13 @@ async fn search_nfts( query = query.bind(offset); let rows = query.fetch_all(conn).await?; - rows.into_iter().map(into_row).collect() + let total_count = rows.first().map(|row| row.total_count as u32).unwrap_or(0); + let nfts = rows + .into_iter() + .map(|row| into_row(row.nft)) + .collect::>>()?; + + Ok((nfts, total_count)) } async fn insert_nft_coin( diff --git a/crates/sage/src/endpoints/data.rs b/crates/sage/src/endpoints/data.rs index 6461c9f1..32f05a75 100644 --- a/crates/sage/src/endpoints/data.rs +++ b/crates/sage/src/endpoints/data.rs @@ -247,20 +247,22 @@ impl Sage { pub async fn get_minter_did_ids( &self, - _req: GetMinterDidIds, + req: GetMinterDidIds, ) -> Result { let wallet = self.wallet()?; - let did_ids = wallet + let (dids, total) = wallet .db - .distinct_minter_dids() - .await? + .distinct_minter_dids(req.limit, req.offset) + .await?; + + let did_ids = dids .into_iter() .filter_map(|did| did.map(|d| encode_address(d.to_bytes(), "did:chia:").ok())) .flatten() .collect(); - Ok(GetMinterDidIdsResponse { did_ids }) + Ok(GetMinterDidIdsResponse { did_ids, total }) } pub async fn get_pending_transactions( @@ -320,10 +322,9 @@ impl Sage { req: GetNftCollections, ) -> Result { let wallet = self.wallet()?; + let include_hidden = req.include_hidden; - let mut records = Vec::new(); - - let collections = if req.include_hidden { + let (collections, total) = if include_hidden { wallet.db.collections_named(req.limit, req.offset).await? } else { wallet @@ -332,19 +333,23 @@ impl Sage { .await? }; - for col in collections { - records.push(NftCollectionRecord { - collection_id: encode_address(col.collection_id.to_bytes(), "col")?, - did_id: encode_address(col.did_id.to_bytes(), "did:chia:")?, - metadata_collection_id: col.metadata_collection_id, - visible: col.visible, - name: col.name, - icon: col.icon, - }); - } + let records = collections + .into_iter() + .map(|row| { + Ok(NftCollectionRecord { + collection_id: encode_address(row.collection_id.to_bytes(), "col")?, + did_id: encode_address(row.did_id.to_bytes(), "did:chia:")?, + metadata_collection_id: row.metadata_collection_id, + name: row.name, + icon: row.icon, + visible: row.visible, + }) + }) + .collect::>>()?; Ok(GetNftCollectionsResponse { collections: records, + total, }) } @@ -433,10 +438,7 @@ impl Sage { name: req.name, }; - let nfts = wallet - .db - .search_nfts(params.clone(), req.limit, req.offset) - .await?; + let (nfts, total) = wallet.db.search_nfts(params, req.limit, req.offset).await?; for nft_row in nfts { let Some(nft) = wallet.db.nft(nft_row.launcher_id).await? else { @@ -452,7 +454,10 @@ impl Sage { records.push(self.nft_record(nft_row, nft, collection_name)?); } - Ok(GetNftsResponse { nfts: records }) + Ok(GetNftsResponse { + nfts: records, + total, + }) } pub async fn get_nft(&self, req: GetNft) -> Result { diff --git a/src/bindings.ts b/src/bindings.ts index bad71202..ac7b6c65 100644 --- a/src/bindings.ts +++ b/src/bindings.ts @@ -311,20 +311,20 @@ export type GetKey = { fingerprint?: number | null } export type GetKeyResponse = { key: KeyInfo | null } export type GetKeys = Record export type GetKeysResponse = { keys: KeyInfo[] } -export type GetMinterDidIds = Record -export type GetMinterDidIdsResponse = { did_ids: string[] } +export type GetMinterDidIds = { offset: number; limit: number } +export type GetMinterDidIdsResponse = { did_ids: string[]; total: number } export type GetNetworks = Record export type GetNetworksResponse = { networks: { [key in string]: Network } } export type GetNft = { nft_id: string } export type GetNftCollection = { collection_id: string | null } export type GetNftCollectionResponse = { collection: NftCollectionRecord | null } export type GetNftCollections = { offset: number; limit: number; include_hidden: boolean } -export type GetNftCollectionsResponse = { collections: NftCollectionRecord[] } +export type GetNftCollectionsResponse = { collections: NftCollectionRecord[]; total: number } export type GetNftData = { nft_id: string } export type GetNftDataResponse = { data: NftData | null } export type GetNftResponse = { nft: NftRecord | null } export type GetNfts = { collection_id?: string | null; minter_did_id?: string | null; owner_did_id?: string | null; name?: string | null; offset: number; limit: number; sort_mode: NftSortMode; include_hidden: boolean } -export type GetNftsResponse = { nfts: NftRecord[] } +export type GetNftsResponse = { nfts: NftRecord[]; total: number } export type GetOffer = { offer_id: string } export type GetOfferResponse = { offer: OfferRecord } export type GetOffers = Record diff --git a/src/components/CardSizeToggle.tsx b/src/components/CardSizeToggle.tsx new file mode 100644 index 00000000..6e830d8e --- /dev/null +++ b/src/components/CardSizeToggle.tsx @@ -0,0 +1,37 @@ +import { Button } from '@/components/ui/button'; +import { CardSize } from '@/hooks/useNftParams'; +import { t } from '@lingui/core/macro'; +import { Maximize2, Minimize2 } from 'lucide-react'; + +interface CardSizeToggleProps { + size: CardSize; + onChange: (size: CardSize) => void; +} + +export function CardSizeToggle({ size, onChange }: CardSizeToggleProps) { + return ( + + ); +} diff --git a/src/components/NftCard.tsx b/src/components/NftCard.tsx index a5cab96b..a43e7db4 100644 --- a/src/components/NftCard.tsx +++ b/src/components/NftCard.tsx @@ -189,10 +189,18 @@ const NftCardComponent = ({ .finally(() => setBurnOpen(false)); }; + const nftName = nft.name ?? t`Unnamed NFT`; + return ( <>
{ if (selectionState === null) { navigate(`/nfts/${nft.launcher_id}`); @@ -210,16 +218,18 @@ const NftCardComponent = ({ } } }} - role='button' + role='article' tabIndex={0} - aria-label={nft.name ? `NFT: ${nft.name}` : t`Unnamed NFT`} + aria-label={nftName} + aria-disabled={!nft.created_height} + aria-selected={selectionState?.[0]} >
{nft.name -

{nft.name ?? t`Unnamed`}

+

{nftName}

@@ -237,20 +247,25 @@ const NftCardComponent = ({ )}
-
+
- - {nft.name ?? t`Unnamed`} - +

+ {nftName} +

-

{nft.name ?? t`Unnamed`}

+

{nftName}

@@ -271,8 +286,13 @@ const NftCardComponent = ({ - @@ -284,8 +304,9 @@ const NftCardComponent = ({ setTransferOpen(true); }} disabled={!nft.created_height} + aria-label={t`Transfer ${nftName}`} > - +