diff --git a/app/frontend/components/data_table.tsx b/app/frontend/components/data_table.tsx index 7a83577..30fb045 100644 --- a/app/frontend/components/data_table.tsx +++ b/app/frontend/components/data_table.tsx @@ -18,16 +18,20 @@ import { TableRow, } from "@/components/ui/table"; +import { cn } from "@/utils/ui"; + interface DataTableProps { columns: ColumnDef[]; data: TData[]; pagination: PaginatorProps; + className?: string; } export function DataTable({ columns, data, pagination, + className, }: DataTableProps) { const table = useReactTable({ data, @@ -38,7 +42,7 @@ export function DataTable({ return ( <> -
+
{table.getHeaderGroups().map((headerGroup) => ( diff --git a/app/frontend/components/external_link.tsx b/app/frontend/components/external_link.tsx index d8bdd46..54f9df8 100644 --- a/app/frontend/components/external_link.tsx +++ b/app/frontend/components/external_link.tsx @@ -1,22 +1,32 @@ -import { Link, type LucideProps } from "lucide-react"; +import { Link as LinkIcon, type LucideProps } from "lucide-react"; + +import { Button } from "@/components/ui/button"; + +import { cn } from "@/utils/ui"; interface Props { href: string; children: React.ReactNode; icon?: React.ForwardRefExoticComponent< Omit & React.RefAttributes - >; + > | null; + className?: string; } -function ExternalLink({ href, children, icon }: Props) { - const Icon = icon || Link; +function ExternalLink({ href, children, icon, className }: Props) { + const Icon = icon || LinkIcon; return ( -
- - - {children} - +
+ {icon !== null && ( + + )} + +
); } diff --git a/app/frontend/components/link.tsx b/app/frontend/components/link.tsx new file mode 100644 index 0000000..c66c389 --- /dev/null +++ b/app/frontend/components/link.tsx @@ -0,0 +1,15 @@ +import { Link as InertiaLink, InertiaLinkProps } from "@inertiajs/react"; + +import { Button } from "@/components/ui/button"; + +interface Props extends InertiaLinkProps {} + +function Link({ children, ...props }: Props) { + return ( + + ); +} + +export default Link; diff --git a/app/frontend/components/ui/button.tsx b/app/frontend/components/ui/button.tsx index efd711c..be55654 100644 --- a/app/frontend/components/ui/button.tsx +++ b/app/frontend/components/ui/button.tsx @@ -1,8 +1,8 @@ -import * as React from "react" -import { Slot } from "@radix-ui/react-slot" -import { cva, type VariantProps } from "class-variance-authority" +import * as React from "react"; +import { Slot } from "@radix-ui/react-slot"; +import { type VariantProps, cva } from "class-variance-authority"; -import { cn } from "@/utils/ui" +import { cn } from "@/utils/ui"; const buttonVariants = cva( "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", @@ -30,27 +30,27 @@ const buttonVariants = cva( variant: "default", size: "default", }, - } -) + }, +); export interface ButtonProps extends React.ButtonHTMLAttributes, VariantProps { - asChild?: boolean + asChild?: boolean; } const Button = React.forwardRef( ({ className, variant, size, asChild = false, ...props }, ref) => { - const Comp = asChild ? Slot : "button" + const Comp = asChild ? Slot : "button"; return ( - ) - } -) -Button.displayName = "Button" + ); + }, +); +Button.displayName = "Button"; -export { Button, buttonVariants } +export { Button, buttonVariants }; diff --git a/app/frontend/components/ui/card.tsx b/app/frontend/components/ui/card.tsx new file mode 100644 index 0000000..3f9d527 --- /dev/null +++ b/app/frontend/components/ui/card.tsx @@ -0,0 +1,88 @@ +import * as React from "react"; + +import { cn } from "@/utils/ui"; + +const Card = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +Card.displayName = "Card"; + +const CardHeader = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +CardHeader.displayName = "CardHeader"; + +const CardTitle = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, children, ...props }, ref) => ( +

+ {children} +

+)); +CardTitle.displayName = "CardTitle"; + +const CardDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)); +CardDescription.displayName = "CardDescription"; + +const CardContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)); +CardContent.displayName = "CardContent"; + +const CardFooter = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +CardFooter.displayName = "CardFooter"; + +export { + Card, + CardHeader, + CardFooter, + CardTitle, + CardDescription, + CardContent, +}; diff --git a/app/frontend/components/ui/input.tsx b/app/frontend/components/ui/input.tsx index f7e7a67..8ee4bbb 100644 --- a/app/frontend/components/ui/input.tsx +++ b/app/frontend/components/ui/input.tsx @@ -1,6 +1,6 @@ -import * as React from "react" +import * as React from "react"; -import { cn } from "@/utils/ui" +import { cn } from "@/utils/ui"; export interface InputProps extends React.InputHTMLAttributes {} @@ -12,14 +12,14 @@ const Input = React.forwardRef( type={type} className={cn( "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", - className + className, )} ref={ref} {...props} /> - ) - } -) -Input.displayName = "Input" + ); + }, +); +Input.displayName = "Input"; -export { Input } +export { Input }; diff --git a/app/frontend/components/ui/separator.tsx b/app/frontend/components/ui/separator.tsx index 2b73cc3..c4e01ff 100644 --- a/app/frontend/components/ui/separator.tsx +++ b/app/frontend/components/ui/separator.tsx @@ -1,7 +1,7 @@ -import * as React from "react" -import * as SeparatorPrimitive from "@radix-ui/react-separator" +import * as SeparatorPrimitive from "@radix-ui/react-separator"; +import * as React from "react"; -import { cn } from "@/utils/ui" +import { cn } from "@/utils/ui"; const Separator = React.forwardRef< React.ElementRef, @@ -9,7 +9,7 @@ const Separator = React.forwardRef< >( ( { className, orientation = "horizontal", decorative = true, ...props }, - ref + ref, ) => ( - ) -) -Separator.displayName = SeparatorPrimitive.Root.displayName + ), +); +Separator.displayName = SeparatorPrimitive.Root.displayName; -export { Separator } +export { Separator }; diff --git a/app/frontend/entrypoints/application.tsx b/app/frontend/entrypoints/application.tsx index 04ca9ed..9b636b3 100644 --- a/app/frontend/entrypoints/application.tsx +++ b/app/frontend/entrypoints/application.tsx @@ -4,16 +4,24 @@ import { createRoot } from "react-dom/client"; import NotFoundPage from "@/pages/errors/not_found"; +import Layout from "@/layouts/application"; import "@/stylesheets/globals.css"; createInertiaApp({ resolve: (name) => { - const pages = import.meta.glob("../pages/**/*.tsx", { eager: true }); - const page = pages[`../pages/${name}.tsx`]; + const pages = import.meta.glob("../pages/**/*.tsx", { + eager: true, + }); + const page = pages[`../pages/${name}.tsx`] as any; - if (page) return page; + if (!page) { + return { default: NotFoundPage }; + } - return NotFoundPage; + page.default.layout = + page.default.layout || ((page: any) => {page}); + + return page; }, setup({ el, App, props }) { createRoot(el).render( diff --git a/app/frontend/images/brands/github.svg b/app/frontend/images/brands/github.svg new file mode 100644 index 0000000..538ec5b --- /dev/null +++ b/app/frontend/images/brands/github.svg @@ -0,0 +1 @@ +GitHub \ No newline at end of file diff --git a/app/frontend/layouts/application.tsx b/app/frontend/layouts/application.tsx new file mode 100644 index 0000000..c8d7d80 --- /dev/null +++ b/app/frontend/layouts/application.tsx @@ -0,0 +1,25 @@ +import Footer from "@/layouts/application/footer"; + +interface Props { + children: React.ReactNode; +} + +function Layout({ children }: Props) { + return ( +
+
+
+

Ruby Companies

+
+
+
+
{children}
+
+
+
+ ); +} + +Layout.displayName = "layouts/application"; + +export default Layout; diff --git a/app/frontend/layouts/application/footer.tsx b/app/frontend/layouts/application/footer.tsx new file mode 100644 index 0000000..f45d22d --- /dev/null +++ b/app/frontend/layouts/application/footer.tsx @@ -0,0 +1,46 @@ +import ExternalLink from "@/components/external_link"; +import { Button } from "@/components/ui/button"; + +import githubImage from "@/images/brands/github.svg"; + +function Footer() { + return ( +
+
+
+
+ +
+ created by Calvin Walzel & Gitta van der Pol +
+
+
+ + sponsored by{" "} + + AvoHQ + + +
+
+
+
+ ); +} + +Footer.displayName = "layouts/application/footer"; + +export default Footer; diff --git a/app/frontend/pages/companies/index.tsx b/app/frontend/pages/companies/index.tsx index 973ca19..100c335 100644 --- a/app/frontend/pages/companies/index.tsx +++ b/app/frontend/pages/companies/index.tsx @@ -1,9 +1,10 @@ -import { Link } from "@inertiajs/react"; import { ColumnDef } from "@tanstack/react-table"; import { useMemo } from "react"; import { DataTable } from "@/components/data_table"; import ExternalLink from "@/components/external_link"; +import Link from "@/components/link"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import type { Company } from "@/types/company"; import type { PaginationData } from "@/types/pagination_data"; @@ -45,14 +46,18 @@ function Index({ companies, pagination }: Props) { ); return ( -
-

Companies

- -
+ + + Companies + + + + + ); } diff --git a/app/frontend/pages/errors/not_found.tsx b/app/frontend/pages/errors/not_found.tsx index d8ead05..1923444 100644 --- a/app/frontend/pages/errors/not_found.tsx +++ b/app/frontend/pages/errors/not_found.tsx @@ -1,19 +1,14 @@ -import { Link } from "@inertiajs/react"; +import Link from "@/components/link"; function NotFound() { return ( -
-
-
-
-

404 - Not Found

-

- Try again on your homepage -

-
-
+
+
+

404 - Not Found

+

+ Try again on the homepage +

-
); } diff --git a/db/seeds.rb b/db/seeds.rb index 2aa06fc..bc2804a 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -91,8 +91,8 @@ def seed_companies { name: "Company #{i}", slug: "company-#{i}", - website: "about:blank", - careers_page: "about:blank", + website: "https://ruby-companies.org", + careers_page: "https://ruby-companies.org", description: "Welcome to the page of Company #{i}. We are a company that does things.", city_id: @sample_cities.sample.id, }