🛻 Upgraded deps, fixed issues
This commit is contained in:
17814
package-lock.json
generated
17814
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
202
package.json
202
package.json
@@ -18,124 +18,128 @@
|
||||
"author": "Rishi Ghan",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@dnd-kit/core": "^6.0.8",
|
||||
"@dnd-kit/sortable": "^7.0.2",
|
||||
"@dnd-kit/utilities": "^3.2.1",
|
||||
"@floating-ui/react": "^0.26.12",
|
||||
"@floating-ui/react-dom": "^2.0.8",
|
||||
"@fortawesome/fontawesome-free": "^6.3.0",
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@floating-ui/react": "^0.27.18",
|
||||
"@floating-ui/react-dom": "^2.1.7",
|
||||
"@fortawesome/fontawesome-free": "^7.2.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
||||
"@tanstack/react-query": "^5.0.5",
|
||||
"@tanstack/react-table": "^8.9.3",
|
||||
"@types/mime-types": "^2.1.0",
|
||||
"@rollup/plugin-node-resolve": "^16.0.3",
|
||||
"@tanstack/react-query": "^5.90.21",
|
||||
"@tanstack/react-table": "^8.21.3",
|
||||
"@types/mime-types": "^3.0.1",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"airdcpp-apisocket": "^2.5.0-beta.2",
|
||||
"axios": "^1.12.0",
|
||||
"axios-cache-interceptor": "^1.11.1",
|
||||
"axios-rate-limit": "^1.3.0",
|
||||
"@vitejs/plugin-react": "^5.1.4",
|
||||
"airdcpp-apisocket": "^3.0.0-beta.14",
|
||||
"axios": "^1.13.5",
|
||||
"axios-cache-interceptor": "^1.11.4",
|
||||
"axios-rate-limit": "^1.6.2",
|
||||
"babel-plugin-styled-components": "^2.1.4",
|
||||
"date-fns": "^2.28.0",
|
||||
"dayjs": "^1.10.6",
|
||||
"ellipsize": "^0.5.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"dayjs": "^1.11.19",
|
||||
"ellipsize": "^0.7.0",
|
||||
"embla-carousel-react": "^8.6.0",
|
||||
"express": "^4.20.0",
|
||||
"filename-parser": "^1.0.2",
|
||||
"final-form": "^4.20.2",
|
||||
"final-form-arrays": "^3.0.2",
|
||||
"focus-trap-react": "^10.2.3",
|
||||
"express": "^5.2.1",
|
||||
"filename-parser": "^1.0.4",
|
||||
"final-form": "^5.0.0",
|
||||
"final-form-arrays": "^4.0.0",
|
||||
"focus-trap-react": "^12.0.0",
|
||||
"history": "^5.3.0",
|
||||
"html-to-text": "^8.1.0",
|
||||
"i18next": "^23.11.1",
|
||||
"i18next-browser-languagedetector": "^7.2.1",
|
||||
"i18next-http-backend": "^2.5.0",
|
||||
"immer": "^10.0.3",
|
||||
"jsdoc": "^3.6.10",
|
||||
"html-to-text": "^9.0.5",
|
||||
"i18next": "^25.8.13",
|
||||
"i18next-browser-languagedetector": "^8.2.1",
|
||||
"i18next-http-backend": "^3.0.2",
|
||||
"immer": "^11.1.4",
|
||||
"jsdoc": "^4.0.5",
|
||||
"lodash": "^4.17.23",
|
||||
"pretty-bytes": "^5.6.0",
|
||||
"pretty-bytes": "^7.1.0",
|
||||
"prop-types": "^15.8.1",
|
||||
"qs": "^6.14.1",
|
||||
"react": "^18.3.1",
|
||||
"react-collapsible": "^2.9.0",
|
||||
"react-comic-viewer": "^0.4.0",
|
||||
"react-day-picker": "^8.10.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-fast-compare": "^3.2.0",
|
||||
"react-final-form": "^6.5.9",
|
||||
"react-final-form-arrays": "^3.1.4",
|
||||
"react-i18next": "^14.1.0",
|
||||
"react-loader-spinner": "^4.0.0",
|
||||
"react-modal": "^3.15.1",
|
||||
"react-router": "^7.12.0",
|
||||
"react-router-dom": "^6.9.0",
|
||||
"react-select": "^5.8.0",
|
||||
"react-select-async-paginate": "^0.7.2",
|
||||
"react-sliding-pane": "^7.1.0",
|
||||
"react-textarea-autosize": "^8.3.4",
|
||||
"react-toastify": "^10.0.5",
|
||||
"socket.io-client": "^4.3.2",
|
||||
"styled-components": "^6.1.0",
|
||||
"qs": "^6.15.0",
|
||||
"react": "^19.2.4",
|
||||
"react-collapsible": "^2.10.0",
|
||||
"react-comic-viewer": "^0.5.1",
|
||||
"react-day-picker": "^9.13.2",
|
||||
"react-dom": "^19.2.4",
|
||||
"react-fast-compare": "^3.2.2",
|
||||
"react-final-form": "^7.0.0",
|
||||
"react-final-form-arrays": "^4.0.0",
|
||||
"react-i18next": "^16.5.4",
|
||||
"react-loader-spinner": "^8.0.2",
|
||||
"react-modal": "^3.16.3",
|
||||
"react-router": "^7.13.1",
|
||||
"react-router-dom": "^7.13.1",
|
||||
"react-select": "^5.10.2",
|
||||
"react-select-async-paginate": "^0.7.11",
|
||||
"react-sliding-pane": "^7.3.0",
|
||||
"react-textarea-autosize": "^8.5.9",
|
||||
"react-toastify": "^11.0.5",
|
||||
"socket.io-client": "^4.8.3",
|
||||
"styled-components": "^6.3.11",
|
||||
"threetwo-ui-typings": "^1.0.14",
|
||||
"vite": "^5.4.21",
|
||||
"vite-plugin-html": "^3.2.0",
|
||||
"websocket": "^1.0.34",
|
||||
"zustand": "^4.4.6"
|
||||
"vite": "^7.3.1",
|
||||
"vite-plugin-html": "^3.2.2",
|
||||
"websocket": "^1.0.35",
|
||||
"zustand": "^5.0.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify-json/solar": "^1.1.8",
|
||||
"@iconify/tailwind": "^0.1.4",
|
||||
"@storybook/addon-essentials": "^7.4.1",
|
||||
"@storybook/addon-interactions": "^7.4.1",
|
||||
"@storybook/addon-links": "^7.4.1",
|
||||
"@storybook/addon-onboarding": "^1.0.8",
|
||||
"@storybook/blocks": "^7.4.1",
|
||||
"@storybook/react": "^7.4.1",
|
||||
"@storybook/react-vite": "^7.4.1",
|
||||
"@storybook/testing-library": "^0.2.0",
|
||||
"@tanstack/eslint-plugin-query": "^5.0.5",
|
||||
"@tanstack/react-query-devtools": "^5.1.0",
|
||||
"@iconify-json/solar": "^1.2.5",
|
||||
"@iconify/json": "^2.2.443",
|
||||
"@iconify/tailwind": "^1.2.0",
|
||||
"@iconify/tailwind4": "^1.2.1",
|
||||
"@iconify/utils": "^3.1.0",
|
||||
"@storybook/addon-essentials": "^8.6.17",
|
||||
"@storybook/addon-interactions": "^8.6.17",
|
||||
"@storybook/addon-links": "^8.6.17",
|
||||
"@storybook/addon-onboarding": "^8.6.17",
|
||||
"@storybook/blocks": "^8.6.17",
|
||||
"@storybook/react": "^8.6.17",
|
||||
"@storybook/react-vite": "^8.6.17",
|
||||
"@storybook/testing-library": "^0.2.2",
|
||||
"@tailwindcss/postcss": "^4.2.1",
|
||||
"@tanstack/eslint-plugin-query": "^5.91.4",
|
||||
"@tanstack/react-query-devtools": "^5.91.3",
|
||||
"@testing-library/jest-dom": "^6.9.1",
|
||||
"@testing-library/react": "^16.3.2",
|
||||
"@testing-library/user-event": "^14.6.1",
|
||||
"@tsconfig/node14": "^1.0.0",
|
||||
"@types/ellipsize": "^0.1.1",
|
||||
"@types/express": "^4.17.8",
|
||||
"@types/jest": "^26.0.20",
|
||||
"@types/lodash": "^4.14.168",
|
||||
"@types/node": "^14.14.34",
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"@types/react-redux": "^7.1.25",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"body-parser": "^1.19.0",
|
||||
"@tsconfig/node14": "^14.1.8",
|
||||
"@types/ellipsize": "^0.1.3",
|
||||
"@types/express": "^5.0.6",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/lodash": "^4.17.24",
|
||||
"@types/node": "^25.3.0",
|
||||
"@types/react": "^19.2.14",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@types/react-redux": "^7.1.34",
|
||||
"autoprefixer": "^10.4.27",
|
||||
"body-parser": "^2.2.2",
|
||||
"docdash": "^2.0.2",
|
||||
"eslint": "^8.49.0",
|
||||
"eslint-config-prettier": "^8.1.0",
|
||||
"eslint-plugin-css-modules": "^2.11.0",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-jsdoc": "^46.6.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.0.3",
|
||||
"eslint-plugin-prettier": "^3.3.1",
|
||||
"eslint-plugin-react": "^7.22.0",
|
||||
"eslint-plugin-storybook": "^0.6.13",
|
||||
"express": "^4.20.0",
|
||||
"eslint": "^10.0.2",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-css-modules": "^2.12.0",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
"eslint-plugin-jsdoc": "^62.7.1",
|
||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||
"eslint-plugin-prettier": "^5.5.5",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-storybook": "^0.11.1",
|
||||
"express": "^5.2.1",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"install": "^0.13.0",
|
||||
"jest": "^29.6.3",
|
||||
"jest": "^30.2.0",
|
||||
"jest-environment-jsdom": "^30.2.0",
|
||||
"nodemon": "^3.0.1",
|
||||
"postcss": "^8.4.32",
|
||||
"postcss-import": "^15.1.0",
|
||||
"prettier": "^2.2.1",
|
||||
"react-refresh": "^0.14.0",
|
||||
"rimraf": "^4.1.3",
|
||||
"sass": "^1.77.0",
|
||||
"storybook": "^7.6.21",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"nodemon": "^3.1.14",
|
||||
"postcss": "^8.5.6",
|
||||
"postcss-import": "^16.1.1",
|
||||
"prettier": "^3.8.1",
|
||||
"react-refresh": "^0.18.0",
|
||||
"rimraf": "^6.1.3",
|
||||
"sass": "^1.97.3",
|
||||
"storybook": "^8.6.17",
|
||||
"tailwindcss": "^4.2.1",
|
||||
"ts-jest": "^29.4.6",
|
||||
"tui-jsdoc-template": "^1.2.2",
|
||||
"typescript": "^5.1.6"
|
||||
"typescript": "^5.9.3"
|
||||
},
|
||||
"resolutions": {
|
||||
"jackspeak": "2.1.1"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
"postcss-import": {},
|
||||
tailwindcss: {},
|
||||
"@tailwindcss/postcss": {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
@font-face {
|
||||
font-family: "PP Object Sans Regular";
|
||||
src: url("/fonts/PPObjectSans-Regular.otf") format("opentype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Hasklig Regular";
|
||||
src: url("/fonts/Hasklig-Regular.otf") format("opentype");
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import React, { ReactElement, useEffect } from "react";
|
||||
import { Outlet } from "react-router-dom";
|
||||
import { Navbar2 } from "./shared/Navbar2";
|
||||
import { ToastContainer } from "react-toastify";
|
||||
import "../assets/scss/App.scss";
|
||||
import "../assets/scss/App.css";
|
||||
import { useStore } from "../store";
|
||||
|
||||
export const App = (): ReactElement => {
|
||||
|
||||
@@ -21,7 +21,6 @@ import { components } from "react-select";
|
||||
import { RootState } from "threetwo-ui-typings";
|
||||
|
||||
import "react-sliding-pane/dist/react-sliding-pane.css";
|
||||
import "react-loader-spinner/dist/loader/css/react-spinner-loader.css";
|
||||
import Loader from "react-loader-spinner";
|
||||
import SlidingPane from "react-sliding-pane";
|
||||
import Modal from "react-modal";
|
||||
|
||||
@@ -67,6 +67,8 @@ export const RecentlyImported = (
|
||||
const isComicVineMetadataAvailable =
|
||||
!isUndefined(comicvine) &&
|
||||
!isUndefined(comicvine.volumeInformation);
|
||||
const hasComicInfo = !isNil(comicInfo) && !isEmpty(comicInfo);
|
||||
const cardState = (hasComicInfo || isComicVineMetadataAvailable) ? "scraped" : "imported";
|
||||
return (
|
||||
<div
|
||||
key={idx}
|
||||
@@ -77,6 +79,7 @@ export const RecentlyImported = (
|
||||
imageUrl={url}
|
||||
title={inferredMetadata.issue.name}
|
||||
hasDetails
|
||||
cardState={cardState}
|
||||
>
|
||||
<div>
|
||||
<dd className="text-sm my-1 flex flex-row gap-1">
|
||||
@@ -115,7 +118,7 @@ export const RecentlyImported = (
|
||||
{/* ComicInfo.xml presence */}
|
||||
{!isNil(comicInfo) && !isEmpty(comicInfo) && (
|
||||
<div className="mt-1">
|
||||
<i className="h-7 w-7 icon-[solar--code-file-bold-duotone] text-yellow-500 dark:text-yellow-300"></i>
|
||||
<i className="h-7 w-7 icon-[solar--code-file-bold-duotone] text-gray-500 dark:text-white-300"></i>
|
||||
</div>
|
||||
)}
|
||||
{/* ComicVine metadata presence */}
|
||||
|
||||
@@ -59,6 +59,7 @@ export const WantedComicsList = ({
|
||||
imageUrl={url}
|
||||
hasDetails
|
||||
title={issueName ? titleElement : <span>No Name</span>}
|
||||
cardState="wanted"
|
||||
>
|
||||
<div className="pb-1">
|
||||
<div className="flex flex-row gap-2">
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React, { ReactElement, useCallback, useEffect, useState } from "react";
|
||||
import "react-loader-spinner/dist/loader/css/react-spinner-loader.css";
|
||||
import { format } from "date-fns";
|
||||
import Loader from "react-loader-spinner";
|
||||
import { isEmpty, isNil, isUndefined } from "lodash";
|
||||
@@ -55,7 +54,6 @@ export const Import = (props: IProps): ReactElement => {
|
||||
url: "http://localhost:3000/api/jobqueue/getJobResultStatistics",
|
||||
params: { _t: Date.now() }, // Cache busting
|
||||
});
|
||||
console.log("Fetched import results:", response.data);
|
||||
return response;
|
||||
},
|
||||
refetchOnWindowFocus: false,
|
||||
@@ -69,13 +67,11 @@ export const Import = (props: IProps): ReactElement => {
|
||||
|
||||
// Listen for import queue drained event to refresh the table
|
||||
const handleQueueDrained = () => {
|
||||
console.log("Import queue drained, refreshing table...");
|
||||
refetch();
|
||||
};
|
||||
|
||||
// Listen for individual import completions to refresh the table
|
||||
const handleCoverExtracted = () => {
|
||||
console.log("Cover extracted, refreshing table...");
|
||||
refetch();
|
||||
};
|
||||
|
||||
@@ -97,7 +93,6 @@ export const Import = (props: IProps): ReactElement => {
|
||||
queueAction,
|
||||
queueStatus,
|
||||
},
|
||||
(data: any) => console.log(data),
|
||||
);
|
||||
};
|
||||
/**
|
||||
|
||||
@@ -10,11 +10,29 @@ interface ICardProps {
|
||||
children?: PropTypes.ReactNodeLike;
|
||||
borderColorClass?: string;
|
||||
backgroundColor?: string;
|
||||
cardState?: "wanted" | "delete" | "scraped" | "uncompressed" | "imported";
|
||||
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
|
||||
cardContainerStyle?: PropTypes.object;
|
||||
imageStyle?: PropTypes.object;
|
||||
cardContainerStyle?: React.CSSProperties;
|
||||
imageStyle?: React.CSSProperties;
|
||||
}
|
||||
|
||||
const getCardStateClass = (cardState?: string): string => {
|
||||
switch (cardState) {
|
||||
case "wanted":
|
||||
return "bg-card-wanted";
|
||||
case "delete":
|
||||
return "bg-card-delete";
|
||||
case "scraped":
|
||||
return "bg-card-scraped";
|
||||
case "uncompressed":
|
||||
return "bg-card-uncompressed";
|
||||
case "imported":
|
||||
return "bg-card-imported";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
const renderCard = (props: ICardProps): ReactElement => {
|
||||
switch (props.orientation) {
|
||||
case "horizontal":
|
||||
@@ -83,7 +101,7 @@ const renderCard = (props: ICardProps): ReactElement => {
|
||||
|
||||
case "vertical-2":
|
||||
return (
|
||||
<div className="block rounded-md max-w-64 h-fit shadow-md shadow-white-400 bg-gray-200 dark:bg-slate-500">
|
||||
<div className={`block rounded-md max-w-64 h-fit shadow-md shadow-white-400 ${getCardStateClass(props.cardState) || "bg-gray-200 dark:bg-slate-500"}`}>
|
||||
<img
|
||||
alt="Home"
|
||||
src={props.imageUrl}
|
||||
@@ -109,7 +127,7 @@ const renderCard = (props: ICardProps): ReactElement => {
|
||||
case "horizontal-small":
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-row justify-start align-top gap-3 bg-slate-200 h-fit rounded-md shadow-md shadow-white-400">
|
||||
<div className={`flex flex-row justify-start align-top gap-3 h-fit rounded-md shadow-md shadow-white-400 ${getCardStateClass(props.cardState) || "bg-slate-200"}`}>
|
||||
{/* thumbnail */}
|
||||
<div className="rounded-md overflow-hidden">
|
||||
<img src={props.imageUrl} className="object-cover h-20 w-20" />
|
||||
@@ -125,7 +143,7 @@ const renderCard = (props: ICardProps): ReactElement => {
|
||||
case "horizontal-medium":
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-row items-center align-top gap-3 bg-slate-200 h-fit p-2 rounded-md shadow-md shadow-white-400">
|
||||
<div className={`flex flex-row items-center align-top gap-3 h-fit p-2 rounded-md shadow-md shadow-white-400 ${getCardStateClass(props.cardState) || "bg-slate-200"}`}>
|
||||
{/* thumbnail */}
|
||||
<div className="rounded-md overflow-hidden">
|
||||
<img src={props.imageUrl} />
|
||||
|
||||
@@ -31,7 +31,7 @@ export const MetadataPanel = (props: IMetadatPanelProps): ReactElement => {
|
||||
{
|
||||
name: "rawFileDetails",
|
||||
content: () => (
|
||||
<dl className="dark:bg-[#647587] bg-slate-200 p-3 rounded-lg">
|
||||
<dl className="dark:bg-card-imported bg-card-imported dark:text-slate-800 p-3 rounded-lg">
|
||||
<dt>
|
||||
<p className="text-lg">{issueName}</p>
|
||||
</dt>
|
||||
|
||||
@@ -113,15 +113,15 @@ export const T2Table = (tableOptions: T2TableProps): ReactElement => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table className="table-auto w-full text-sm text-gray-900 dark:text-slate-100 border-separate border-spacing-0">
|
||||
<thead className="sticky top-0 bg-white dark:bg-slate-900 z-10 border-b border-gray-300 dark:border-slate-700">
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<table className="table-auto w-full text-sm text-gray-900 dark:text-slate-100">
|
||||
<thead className="sticky top-0 z-10 bg-white dark:bg-slate-900">
|
||||
{table.getHeaderGroups().map((headerGroup, groupIndex) => (
|
||||
<tr key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => (
|
||||
{headerGroup.headers.map((header, index) => (
|
||||
<th
|
||||
key={header.id}
|
||||
colSpan={header.colSpan}
|
||||
className="px-3 py-2 text-[11px] font-semibold tracking-wide uppercase text-left text-gray-500 dark:text-slate-400"
|
||||
className="px-3 py-2 text-[11px] font-semibold tracking-wide uppercase text-left text-gray-500 dark:text-slate-400 border-b border-gray-300 dark:border-slate-700"
|
||||
>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
@@ -136,11 +136,11 @@ export const T2Table = (tableOptions: T2TableProps): ReactElement => {
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{table.getRowModel().rows.map((row) => (
|
||||
{table.getRowModel().rows.map((row, rowIndex) => (
|
||||
<tr
|
||||
key={row.id}
|
||||
onClick={() => rowClickHandler(row)}
|
||||
className="border-b border-gray-200 dark:border-slate-700 hover:bg-gray-50 dark:hover:bg-slate-800 transition-colors"
|
||||
className="border-b border-gray-200 dark:border-slate-700 hover:bg-slate-100/30 dark:hover:bg-slate-700/20 transition-colors cursor-pointer"
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<td key={cell.id} className="px-3 py-2 align-top">
|
||||
|
||||
@@ -4,7 +4,7 @@ import { SOCKET_BASE_URI } from "../constants/endpoints";
|
||||
import { isNil } from "lodash";
|
||||
import { QueryClient } from "@tanstack/react-query";
|
||||
import { toast } from "react-toastify";
|
||||
import "react-toastify/dist/ReactToastify.min.css";
|
||||
import "react-toastify/dist/ReactToastify.css";
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import React from 'react';
|
||||
import { ComponentMeta, ComponentStory } from '@storybook/react';
|
||||
|
||||
import { MetadataPanel } from '../components/shared/MetadataPanel';
|
||||
import "../assets/scss/App.scss";
|
||||
import "../assets/scss/App.css";
|
||||
export default {
|
||||
/* 👇 The title prop is optional.
|
||||
* See https://storybook.js.org/docs/react/configure/overview#configure-story-loading
|
||||
|
||||
@@ -5,7 +5,7 @@ import React from 'react';
|
||||
import { ComponentMeta, ComponentStory } from '@storybook/react';
|
||||
|
||||
import { Card } from '../components/shared/Carda';
|
||||
import "../assets/scss/App.scss";
|
||||
import "../assets/scss/App.css";
|
||||
export default {
|
||||
/* 👇 The title prop is optional.
|
||||
* See https://storybook.js.org/docs/react/configure/overview#configure-story-loading
|
||||
|
||||
@@ -5,6 +5,17 @@ module.exports = {
|
||||
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
card: {
|
||||
wanted: "#f2d98d",
|
||||
delete: "#FFEBEE",
|
||||
scraped: "#b8edbc",
|
||||
uncompressed: "#FFF3E0",
|
||||
imported: "#d8dab0",
|
||||
},
|
||||
},
|
||||
},
|
||||
fontFamily: {
|
||||
sans: ["PP Object Sans Regular", "sans-serif"],
|
||||
hasklig: ["Hasklig Regular", "monospace"],
|
||||
|
||||
132
vite-plugin-iconify.js
Normal file
132
vite-plugin-iconify.js
Normal file
@@ -0,0 +1,132 @@
|
||||
import { readFileSync } from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname, join } from 'path';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
export function iconifyPlugin() {
|
||||
const iconCache = new Map();
|
||||
const collections = new Map();
|
||||
|
||||
function loadCollection(prefix) {
|
||||
if (collections.has(prefix)) {
|
||||
return collections.get(prefix);
|
||||
}
|
||||
|
||||
try {
|
||||
const collectionPath = join(__dirname, 'node_modules', '@iconify-json', prefix, 'icons.json');
|
||||
const data = JSON.parse(readFileSync(collectionPath, 'utf8'));
|
||||
collections.set(prefix, data);
|
||||
return data;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function getIconCSS(iconData, selector) {
|
||||
const { body, width, height } = iconData;
|
||||
const viewBox = `0 0 ${width || 24} ${height || 24}`;
|
||||
|
||||
// Create SVG data URI
|
||||
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="${viewBox}">${body}</svg>`;
|
||||
const dataUri = `data:image/svg+xml;base64,${Buffer.from(svg).toString('base64')}`;
|
||||
|
||||
return `${selector} {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
background-color: currentColor;
|
||||
-webkit-mask-image: url("${dataUri}");
|
||||
mask-image: url("${dataUri}");
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-repeat: no-repeat;
|
||||
-webkit-mask-size: 100% 100%;
|
||||
mask-size: 100% 100%;
|
||||
}`;
|
||||
}
|
||||
|
||||
return {
|
||||
name: 'vite-plugin-iconify',
|
||||
|
||||
transform(code, id) {
|
||||
// Only process files that might contain icon classes
|
||||
if (!id.endsWith('.tsx') && !id.endsWith('.jsx') && !id.endsWith('.ts') && !id.endsWith('.js')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Find all icon-[...] patterns
|
||||
const iconPattern = /icon-\[([^\]]+)\]/g;
|
||||
const matches = [...code.matchAll(iconPattern)];
|
||||
|
||||
if (matches.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Extract unique icons
|
||||
const icons = new Set(matches.map(m => m[1]));
|
||||
|
||||
// Generate CSS for each icon
|
||||
for (const iconName of icons) {
|
||||
if (iconCache.has(iconName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
// Parse icon name (e.g., "solar--add-square-bold-duotone")
|
||||
const parts = iconName.split('--');
|
||||
if (parts.length !== 2) continue;
|
||||
|
||||
const [prefix, name] = parts;
|
||||
|
||||
// Load collection
|
||||
const collection = loadCollection(prefix);
|
||||
if (!collection || !collection.icons || !collection.icons[name]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get icon data
|
||||
const iconData = collection.icons[name];
|
||||
|
||||
// Generate CSS
|
||||
const selector = `.icon-\\[${iconName}\\]`;
|
||||
const iconCSS = getIconCSS(iconData, selector);
|
||||
|
||||
iconCache.set(iconName, iconCSS);
|
||||
} catch (e) {
|
||||
// Silently skip failed icons
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
resolveId(id) {
|
||||
if (id === '/@iconify-css') {
|
||||
return id;
|
||||
}
|
||||
},
|
||||
|
||||
load(id) {
|
||||
if (id === '/@iconify-css') {
|
||||
const allCSS = Array.from(iconCache.values()).join('\n');
|
||||
return allCSS;
|
||||
}
|
||||
},
|
||||
|
||||
transformIndexHtml() {
|
||||
// Inject icon CSS into HTML
|
||||
const allCSS = Array.from(iconCache.values()).join('\n');
|
||||
if (allCSS) {
|
||||
return [
|
||||
{
|
||||
tag: 'style',
|
||||
attrs: { type: 'text/css' },
|
||||
children: allCSS,
|
||||
injectTo: 'head'
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -5,7 +5,9 @@ import { defineConfig } from "vite";
|
||||
export default defineConfig({
|
||||
publicDir: "public",
|
||||
base: "",
|
||||
build: "esnext",
|
||||
build: {
|
||||
target: "esnext",
|
||||
},
|
||||
esbuild: {
|
||||
supported: {
|
||||
"top-level-await": true, //browsers can handle top-level-await features
|
||||
|
||||
Reference in New Issue
Block a user