fix(app): remove legacy and scoped namespace alias
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"hooks": "@/hooks",
|
||||
"lib": "@/lib",
|
||||
"components": "#dashboard/components",
|
||||
"hooks": "#dashboard/hooks",
|
||||
"lib": "#dashboard/lib",
|
||||
"ui": "@basango/ui/components",
|
||||
"utils": "@basango/ui/lib/utils"
|
||||
},
|
||||
|
||||
@@ -4,10 +4,13 @@
|
||||
"@basango/ui": "workspace:*",
|
||||
"@date-fns/tz": "^1.4.1",
|
||||
"@hookform/resolvers": "^5.2.2",
|
||||
"@tanstack/react-query": "^5.90.7",
|
||||
"@tanstack/react-query": "^5.90.8",
|
||||
"@tanstack/react-table": "^8.21.3",
|
||||
"@trpc/client": "^11.7.1",
|
||||
"@trpc/react-query": "^11.7.1",
|
||||
"@trpc/server": "^11.7.1",
|
||||
"@trpc/tanstack-react-query": "^11.7.1",
|
||||
"client-only": "^0.0.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"lucide-react": "^0.553.0",
|
||||
"next": "catalog:",
|
||||
@@ -18,6 +21,7 @@
|
||||
"react-dom": "catalog:",
|
||||
"react-hook-form": "^7.66.0",
|
||||
"recharts": "^3.4.1",
|
||||
"server-only": "^0.0.1",
|
||||
"superjson": "^2.2.5",
|
||||
"zod": "^4.1.12",
|
||||
"zustand": "^5.0.8"
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
import { Metadata } from "next";
|
||||
|
||||
import { PageLayout } from "#dashboard/components/shell/page-layout";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Articles | Basango Dashboard",
|
||||
};
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<div className="flex flex-1 flex-col gap-4 p-4 pt-0">
|
||||
<div className="grid auto-rows-min gap-4 md:grid-cols-3">
|
||||
<div className="bg-muted/50 aspect-video rounded-xl" />
|
||||
<div className="bg-muted/50 aspect-video rounded-xl" />
|
||||
<div className="bg-muted/50 aspect-video rounded-xl" />
|
||||
<PageLayout leading="Manage your articles" title="Articles">
|
||||
<div className="flex flex-1 flex-col gap-4">
|
||||
<div className="grid auto-rows-min gap-4 md:grid-cols-3">
|
||||
<div className="bg-muted/50 aspect-video rounded-xl" />
|
||||
<div className="bg-muted/50 aspect-video rounded-xl" />
|
||||
<div className="bg-muted/50 aspect-video rounded-xl" />
|
||||
</div>
|
||||
<div className="bg-muted/50 min-h-screen flex-1 rounded-xl md:min-h-min" />
|
||||
</div>
|
||||
<div className="bg-muted/50 min-h-screen flex-1 rounded-xl md:min-h-min" />
|
||||
</div>
|
||||
</PageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { SidebarInset, SidebarProvider } from "@basango/ui/components/sidebar";
|
||||
|
||||
import { PageHeader } from "@/components/shell/page-header";
|
||||
import { AppSidebar } from "@/components/sidebar/app-sidebar";
|
||||
import { HydrateClient } from "@/trpc/server";
|
||||
import { PageHeader } from "#dashboard/components/shell/page-header";
|
||||
import { AppSidebar } from "#dashboard/components/sidebar/app-sidebar";
|
||||
import { HydrateClient } from "#dashboard/trpc/server";
|
||||
|
||||
export default async function Layout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
|
||||
@@ -1,26 +1,31 @@
|
||||
import { RouterOutputs } from "@basango/api/trpc/routers/_app";
|
||||
import { Metadata } from "next";
|
||||
|
||||
import { PageLayout } from "@/components/shell/page-layout";
|
||||
import { SourceCard } from "@/components/source-card";
|
||||
import { batchPrefetch, getQueryClient, trpc } from "@/trpc/server";
|
||||
import { PageLayout } from "#dashboard/components/shell/page-layout";
|
||||
import { SourceCard } from "#dashboard/components/source-card";
|
||||
import { HydrateClient, getQueryClient, prefetch, trpc } from "#dashboard/trpc/server";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Sources | Basango Dashboard",
|
||||
};
|
||||
|
||||
type SourceDetails = RouterOutputs["sources"]["get"][number];
|
||||
|
||||
export default async function Page() {
|
||||
const queryClient = getQueryClient();
|
||||
|
||||
batchPrefetch([trpc.sources.get.queryOptions()]);
|
||||
prefetch(trpc.sources.get.queryOptions());
|
||||
const sources = await queryClient.fetchQuery(trpc.sources.get.queryOptions());
|
||||
|
||||
return (
|
||||
<PageLayout leading="Manage your news sources" title="Sources">
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-3">
|
||||
{sources.map((source) => (
|
||||
<SourceCard key={source.id} {...source} />
|
||||
))}
|
||||
</div>
|
||||
</PageLayout>
|
||||
<HydrateClient>
|
||||
<PageLayout leading="Manage your news sources" title="Sources">
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-3">
|
||||
{sources.map((source: SourceDetails) => (
|
||||
<SourceCard key={source.id} source={source} />
|
||||
))}
|
||||
</div>
|
||||
</PageLayout>
|
||||
</HydrateClient>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { GalleryVerticalEnd } from "lucide-react";
|
||||
|
||||
import { LoginForm } from "@/components/forms/login-form";
|
||||
import { LoginForm } from "#dashboard/components/forms/login-form";
|
||||
|
||||
export default function LoginPage() {
|
||||
return (
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
import { ThemeProvider } from "next-themes";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
import { I18nProviderClient } from "@/locales/client";
|
||||
import { TRPCReactProvider } from "@/trpc/client";
|
||||
import { I18nProviderClient } from "#dashboard/locales/client";
|
||||
import { TRPCReactProvider } from "#dashboard/trpc/client";
|
||||
|
||||
type ProviderProps = {
|
||||
locale: string;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import { Badge } from "@basango/ui/components/badge";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@basango/ui/components/card";
|
||||
@@ -14,49 +14,9 @@ import {
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
} from "@basango/ui/components/chart";
|
||||
import { Separator } from "@basango/ui/components/separator";
|
||||
import { Bar, BarChart, CartesianGrid, XAxis } from "recharts";
|
||||
|
||||
interface CredibilityMetric {
|
||||
bias: string;
|
||||
reliability: string;
|
||||
transparency: string;
|
||||
}
|
||||
|
||||
interface PublicationItem {
|
||||
date: string;
|
||||
count: number;
|
||||
}
|
||||
|
||||
interface SourceCardProps {
|
||||
id: string;
|
||||
name: string;
|
||||
displayName: string | null;
|
||||
url: string;
|
||||
description: string;
|
||||
publicationGraph: {
|
||||
items: PublicationItem[];
|
||||
total: number;
|
||||
};
|
||||
credibility: CredibilityMetric;
|
||||
}
|
||||
|
||||
const credibilityColors = {
|
||||
high: "bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200",
|
||||
low: "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200",
|
||||
medium: "bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200",
|
||||
};
|
||||
|
||||
function getCredibilityColor(value: string): string {
|
||||
const lower = value.toLowerCase();
|
||||
if (lower.includes("high") || lower.includes("strong") || lower.includes("good")) {
|
||||
return credibilityColors.high;
|
||||
}
|
||||
if (lower.includes("medium") || lower.includes("moderate")) {
|
||||
return credibilityColors.medium;
|
||||
}
|
||||
return credibilityColors.low;
|
||||
}
|
||||
import { formatNumber } from "#dashboard/utils/utils";
|
||||
|
||||
const chartConfig = {
|
||||
count: {
|
||||
@@ -68,50 +28,34 @@ const chartConfig = {
|
||||
},
|
||||
} satisfies ChartConfig;
|
||||
|
||||
export function SourceCard({
|
||||
id,
|
||||
name,
|
||||
displayName,
|
||||
url,
|
||||
description,
|
||||
publicationGraph,
|
||||
credibility,
|
||||
}: SourceCardProps) {
|
||||
const chartData = publicationGraph.items;
|
||||
type SourceDetails = {
|
||||
id: string;
|
||||
name: string;
|
||||
displayName: string | null;
|
||||
url: string;
|
||||
description: string;
|
||||
publicationGraph: {
|
||||
items: { date: string; count: number }[];
|
||||
total: number;
|
||||
};
|
||||
credibility: {
|
||||
bias: string;
|
||||
reliability: string;
|
||||
transparency: string;
|
||||
};
|
||||
articles: number;
|
||||
};
|
||||
|
||||
export function SourceCard({ source }: { source: SourceDetails }) {
|
||||
return (
|
||||
<Card className="w-full max-w-6xl border-border">
|
||||
<CardHeader className="border-b">
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="space-y-2 flex-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<CardTitle>
|
||||
<a
|
||||
aria-label="Visit source website"
|
||||
href={url}
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
{displayName || name}
|
||||
</a>
|
||||
</CardTitle>
|
||||
</div>
|
||||
<CardDescription className="text-base">{description}</CardDescription>
|
||||
<p className="text-xs text-muted-foreground">ID: {id}</p>
|
||||
</div>
|
||||
</div>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>{source.name}</CardTitle>
|
||||
<CardDescription>{source.id}</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="space-y-6">
|
||||
<ChartContainer className="aspect-auto h-[250px] w-full" config={chartConfig}>
|
||||
<BarChart
|
||||
accessibilityLayer
|
||||
data={chartData}
|
||||
margin={{
|
||||
left: 12,
|
||||
right: 12,
|
||||
}}
|
||||
>
|
||||
<CardContent>
|
||||
<ChartContainer config={chartConfig}>
|
||||
<BarChart accessibilityLayer data={source.publicationGraph.items}>
|
||||
<CartesianGrid vertical={false} />
|
||||
<XAxis
|
||||
axisLine={false}
|
||||
@@ -127,65 +71,19 @@ export function SourceCard({
|
||||
tickLine={false}
|
||||
tickMargin={8}
|
||||
/>
|
||||
<ChartTooltip
|
||||
content={
|
||||
<ChartTooltipContent
|
||||
className="w-[150px]"
|
||||
labelFormatter={(value) => {
|
||||
return new Date(value).toLocaleDateString("en-US", {
|
||||
day: "numeric",
|
||||
month: "short",
|
||||
year: "numeric",
|
||||
});
|
||||
}}
|
||||
nameKey="views"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Bar dataKey="count" fill={`var(--color-2)`} />
|
||||
<ChartTooltip content={<ChartTooltipContent indicator="dashed" />} cursor={false} />
|
||||
<Bar dataKey="count" fill="var(--color-count)" radius={4} />
|
||||
</BarChart>
|
||||
</ChartContainer>
|
||||
|
||||
<Separator />
|
||||
<div className="space-y-2">
|
||||
<h3 className="font-semibold">Credibility Metrics</h3>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm font-medium text-muted-foreground">Bias</p>
|
||||
<Badge className={`${getCredibilityColor(credibility.bias)} border-0`}>
|
||||
{credibility.bias}
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm font-medium text-muted-foreground">Reliability</p>
|
||||
<Badge className={`${getCredibilityColor(credibility.reliability)} border-0`}>
|
||||
{credibility.reliability}
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm font-medium text-muted-foreground">Transparency</p>
|
||||
<Badge className={`${getCredibilityColor(credibility.transparency)} border-0`}>
|
||||
{credibility.transparency}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
<div className="space-y-2">
|
||||
<h3 className="font-semibold">Summary</h3>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<p className="text-sm text-muted-foreground">Total Publications</p>
|
||||
<p className="text-2xl font-bold">{publicationGraph.total}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm text-muted-foreground">Timeline Entries</p>
|
||||
<p className="text-2xl font-bold">{publicationGraph.items.length}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
<CardFooter className="flex-col items-start gap-2 text-sm">
|
||||
<div className="flex gap-2 leading-none font-medium">
|
||||
{formatNumber(source.articles)} articles crawled
|
||||
</div>
|
||||
<div className="text-muted-foreground leading-none">
|
||||
Showing last {source.publicationGraph.total} days
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
import type { AppRouter } from "@basango/api/trpc/routers/_app";
|
||||
import type { QueryClient } from "@tanstack/react-query";
|
||||
import { QueryClientProvider, isServer } from "@tanstack/react-query";
|
||||
import { createTRPCClient, httpBatchLink, loggerLink } from "@trpc/client";
|
||||
import { QueryClientProvider } from "@tanstack/react-query";
|
||||
import { createTRPCClient, httpBatchLink } from "@trpc/client";
|
||||
import { createTRPCContext } from "@trpc/tanstack-react-query";
|
||||
import { useState } from "react";
|
||||
import superjson from "superjson";
|
||||
@@ -15,7 +15,7 @@ export const { TRPCProvider, useTRPC } = createTRPCContext<AppRouter>();
|
||||
let browserQueryClient: QueryClient;
|
||||
|
||||
function getQueryClient() {
|
||||
if (isServer) {
|
||||
if (typeof window === "undefined") {
|
||||
// Server: always make a new query client
|
||||
return makeQueryClient();
|
||||
}
|
||||
@@ -34,25 +34,25 @@ export function TRPCReactProvider(
|
||||
children: React.ReactNode;
|
||||
}>,
|
||||
) {
|
||||
// NOTE: Avoid useState when initializing the query client if you don't
|
||||
// have a suspense boundary between this and the code that may
|
||||
// suspend because React will throw away the client on the initial
|
||||
// render if it suspends and there is no boundary
|
||||
const queryClient = getQueryClient();
|
||||
const [trpcClient] = useState(() =>
|
||||
createTRPCClient<AppRouter>({
|
||||
links: [
|
||||
httpBatchLink({
|
||||
async headers() {
|
||||
const token = window.localStorage.getItem("auth_token");
|
||||
headers: async () => {
|
||||
//const token = window.localStorage.getItem("auth_token");
|
||||
|
||||
return {
|
||||
Authorization: `Bearer ${token}`,
|
||||
//Authorization: `Bearer ${token}`,
|
||||
};
|
||||
},
|
||||
transformer: superjson,
|
||||
url: `${process.env.NEXT_PUBLIC_API_URL}/trpc`,
|
||||
}),
|
||||
loggerLink({
|
||||
enabled: (opts) =>
|
||||
process.env.NODE_ENV === "development" ||
|
||||
(opts.direction === "down" && opts.result instanceof Error),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/** biome-ignore-all lint/suspicious/noExplicitAny: needed for tRPC type inference */
|
||||
import "server-only";
|
||||
|
||||
import type { AppRouter } from "@basango/api/trpc/routers/_app";
|
||||
//import { getCountryCode, getLocale, getTimezone } from "@basango/location";
|
||||
import { HydrationBoundary, dehydrate } from "@tanstack/react-query";
|
||||
import { createTRPCClient, httpBatchLink, loggerLink } from "@trpc/client";
|
||||
import { type TRPCQueryOptions, createTRPCOptionsProxy } from "@trpc/tanstack-react-query";
|
||||
@@ -43,38 +43,14 @@ export const trpc = createTRPCOptionsProxy<AppRouter>({
|
||||
|
||||
export function HydrateClient(props: { children: React.ReactNode }) {
|
||||
const queryClient = getQueryClient();
|
||||
|
||||
return <HydrationBoundary state={dehydrate(queryClient)}>{props.children}</HydrationBoundary>;
|
||||
}
|
||||
|
||||
export function prefetch<T extends ReturnType<TRPCQueryOptions<AppRouter>>>(queryOptions: T) {
|
||||
export function prefetch<T extends ReturnType<TRPCQueryOptions<any>>>(queryOptions: T) {
|
||||
const queryClient = getQueryClient();
|
||||
|
||||
if (queryOptions.queryKey[1]?.type === "infinite") {
|
||||
void queryClient.prefetchInfiniteQuery(
|
||||
queryOptions as unknown as Parameters<typeof queryClient.prefetchInfiniteQuery>[0],
|
||||
);
|
||||
void queryClient.prefetchInfiniteQuery(queryOptions as any);
|
||||
} else {
|
||||
void queryClient.prefetchQuery(
|
||||
queryOptions as unknown as Parameters<typeof queryClient.prefetchQuery>[0],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function batchPrefetch<T extends ReturnType<TRPCQueryOptions<AppRouter>>>(
|
||||
queryOptionsArray: T[],
|
||||
) {
|
||||
const queryClient = getQueryClient();
|
||||
|
||||
for (const queryOptions of queryOptionsArray) {
|
||||
if (queryOptions.queryKey[1]?.type === "infinite") {
|
||||
void queryClient.prefetchInfiniteQuery(
|
||||
queryOptions as unknown as Parameters<typeof queryClient.prefetchInfiniteQuery>[0],
|
||||
);
|
||||
} else {
|
||||
void queryClient.prefetchQuery(
|
||||
queryOptions as unknown as Parameters<typeof queryClient.prefetchQuery>[0],
|
||||
);
|
||||
}
|
||||
void queryClient.prefetchQuery(queryOptions);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
import type { TZDate } from "@date-fns/tz";
|
||||
import { format, isSameYear } from "date-fns";
|
||||
|
||||
export function formatSize(bytes: number): string {
|
||||
const units = ["byte", "kilobyte", "megabyte", "gigabyte", "terabyte"];
|
||||
|
||||
const unitIndex = Math.max(
|
||||
0,
|
||||
Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1),
|
||||
);
|
||||
|
||||
return Intl.NumberFormat("en-US", {
|
||||
style: "unit",
|
||||
unit: units[unitIndex],
|
||||
}).format(+Math.round(bytes / 1024 ** unitIndex));
|
||||
}
|
||||
|
||||
export function secondsToHoursAndMinutes(seconds: number) {
|
||||
const hours = Math.floor(seconds / 3600);
|
||||
const minutes = Math.floor((seconds % 3600) / 60);
|
||||
|
||||
if (hours && minutes) {
|
||||
return `${hours}h ${minutes}m`;
|
||||
}
|
||||
|
||||
if (hours) {
|
||||
return `${hours}h`;
|
||||
}
|
||||
|
||||
if (minutes) {
|
||||
return `${minutes}m`;
|
||||
}
|
||||
|
||||
return "0m";
|
||||
}
|
||||
|
||||
export function formatDate(date: string, dateFormat?: string | null, checkYear = true) {
|
||||
if (checkYear && isSameYear(new Date(), new Date(date))) {
|
||||
return format(new Date(date), "MMM d");
|
||||
}
|
||||
|
||||
return format(new Date(date), dateFormat ?? "P");
|
||||
}
|
||||
|
||||
export function formatNumber(value: number): string {
|
||||
return Intl.NumberFormat("en-US").format(value);
|
||||
}
|
||||
|
||||
export function getInitials(value: string) {
|
||||
const formatted = value.toUpperCase().replace(/[\s.-]/g, "");
|
||||
|
||||
if (formatted.split(" ").length > 1) {
|
||||
return `${formatted.charAt(0)}${formatted.charAt(1)}`;
|
||||
}
|
||||
|
||||
if (value.length > 1) {
|
||||
return formatted.charAt(0) + formatted.charAt(1);
|
||||
}
|
||||
|
||||
return formatted.charAt(0);
|
||||
}
|
||||
|
||||
export function formatDateRange(dates: TZDate[]): string {
|
||||
if (!dates.length) return "";
|
||||
|
||||
const formatFullDate = (date: TZDate) => format(date, "MMM d");
|
||||
const formatDay = (date: TZDate) => format(date, "d");
|
||||
|
||||
const startDate = dates[0];
|
||||
const endDate = dates[1];
|
||||
|
||||
if (!startDate) return "";
|
||||
|
||||
if (dates.length === 1 || !endDate || startDate.getTime() === endDate.getTime()) {
|
||||
return formatFullDate(startDate);
|
||||
}
|
||||
|
||||
if (startDate.getMonth() === endDate.getMonth()) {
|
||||
// Same month
|
||||
return `${format(startDate, "MMM")} ${formatDay(startDate)} - ${formatDay(endDate)}`;
|
||||
}
|
||||
// Different months
|
||||
return `${formatFullDate(startDate)} - ${formatFullDate(endDate)}`;
|
||||
}
|
||||
|
||||
export function formatRelativeTime(date: Date): string {
|
||||
const now = new Date();
|
||||
const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000);
|
||||
|
||||
if (diffInSeconds < 60) {
|
||||
return "just now";
|
||||
}
|
||||
|
||||
const intervals = [
|
||||
{ label: "y", seconds: 31536000 },
|
||||
{ label: "mo", seconds: 2592000 },
|
||||
{ label: "d", seconds: 86400 },
|
||||
{ label: "h", seconds: 3600 },
|
||||
{ label: "m", seconds: 60 },
|
||||
] as const;
|
||||
|
||||
for (const interval of intervals) {
|
||||
const count = Math.floor(diffInSeconds / interval.seconds);
|
||||
if (count > 0) {
|
||||
return `${count}${interval.label} ago`;
|
||||
}
|
||||
}
|
||||
|
||||
return "just now";
|
||||
}
|
||||
@@ -2,8 +2,9 @@
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"],
|
||||
"@basango/ui/*": ["../../packages/ui/src/*"]
|
||||
"@basango/api/*": ["../api/src/*"],
|
||||
"@basango/ui/*": ["../../packages/ui/src/*"],
|
||||
"#dashboard/*": ["./src/*"]
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
@@ -13,12 +14,10 @@
|
||||
},
|
||||
"exclude": ["node_modules"],
|
||||
"extends": "@basango/tsconfig/nextjs.json",
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"next.config.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts",
|
||||
"../../packages/ui/src/hooks/use-mobile.ts"
|
||||
"include": ["next-env.d.ts", "next.config.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../api"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user