hotfix godspeed
This commit is contained in:
parent
e34d564b4d
commit
7b670c1f93
6 changed files with 212 additions and 151 deletions
22
website/package-lock.json
generated
22
website/package-lock.json
generated
|
|
@ -53,7 +53,8 @@
|
||||||
"tailwindcss": "^4.1.7",
|
"tailwindcss": "^4.1.7",
|
||||||
"tw-animate-css": "^1.3.0",
|
"tw-animate-css": "^1.3.0",
|
||||||
"typescript": "^5.0.0",
|
"typescript": "^5.0.0",
|
||||||
"vite": "^5.4.11"
|
"vite": "^5.4.11",
|
||||||
|
"vite-plugin-iso-import": "^1.2.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@rollup/rollup-linux-x64-gnu": "*"
|
"@rollup/rollup-linux-x64-gnu": "*"
|
||||||
|
|
@ -3689,6 +3690,12 @@
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/es-module-lexer": {
|
||||||
|
"version": "1.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
|
||||||
|
"integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/es-object-atoms": {
|
"node_modules/es-object-atoms": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
@ -5754,6 +5761,19 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vite-plugin-iso-import": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/vite-plugin-iso-import/-/vite-plugin-iso-import-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-z8EI6cbN6Gg8ht09KAgkUlaC4XLuvZAEJenIyB5AsASQ0nfiXg0E670SBmv8qx48ZzGbEDgYTCOgxcRZJ3ROXw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"es-module-lexer": "^1.6.0",
|
||||||
|
"magic-string": "^0.30.17"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vite": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vite/node_modules/esbuild": {
|
"node_modules/vite/node_modules/esbuild": {
|
||||||
"version": "0.21.5",
|
"version": "0.21.5",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,8 @@
|
||||||
"tailwindcss": "^4.1.7",
|
"tailwindcss": "^4.1.7",
|
||||||
"tw-animate-css": "^1.3.0",
|
"tw-animate-css": "^1.3.0",
|
||||||
"typescript": "^5.0.0",
|
"typescript": "^5.0.0",
|
||||||
"vite": "^5.4.11"
|
"vite": "^5.4.11",
|
||||||
|
"vite-plugin-iso-import": "^1.2.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "^3.815.0",
|
"@aws-sdk/client-s3": "^3.815.0",
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
import CoinSkeleton from '$lib/components/self/skeletons/CoinSkeleton.svelte';
|
import CoinSkeleton from '$lib/components/self/skeletons/CoinSkeleton.svelte';
|
||||||
import TopHolders from '$lib/components/self/TopHolders.svelte';
|
import TopHolders from '$lib/components/self/TopHolders.svelte';
|
||||||
import { TrendingUp, TrendingDown, DollarSign, Coins, ChartColumn } from 'lucide-svelte';
|
import { TrendingUp, TrendingDown, DollarSign, Coins, ChartColumn } from 'lucide-svelte';
|
||||||
import { onMount } from 'svelte';
|
import { onMount, onDestroy } from 'svelte';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { toast } from 'svelte-sonner';
|
import { toast } from 'svelte-sonner';
|
||||||
import CoinIcon from '$lib/components/self/CoinIcon.svelte';
|
import CoinIcon from '$lib/components/self/CoinIcon.svelte';
|
||||||
|
|
@ -44,6 +44,8 @@
|
||||||
let candlestickSeries: any = null;
|
let candlestickSeries: any = null;
|
||||||
let volumeSeries: any = null;
|
let volumeSeries: any = null;
|
||||||
let chartLibrary: any = null;
|
let chartLibrary: any = null;
|
||||||
|
let chartInitialized = $state(false);
|
||||||
|
let resizeHandler: (() => void) | null = null;
|
||||||
|
|
||||||
const timeframeOptions = [
|
const timeframeOptions = [
|
||||||
{ value: '1m', label: '1 minute' },
|
{ value: '1m', label: '1 minute' },
|
||||||
|
|
@ -58,8 +60,14 @@
|
||||||
// Only import chart library on client-side
|
// Only import chart library on client-side
|
||||||
if (browser) {
|
if (browser) {
|
||||||
try {
|
try {
|
||||||
const { createChart, ColorType, CandlestickSeries, HistogramSeries } = await import('lightweight-charts');
|
const chartModule = await import('lightweight-charts');
|
||||||
chartLibrary = { createChart, ColorType, CandlestickSeries, HistogramSeries };
|
chartLibrary = {
|
||||||
|
createChart: chartModule.createChart,
|
||||||
|
ColorType: chartModule.ColorType,
|
||||||
|
CandlestickSeries: chartModule.CandlestickSeries,
|
||||||
|
HistogramSeries: chartModule.HistogramSeries
|
||||||
|
};
|
||||||
|
console.log('Chart library loaded successfully');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to load chart library:', e);
|
console.error('Failed to load chart library:', e);
|
||||||
}
|
}
|
||||||
|
|
@ -67,20 +75,41 @@
|
||||||
|
|
||||||
await loadUserHolding();
|
await loadUserHolding();
|
||||||
|
|
||||||
websocketController.setCoin(coinSymbol.toUpperCase());
|
if (browser) {
|
||||||
websocketController.subscribeToPriceUpdates(coinSymbol.toUpperCase(), handlePriceUpdate);
|
websocketController.setCoin(coinSymbol.toUpperCase());
|
||||||
|
websocketController.subscribeToPriceUpdates(coinSymbol.toUpperCase(), handlePriceUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
previousCoinSymbol = coinSymbol;
|
previousCoinSymbol = coinSymbol;
|
||||||
});
|
});
|
||||||
|
|
||||||
$effect(() => {
|
onDestroy(() => {
|
||||||
return () => {
|
if (browser) {
|
||||||
|
cleanupChart();
|
||||||
if (previousCoinSymbol) {
|
if (previousCoinSymbol) {
|
||||||
websocketController.unsubscribeFromPriceUpdates(previousCoinSymbol.toUpperCase());
|
websocketController.unsubscribeFromPriceUpdates(previousCoinSymbol.toUpperCase());
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function cleanupChart() {
|
||||||
|
if (!browser) return;
|
||||||
|
|
||||||
|
if (resizeHandler) {
|
||||||
|
window.removeEventListener('resize', resizeHandler);
|
||||||
|
resizeHandler = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chart) {
|
||||||
|
chart.remove();
|
||||||
|
chart = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
candlestickSeries = null;
|
||||||
|
volumeSeries = null;
|
||||||
|
chartInitialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (coinSymbol && previousCoinSymbol && coinSymbol !== previousCoinSymbol) {
|
if (coinSymbol && previousCoinSymbol && coinSymbol !== previousCoinSymbol) {
|
||||||
loading = true;
|
loading = true;
|
||||||
|
|
@ -89,145 +118,31 @@
|
||||||
volumeData = [];
|
volumeData = [];
|
||||||
userHolding = 0;
|
userHolding = 0;
|
||||||
|
|
||||||
websocketController.unsubscribeFromPriceUpdates(previousCoinSymbol.toUpperCase());
|
if (browser) {
|
||||||
|
websocketController.unsubscribeFromPriceUpdates(previousCoinSymbol.toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
loadCoinData().then(() => {
|
loadCoinData().then(() => {
|
||||||
loadUserHolding();
|
loadUserHolding();
|
||||||
websocketController.setCoin(coinSymbol.toUpperCase());
|
if (browser) {
|
||||||
websocketController.subscribeToPriceUpdates(coinSymbol.toUpperCase(), handlePriceUpdate);
|
websocketController.setCoin(coinSymbol.toUpperCase());
|
||||||
|
websocketController.subscribeToPriceUpdates(coinSymbol.toUpperCase(), handlePriceUpdate);
|
||||||
|
}
|
||||||
previousCoinSymbol = coinSymbol;
|
previousCoinSymbol = coinSymbol;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
async function loadCoinData() {
|
// Chart initialization effect
|
||||||
try {
|
|
||||||
loading = true;
|
|
||||||
const response = await fetch(`/api/coin/${coinSymbol}?timeframe=${selectedTimeframe}`);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
toast.error(response.status === 404 ? 'Coin not found' : 'Failed to load coin data');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await response.json();
|
|
||||||
coin = result.coin;
|
|
||||||
chartData = result.candlestickData || [];
|
|
||||||
volumeData = result.volumeData || [];
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Failed to fetch coin data:', e);
|
|
||||||
toast.error('Failed to load coin data');
|
|
||||||
} finally {
|
|
||||||
loading = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadUserHolding() {
|
|
||||||
if (!$USER_DATA) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await fetch('/api/portfolio/total');
|
|
||||||
if (response.ok) {
|
|
||||||
const result = await response.json();
|
|
||||||
const holding = result.coinHoldings.find((h: any) => h.symbol === coinSymbol.toUpperCase());
|
|
||||||
userHolding = holding ? holding.quantity : 0;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Failed to load user holding:', e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function handleTradeSuccess() {
|
|
||||||
await Promise.all([loadCoinData(), loadUserHolding(), fetchPortfolioSummary()]);
|
|
||||||
}
|
|
||||||
function handlePriceUpdate(priceUpdate: PriceUpdate) {
|
|
||||||
if (coin && priceUpdate.coinSymbol === coinSymbol.toUpperCase()) {
|
|
||||||
// throttle updates to prevent excessive UI updates, 1s interval
|
|
||||||
const now = Date.now();
|
|
||||||
if (now - lastPriceUpdateTime < 1000) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lastPriceUpdateTime = now;
|
|
||||||
|
|
||||||
coin = {
|
|
||||||
...coin,
|
|
||||||
currentPrice: priceUpdate.currentPrice,
|
|
||||||
marketCap: priceUpdate.marketCap,
|
|
||||||
change24h: priceUpdate.change24h,
|
|
||||||
volume24h: priceUpdate.volume24h,
|
|
||||||
...(priceUpdate.poolCoinAmount !== undefined && {
|
|
||||||
poolCoinAmount: priceUpdate.poolCoinAmount
|
|
||||||
}),
|
|
||||||
...(priceUpdate.poolBaseCurrencyAmount !== undefined && {
|
|
||||||
poolBaseCurrencyAmount: priceUpdate.poolBaseCurrencyAmount
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
updateChartRealtime(priceUpdate.currentPrice);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateChartRealtime(newPrice: number) {
|
|
||||||
if (!candlestickSeries || !chart || chartData.length === 0) return;
|
|
||||||
|
|
||||||
const timeframeSeconds = getTimeframeInSeconds(selectedTimeframe);
|
|
||||||
const currentTime = Math.floor(Date.now() / 1000);
|
|
||||||
|
|
||||||
const currentCandleTime = Math.floor(currentTime / timeframeSeconds) * timeframeSeconds;
|
|
||||||
const localCandleTime = timeToLocal(currentCandleTime);
|
|
||||||
|
|
||||||
const lastCandle = chartData[chartData.length - 1];
|
|
||||||
|
|
||||||
if (lastCandle && lastCandle.time === localCandleTime) {
|
|
||||||
const updatedCandle = {
|
|
||||||
time: localCandleTime,
|
|
||||||
open: lastCandle.open,
|
|
||||||
high: Math.max(lastCandle.high, newPrice),
|
|
||||||
low: Math.min(lastCandle.low, newPrice),
|
|
||||||
close: newPrice
|
|
||||||
};
|
|
||||||
|
|
||||||
candlestickSeries.update(updatedCandle);
|
|
||||||
chartData[chartData.length - 1] = updatedCandle;
|
|
||||||
} else if (localCandleTime > (lastCandle?.time || 0)) {
|
|
||||||
const newCandle = {
|
|
||||||
time: localCandleTime,
|
|
||||||
open: newPrice,
|
|
||||||
high: newPrice,
|
|
||||||
low: newPrice,
|
|
||||||
close: newPrice
|
|
||||||
};
|
|
||||||
|
|
||||||
candlestickSeries.update(newCandle);
|
|
||||||
chartData.push(newCandle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleTimeframeChange(timeframe: string) {
|
|
||||||
selectedTimeframe = timeframe;
|
|
||||||
loading = true;
|
|
||||||
|
|
||||||
if (chart) {
|
|
||||||
chart.remove();
|
|
||||||
chart = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
await loadCoinData();
|
|
||||||
loading = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let currentTimeframeLabel = $derived(
|
|
||||||
timeframeOptions.find((option) => option.value === selectedTimeframe)?.label || '1 minute'
|
|
||||||
);
|
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (!browser || !chartLibrary) return;
|
if (!browser || !chartLibrary || !chartContainer || !chartData || chartData.length === 0) {
|
||||||
|
return;
|
||||||
if (chart && chartData.length > 0) {
|
|
||||||
chart.remove();
|
|
||||||
chart = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chartContainer && chartData.length > 0) {
|
// Clean up existing chart
|
||||||
|
cleanupChart();
|
||||||
|
|
||||||
|
try {
|
||||||
const { createChart, ColorType, CandlestickSeries, HistogramSeries } = chartLibrary;
|
const { createChart, ColorType, CandlestickSeries, HistogramSeries } = chartLibrary;
|
||||||
|
|
||||||
chart = createChart(chartContainer, {
|
chart = createChart(chartContainer, {
|
||||||
|
|
@ -306,24 +221,147 @@
|
||||||
|
|
||||||
chart.timeScale().fitContent();
|
chart.timeScale().fitContent();
|
||||||
|
|
||||||
const handleResize = () => chart?.applyOptions({ width: chartContainer?.clientWidth });
|
// Setup resize handler
|
||||||
window.addEventListener('resize', handleResize);
|
resizeHandler = () => {
|
||||||
handleResize();
|
if (chart && chartContainer) {
|
||||||
|
chart.applyOptions({ width: chartContainer.clientWidth });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
window.addEventListener('resize', resizeHandler);
|
||||||
|
resizeHandler(); // Initial call
|
||||||
|
|
||||||
candlestickSeries.priceScale().applyOptions({ borderColor: '#71649C' });
|
candlestickSeries.priceScale().applyOptions({ borderColor: '#71649C' });
|
||||||
volumeSeries.priceScale().applyOptions({ borderColor: '#71649C' });
|
volumeSeries.priceScale().applyOptions({ borderColor: '#71649C' });
|
||||||
chart.timeScale().applyOptions({ borderColor: '#71649C' });
|
chart.timeScale().applyOptions({ borderColor: '#71649C' });
|
||||||
|
|
||||||
return () => {
|
chartInitialized = true;
|
||||||
window.removeEventListener('resize', handleResize);
|
console.log('Chart initialized successfully');
|
||||||
if (chart) {
|
} catch (error) {
|
||||||
chart.remove();
|
console.error('Failed to initialize chart:', error);
|
||||||
chart = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function loadCoinData() {
|
||||||
|
try {
|
||||||
|
loading = true;
|
||||||
|
const response = await fetch(`/api/coin/${coinSymbol}?timeframe=${selectedTimeframe}`);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
toast.error(response.status === 404 ? 'Coin not found' : 'Failed to load coin data');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
coin = result.coin;
|
||||||
|
chartData = result.candlestickData || [];
|
||||||
|
volumeData = result.volumeData || [];
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to fetch coin data:', e);
|
||||||
|
toast.error('Failed to load coin data');
|
||||||
|
} finally {
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadUserHolding() {
|
||||||
|
if (!$USER_DATA) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/portfolio/total');
|
||||||
|
if (response.ok) {
|
||||||
|
const result = await response.json();
|
||||||
|
const holding = result.coinHoldings.find((h: any) => h.symbol === coinSymbol.toUpperCase());
|
||||||
|
userHolding = holding ? holding.quantity : 0;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to load user holding:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleTradeSuccess() {
|
||||||
|
await Promise.all([loadCoinData(), loadUserHolding(), fetchPortfolioSummary()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePriceUpdate(priceUpdate: PriceUpdate) {
|
||||||
|
if (!browser || !coin || priceUpdate.coinSymbol !== coinSymbol.toUpperCase()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// throttle updates to prevent excessive UI updates, 1s interval
|
||||||
|
const now = Date.now();
|
||||||
|
if (now - lastPriceUpdateTime < 1000) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lastPriceUpdateTime = now;
|
||||||
|
|
||||||
|
coin = {
|
||||||
|
...coin,
|
||||||
|
currentPrice: priceUpdate.currentPrice,
|
||||||
|
marketCap: priceUpdate.marketCap,
|
||||||
|
change24h: priceUpdate.change24h,
|
||||||
|
volume24h: priceUpdate.volume24h,
|
||||||
|
...(priceUpdate.poolCoinAmount !== undefined && {
|
||||||
|
poolCoinAmount: priceUpdate.poolCoinAmount
|
||||||
|
}),
|
||||||
|
...(priceUpdate.poolBaseCurrencyAmount !== undefined && {
|
||||||
|
poolBaseCurrencyAmount: priceUpdate.poolBaseCurrencyAmount
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
updateChartRealtime(priceUpdate.currentPrice);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateChartRealtime(newPrice: number) {
|
||||||
|
if (!browser || !candlestickSeries || !chart || chartData.length === 0) return;
|
||||||
|
|
||||||
|
const timeframeSeconds = getTimeframeInSeconds(selectedTimeframe);
|
||||||
|
const currentTime = Math.floor(Date.now() / 1000);
|
||||||
|
|
||||||
|
const currentCandleTime = Math.floor(currentTime / timeframeSeconds) * timeframeSeconds;
|
||||||
|
const localCandleTime = timeToLocal(currentCandleTime);
|
||||||
|
|
||||||
|
const lastCandle = chartData[chartData.length - 1];
|
||||||
|
|
||||||
|
if (lastCandle && lastCandle.time === localCandleTime) {
|
||||||
|
const updatedCandle = {
|
||||||
|
time: localCandleTime,
|
||||||
|
open: lastCandle.open,
|
||||||
|
high: Math.max(lastCandle.high, newPrice),
|
||||||
|
low: Math.min(lastCandle.low, newPrice),
|
||||||
|
close: newPrice
|
||||||
|
};
|
||||||
|
|
||||||
|
candlestickSeries.update(updatedCandle);
|
||||||
|
chartData[chartData.length - 1] = updatedCandle;
|
||||||
|
} else if (localCandleTime > (lastCandle?.time || 0)) {
|
||||||
|
const newCandle = {
|
||||||
|
time: localCandleTime,
|
||||||
|
open: newPrice,
|
||||||
|
high: newPrice,
|
||||||
|
low: newPrice,
|
||||||
|
close: newPrice
|
||||||
|
};
|
||||||
|
|
||||||
|
candlestickSeries.update(newCandle);
|
||||||
|
chartData.push(newCandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleTimeframeChange(timeframe: string) {
|
||||||
|
selectedTimeframe = timeframe;
|
||||||
|
loading = true;
|
||||||
|
|
||||||
|
// Clean up chart before loading new data
|
||||||
|
cleanupChart();
|
||||||
|
|
||||||
|
await loadCoinData();
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let currentTimeframeLabel = $derived(
|
||||||
|
timeframeOptions.find((option) => option.value === selectedTimeframe)?.label || '1 minute'
|
||||||
|
);
|
||||||
|
|
||||||
function formatPrice(price: number): string {
|
function formatPrice(price: number): string {
|
||||||
if (price < 0.000001) {
|
if (price < 0.000001) {
|
||||||
return price.toFixed(8);
|
return price.toFixed(8);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { chart } from 'svelte-apexcharts';
|
import { chart } from 'svelte-apexcharts?client';
|
||||||
// it doens't have types idk
|
// it doens't have types idk
|
||||||
import { Skeleton } from '$lib/components/ui/skeleton';
|
import { Skeleton } from '$lib/components/ui/skeleton';
|
||||||
import * as Card from '$lib/components/ui/card';
|
import * as Card from '$lib/components/ui/card';
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,8 @@
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"moduleResolution": "bundler"
|
"moduleResolution": "bundler",
|
||||||
|
"plugins": [{ "name": "vite-plugin-iso-import" }]
|
||||||
}
|
}
|
||||||
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
|
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
|
||||||
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
|
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { sveltekit } from '@sveltejs/kit/vite';
|
import { sveltekit } from '@sveltejs/kit/vite';
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
|
import { isoImport } from 'vite-plugin-iso-import';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [sveltekit()]
|
plugins: [sveltekit(), isoImport()]
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Reference in a new issue