Skip to content

Commit

Permalink
Download the asset for current operation system directly (#22)
Browse files Browse the repository at this point in the history
* Render downloads as dropdown button and auto detect system

* Create a provider for release asset

* Make download links adaptive

* Use carousel from shadcn

* Use nextui accordion for FAQ
  • Loading branch information
lilac authored Jun 15, 2024
1 parent 1f49489 commit ccacb51
Show file tree
Hide file tree
Showing 12 changed files with 1,983 additions and 164 deletions.
1,494 changes: 1,408 additions & 86 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,19 @@
},
"dependencies": {
"@next/third-parties": "^14.1.3",
"@nextui-org/accordion": "^2.0.34",
"@nextui-org/button": "^2.0.33",
"@nextui-org/dropdown": "^2.1.25",
"@nextui-org/link": "^2.0.31",
"@nextui-org/system": "^2.2.1",
"@nextui-org/theme": "^2.2.5",
"@radix-ui/react-avatar": "^1.0.4",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-slot": "^1.0.2",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"embla-carousel-react": "^8.1.5",
"framer-motion": "^11.2.10",
"lucide-react": "^0.289.0",
"next": "13.5.6",
"react": "^18",
Expand Down
4 changes: 0 additions & 4 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@
@tailwind components;
@tailwind utilities;

section {
@apply py-12 md:py-16 lg:py-20;
}

.bubble {
@apply absolute -z-10 rounded-full blur-3xl opacity-20;
}
12 changes: 9 additions & 3 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import "./globals.css";
import Navbar from "@/components/Navbar";
import Footer from "@/components/Footer";
import { GoogleAnalytics } from '@next/third-parties/google'
import { NextUIProvider } from "@nextui-org/system";
import { ReleaseProvider } from "@/lib/release-provider";

const inter = Inter({ subsets: ["latin"] });

Expand Down Expand Up @@ -39,9 +41,13 @@ export default function RootLayout({
<body
className={`${inter.className} bg-slate-900 text-slate-300 text-lg min-h-screen overflow-x-hidden`}
>
<Navbar />
{children}
<Footer />
<NextUIProvider>
<Navbar />
<ReleaseProvider repo="rabrain/ai-chat">
{children}
</ReleaseProvider>
<Footer />
</NextUIProvider>
</body>
<GoogleAnalytics gaId="G-XHXGY43X34" />
</html>
Expand Down
65 changes: 27 additions & 38 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
import { MoveRight } from "lucide-react";
import Heading from "@/components/Heading";
import Button from "@/components/Button";
import Link from "next/link";
import Image from "next/image";
import { Clients } from "@/constants/client";
import { feature, featuresBlock } from "@/constants/feature";
import FeatureCard from "@/components/FeatureCard";
import FeatureBlock from "@/components/FeatureBlock";
import Windows from "@/components/icons/Windows";
import Linux from "@/components/icons/Linux";
import Apple from "super-tiny-icons/images/svg/apple.svg";
import IconLink from "@/components/IconLink";
import FAQ from "@/components/FAQ";
import screenshot from 'public/screenshot-full.jpg';
import DropdownDownload from "@/components/DropdownDownload";
import DownloadLink from "@/components/Download";
import { Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext } from "@/components/ui/carousel";

export default function Home() {
const downloadUrl = "https://github.com/rabrain/ai-chat/releases/latest"
return (
<main className="pt-24 lg:pt-28 antialiased">
<div className="relative container lg:w-4/5">
<div className="relative container lg:w-4/5 space-y-12 md:space-y-16 lg:space-y-20">
{/* <Image
src="/bg.png"
width={1920}
Expand All @@ -41,39 +37,26 @@ export default function Home() {
<p className="max-w-[46rem] leading-normal md:text-xl sm:text-lg sm:leading-8">
AI Chat is a cross-platform ChatGPT desktop application that provides quick access to chatbots like OpenAI ChatGPT from the menu bar (tray).
</p>
<div className="flex flex-wrap items-center justify-center gap-4">
<Link href={downloadUrl} className="btn btn-outline flex-shrink">
<Windows className="w-6 h-6" />
<span>Windows</span>
</Link>
<IconLink icon={Apple} text="Mac OS" href={downloadUrl} />
<Link href={downloadUrl} className="btn btn-outline flex-shrink">
<Linux className="w-6 h-6" />
<span>Linux</span>
</Link>
</div>
<DropdownDownload />
</div>
<div>
<div className="carousel carousel-center w-full">
<div id="slide1" className="carousel-item w-full">
<Carousel opts={{ loop: true }} className="mx-12">
<CarouselContent>
<CarouselItem>
<video controls>
<source src="/preview.mp4" type="video/mp4" />
Your browser does not support the video tag.
</video>
</div>
<div id="slide2" className="carousel-item w-full">
</CarouselItem>
<CarouselItem>
<Image
src={screenshot}
alt="banner"
className="mx-auto shadow-xl rounded-box"
/>
</div>
</div>
<div className="flex justify-center w-full py-2 gap-2">
<a href="#slide1" className="btn btn-xs">1</a>
<a href="#slide2" className="btn btn-xs">2</a>
</div>
</div>
</CarouselItem>
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>
</div>
</section>
{/* Home section */}
Expand Down Expand Up @@ -114,9 +97,9 @@ export default function Home() {
<p className="lg:max-w-[34rem] leading-normal sm:text-lg sm:leading-8">
AI Chat eliminates the need to switch between windows when using ChatGPT as our daily assistant.
</p>
<Link href={downloadUrl}>
<Button>Get Started</Button>
</Link>
<DownloadLink color="primary" size="lg">
Get Started
</DownloadLink>
</div>
<div className="grid md:grid-cols-2 lg:grid-cols-1 gap-4 ">
{feature.map((feature, index) => (
Expand Down Expand Up @@ -160,10 +143,16 @@ export default function Home() {
Get started today!
</p>
</div>
<Link href={downloadUrl} className="btn btn-primary">
<DownloadLink
color="secondary"
size="lg"
showAnchorIcon
anchorIcon={
<MoveRight className="w-4 h-4" />
}
>
Download
<MoveRight className="w-4 h-4" />
</Link>
</DownloadLink>
</div>
</section>
{/* Contact section */}
Expand Down
24 changes: 24 additions & 0 deletions src/components/Download.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'use client'

import { useRelease } from "@/lib/release-provider"
import { Button, ButtonProps } from "@nextui-org/button"
import { Link, LinkProps } from "@nextui-org/link"

const DownloadLink = ({ children, ...props }: ButtonProps & LinkProps) => {
const release = useRelease()
const systems = release.systems
const defaultSystem = release.current ?? systems[0]
const href = defaultSystem.href || release.url

return (
<Button
as={Link}
href={href}
{...props}
>
{children}
</Button>
)
}

export default DownloadLink
62 changes: 62 additions & 0 deletions src/components/DropdownDownload.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
'use client';

// Ref: https://github.com/janhq/docs/blob/main/src/components/DropdownDownload/index.tsx#L114
import { Button, ButtonGroup } from "@nextui-org/button";
import { Dropdown, DropdownItem, DropdownMenu, DropdownTrigger } from "@nextui-org/dropdown";

import { useRelease } from '@/lib/release-provider';
import { Link } from '@nextui-org/link';
import { ChevronDownIcon } from './icons/ChevronDownIcon';


const DropdownDownload = () => {
const release = useRelease()
const systems = release.systems
const defaultSystem = release.current ?? systems[0]

return (
<ButtonGroup variant="flat">
<Button
href={defaultSystem.href || release.url}
as={Link}
color="primary"
variant="solid"
size='lg'
startContent={
<defaultSystem.logo className='w-6' />
}
// showAnchorIcon
>
{defaultSystem.name}
</Button>
<Dropdown placement="bottom-end">
<DropdownTrigger>
<Button isIconOnly color='primary' variant='solid' size='lg' aria-label="Download options">
<ChevronDownIcon />
</Button>
</DropdownTrigger>
<DropdownMenu
// disallowEmptySelection
aria-label="Download options"
// selectionMode="single"
color="primary"
variant="solid"
>
{systems.map((system) => (
<DropdownItem
key={system.name}
startContent={<system.logo className="w-6" />}
textValue={system.name}
>
<Link color='foreground' href={system.href || ''}>
{system.name}
</Link>
</DropdownItem>
))}
</DropdownMenu>
</Dropdown>
</ButtonGroup>
)
}

export default DropdownDownload
47 changes: 15 additions & 32 deletions src/components/FAQ.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,21 @@
import React, { ReactNode } from "react"
"use client"

type Props = {
title: string,
default?: boolean,
children?: ReactNode
}

function QuestionAnswer(props: Props) {
return (
<div className="collapse collapse-arrow bg-slate-800">
<input type="radio" name="my-accordion-2" defaultChecked={props.default} />
<div className="collapse-title text-xl font-medium">
{props.title}
</div>
<div className="collapse-content space-y-2">
{props.children}
</div>
</div>
)
}
import React from "react"
import {Accordion, AccordionItem} from "@nextui-org/accordion"

export default function FAQ() {
return (
<div className="flex flex-col gap-2">
<QuestionAnswer title="What is AI Chat? Why did you create it?">
<Accordion>
<AccordionItem key="1" title="What is AI Chat? Why did you create it?">
<b>AI Chat is a cross-platform desktop application that lets you open AI chatbots like OpenAI ChatGPT from the menu bar (tray).</b>
<p>
By having it reside on the menu bar, we eliminate the need to switch between windows when using ChatGPT as our daily assistant. It also enables us to have a streamlined workflow, as we can easily multitask and communicate with the AI without interrupting our current tasks.
</p>
</QuestionAnswer>
<QuestionAnswer title="Is it free?">
</AccordionItem>
<AccordionItem key="2" title="Is it free?">
Yes, AI Chat is a free ChatGPT desktop app.
</QuestionAnswer>
<QuestionAnswer title="What chatbots (LLM models) can I use in AI Chat?">
</AccordionItem>
<AccordionItem key="3" title="What chatbots (LLM models) can I use in AI Chat?">
AI Chat enables you to quickly open AI chatbots of your choice, including:
<ul className="list-disc ml-4">
<li><a href="https://chat.openai.com" rel="nofollow">OpenAI ChatGPT</a></li>
Expand All @@ -43,18 +26,18 @@ export default function FAQ() {
<li><a href="https://pi.ai" rel="nofollow">Pi</a></li>
<li><a href="https://poe.com" rel="nofollow">Poe</a></li>
</ul>
</QuestionAnswer>
<QuestionAnswer title="What are the system requirements for AI Chat?">
</AccordionItem>
<AccordionItem key="4" title="What are the system requirements for AI Chat?">
AI Chat is available on the following operating systems:
<ul className="list-disc ml-4">
<li>Windows</li>
<li>Mac OS X</li>
<li>Linux</li>
</ul>
</QuestionAnswer>
<QuestionAnswer title="Is AI Chat available in the Mac App Store?">
</AccordionItem>
<AccordionItem key="5" title="Is AI Chat available in the Mac App Store?">
Yes, AI Chat is listed in the <a href="https://apps.apple.com/app/ai-chat-open-bot/id6479942223" target="_blank">Mac App Store</a> and available in most countries. But due to restrictions of Apple&lsquo;s app store, the version of AI Chat downloaded from the Mac App Store may lack some features of the version available from this official site.
</QuestionAnswer>
</div>
</AccordionItem>
</Accordion>
)
}
28 changes: 28 additions & 0 deletions src/components/icons/ChevronDownIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React, { SVGProps } from "react";

type Props = SVGProps<SVGSVGElement> & {
size?: number,
filled?: boolean,
label?: string,
}

export const ChevronDownIcon = ({
fill = 'currentColor',
filled,
size,
height,
width,
label,
...props
}: Props) => (
<svg
width={size || width || 24}
height={size || height || 24}
viewBox="0 0 24 24"
fill={filled ? fill : 'none'}
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path d="M17.9188 8.17969H11.6888H6.07877C5.11877 8.17969 4.63877 9.33969 5.31877 10.0197L10.4988 15.1997C11.3288 16.0297 12.6788 16.0297 13.5088 15.1997L15.4788 13.2297L18.6888 10.0197C19.3588 9.33969 18.8788 8.17969 17.9188 8.17969Z" stroke={fill} />
</svg>
);
Loading

0 comments on commit ccacb51

Please sign in to comment.