feat: revamp homepage
This commit is contained in:
parent
6c81d83d30
commit
4470d3ac85
@ -1,32 +1,38 @@
|
|||||||
import React from "react";
|
import React from 'react'
|
||||||
|
|
||||||
import { useAppStars } from "@site/src/hooks/useAppStars";
|
import { useAppStars } from '@site/src/hooks/useAppStars'
|
||||||
import { useAppRelease } from "@site/src/hooks/useAppRelease";
|
import { useAppRelease } from '@site/src/hooks/useAppRelease'
|
||||||
|
|
||||||
import { AiOutlineGithub, AiOutlineTwitter } from "react-icons/ai";
|
import { AiOutlineGithub, AiOutlineTwitter } from 'react-icons/ai'
|
||||||
import { BiLogoDiscordAlt } from "react-icons/bi";
|
import { BiLogoDiscordAlt } from 'react-icons/bi'
|
||||||
|
|
||||||
const socials = [
|
const socials = [
|
||||||
{
|
{
|
||||||
icon: <AiOutlineTwitter className="text-xl text-white" />,
|
icon: <AiOutlineTwitter className="text-xl text-white" />,
|
||||||
href: "https://twitter.com/janframework",
|
href: 'https://twitter.com/janframework',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: <BiLogoDiscordAlt className="text-xl text-white" />,
|
icon: <BiLogoDiscordAlt className="text-xl text-white" />,
|
||||||
href: "https://discord.com/invite/FTk2MvZwJH",
|
href: 'https://discord.com/invite/FTk2MvZwJH',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: <AiOutlineGithub className="text-lg text-white" />,
|
icon: <AiOutlineGithub className="text-lg text-white" />,
|
||||||
href: "https://github.com/janhq/jan",
|
href: 'https://github.com/janhq/jan',
|
||||||
},
|
},
|
||||||
];
|
]
|
||||||
|
|
||||||
export default function AnnoncementBanner() {
|
export default function AnnoncementBanner() {
|
||||||
const { stargazers } = useAppStars();
|
const { stargazers } = useAppStars()
|
||||||
const { release } = useAppRelease();
|
const { release } = useAppRelease()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-10 w-full flex-shrink-0 bg-blue-600">
|
<div
|
||||||
|
className="h-10 w-full flex-shrink-0"
|
||||||
|
style={{
|
||||||
|
background:
|
||||||
|
'radial-gradient(58.83% 95.12% at 62.37% 97.91%, rgba(238, 203, 255, 0.59) 0%, rgba(255, 255, 255, 0.00) 100%), linear-gradient(249deg, rgba(67, 119, 233, 0.80) 79.81%, rgba(67, 119, 233, 0.80) 93.59%, rgba(194, 226, 255, 0.80) 110.85%)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div className="px-4 lg:px-10 flex h-full items-center justify-between py-0.5">
|
<div className="px-4 lg:px-10 flex h-full items-center justify-between py-0.5">
|
||||||
<div className="flex h-6 items-center shadow-sm">
|
<div className="flex h-6 items-center shadow-sm">
|
||||||
<a
|
<a
|
||||||
@ -75,10 +81,10 @@ export default function AnnoncementBanner() {
|
|||||||
>
|
>
|
||||||
{social.icon}
|
{social.icon}
|
||||||
</a>
|
</a>
|
||||||
);
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,134 +1,134 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from 'react'
|
||||||
import { Fragment } from "react";
|
import { Fragment } from 'react'
|
||||||
import { Menu, Transition } from "@headlessui/react";
|
import { Menu, Transition } from '@headlessui/react'
|
||||||
import { ChevronDownIcon } from "@heroicons/react/20/solid";
|
import { ChevronDownIcon } from '@heroicons/react/20/solid'
|
||||||
import axios from "axios";
|
import axios from 'axios'
|
||||||
import { FaWindows, FaApple, FaLinux } from "react-icons/fa";
|
import { FaWindows, FaApple, FaLinux } from 'react-icons/fa'
|
||||||
|
|
||||||
const systemsTemplate = [
|
const systemsTemplate = [
|
||||||
{
|
{
|
||||||
name: "Download for Mac (M1/M2/M3)",
|
name: 'Download for Mac (M1/M2/M3)',
|
||||||
logo: FaApple,
|
logo: FaApple,
|
||||||
fileFormat: "{appname}-mac-arm64-{tag}.dmg",
|
fileFormat: '{appname}-mac-arm64-{tag}.dmg',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Download for Mac (Intel)",
|
name: 'Download for Mac (Intel)',
|
||||||
logo: FaApple,
|
logo: FaApple,
|
||||||
fileFormat: "{appname}-mac-x64-{tag}.dmg",
|
fileFormat: '{appname}-mac-x64-{tag}.dmg',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Download for Windows",
|
name: 'Download for Windows',
|
||||||
logo: FaWindows,
|
logo: FaWindows,
|
||||||
fileFormat: "{appname}-win-x64-{tag}.exe",
|
fileFormat: '{appname}-win-x64-{tag}.exe',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Download for Linux (AppImage)",
|
name: 'Download for Linux (AppImage)',
|
||||||
logo: FaLinux,
|
logo: FaLinux,
|
||||||
fileFormat: "{appname}-linux-x86_64-{tag}.AppImage",
|
fileFormat: '{appname}-linux-x86_64-{tag}.AppImage',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Download for Linux (deb)",
|
name: 'Download for Linux (deb)',
|
||||||
logo: FaLinux,
|
logo: FaLinux,
|
||||||
fileFormat: "{appname}-linux-amd64-{tag}.deb",
|
fileFormat: '{appname}-linux-amd64-{tag}.deb',
|
||||||
}
|
},
|
||||||
];
|
]
|
||||||
|
|
||||||
function classNames(...classes) {
|
function classNames(...classes) {
|
||||||
return classes.filter(Boolean).join(" ");
|
return classes.filter(Boolean).join(' ')
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Dropdown() {
|
export default function Dropdown() {
|
||||||
const [systems, setSystems] = useState(systemsTemplate);
|
const [systems, setSystems] = useState(systemsTemplate)
|
||||||
const [defaultSystem, setDefaultSystem] = useState(systems[0]);
|
const [defaultSystem, setDefaultSystem] = useState(systems[0])
|
||||||
|
|
||||||
const getLatestReleaseInfo = async (repoOwner, repoName) => {
|
const getLatestReleaseInfo = async (repoOwner, repoName) => {
|
||||||
const url = `https://api.github.com/repos/${repoOwner}/${repoName}/releases/latest`;
|
const url = `https://api.github.com/repos/${repoOwner}/${repoName}/releases/latest`
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(url);
|
const response = await axios.get(url)
|
||||||
return response.data;
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error)
|
||||||
return null;
|
return null
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const extractAppName = (fileName) => {
|
const extractAppName = (fileName) => {
|
||||||
// Extract appname using a regex that matches the provided file formats
|
// Extract appname using a regex that matches the provided file formats
|
||||||
const regex = /^(.*?)-(?:mac|win|linux)-(?:arm64|x64|x86_64|amd64)-.*$/;
|
const regex = /^(.*?)-(?:mac|win|linux)-(?:arm64|x64|x86_64|amd64)-.*$/
|
||||||
const match = fileName.match(regex);
|
const match = fileName.match(regex)
|
||||||
return match ? match[1] : null;
|
return match ? match[1] : null
|
||||||
};
|
}
|
||||||
|
|
||||||
const changeDefaultSystem = async (systems) => {
|
const changeDefaultSystem = async (systems) => {
|
||||||
const userAgent = navigator.userAgent;
|
const userAgent = navigator.userAgent
|
||||||
|
|
||||||
if (userAgent.includes("Windows")) {
|
if (userAgent.includes('Windows')) {
|
||||||
// windows user
|
// windows user
|
||||||
setDefaultSystem(systems[2]);
|
setDefaultSystem(systems[2])
|
||||||
} else if (userAgent.includes("Linux")) {
|
} else if (userAgent.includes('Linux')) {
|
||||||
// linux user
|
// linux user
|
||||||
setDefaultSystem(systems[3]);
|
setDefaultSystem(systems[3])
|
||||||
} else if (userAgent.includes("Mac OS")) {
|
} else if (userAgent.includes('Mac OS')) {
|
||||||
setDefaultSystem(systems[0]);
|
setDefaultSystem(systems[0])
|
||||||
} else {
|
} else {
|
||||||
setDefaultSystem(systems[1]);
|
setDefaultSystem(systems[1])
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const updateDownloadLinks = async () => {
|
const updateDownloadLinks = async () => {
|
||||||
try {
|
try {
|
||||||
const releaseInfo = await getLatestReleaseInfo("janhq", "jan");
|
const releaseInfo = await getLatestReleaseInfo('janhq', 'jan')
|
||||||
|
|
||||||
// Extract appname from the first asset name
|
// Extract appname from the first asset name
|
||||||
const firstAssetName = releaseInfo.assets[0].name;
|
const firstAssetName = releaseInfo.assets[0].name
|
||||||
const appname = extractAppName(firstAssetName);
|
const appname = extractAppName(firstAssetName)
|
||||||
|
|
||||||
if (!appname) {
|
if (!appname) {
|
||||||
console.error(
|
console.error(
|
||||||
"Failed to extract appname from file name:",
|
'Failed to extract appname from file name:',
|
||||||
firstAssetName
|
firstAssetName
|
||||||
);
|
)
|
||||||
changeDefaultSystem(systems);
|
changeDefaultSystem(systems)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove 'v' at the start of the tag_name
|
// Remove 'v' at the start of the tag_name
|
||||||
const tag = releaseInfo.tag_name.startsWith("v")
|
const tag = releaseInfo.tag_name.startsWith('v')
|
||||||
? releaseInfo.tag_name.substring(1)
|
? releaseInfo.tag_name.substring(1)
|
||||||
: releaseInfo.tag_name;
|
: releaseInfo.tag_name
|
||||||
|
|
||||||
const updatedSystems = systems.map((system) => {
|
const updatedSystems = systems.map((system) => {
|
||||||
const downloadUrl = system.fileFormat
|
const downloadUrl = system.fileFormat
|
||||||
.replace("{appname}", appname)
|
.replace('{appname}', appname)
|
||||||
.replace("{tag}", tag);
|
.replace('{tag}', tag)
|
||||||
return {
|
return {
|
||||||
...system,
|
...system,
|
||||||
href: `https://github.com/janhq/jan/releases/download/${releaseInfo.tag_name}/${downloadUrl}`,
|
href: `https://github.com/janhq/jan/releases/download/${releaseInfo.tag_name}/${downloadUrl}`,
|
||||||
};
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
setSystems(updatedSystems);
|
setSystems(updatedSystems)
|
||||||
changeDefaultSystem(updatedSystems);
|
changeDefaultSystem(updatedSystems)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to update download links:", error);
|
console.error('Failed to update download links:', error)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
updateDownloadLinks();
|
updateDownloadLinks()
|
||||||
}, []);
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="inline-flex align-items-stretch">
|
<div className="inline-flex align-items-stretch">
|
||||||
<a
|
<a
|
||||||
href={defaultSystem.href || ""}
|
href={defaultSystem.href || ''}
|
||||||
className="cursor-pointer relative inline-flex items-center rounded-l-md border-0 px-4 py-3 text-base font-semibold dark:bg-white dark:text-black bg-black text-white dark:hover:text-black hover:text-white"
|
className="cursor-pointer relative inline-flex items-center rounded-l-xl border-0 px-4 py-4 text-base font-semibold dark:bg-[#343435] dark:text-white bg-black text-white hover:text-white dark:border dark:border-[#B2B2B3]"
|
||||||
>
|
>
|
||||||
<defaultSystem.logo className="h-5 mr-3 -mt-1" />
|
<defaultSystem.logo className="h-5 mr-3 -mt-1" />
|
||||||
{defaultSystem.name}
|
{defaultSystem.name}
|
||||||
</a>
|
</a>
|
||||||
<Menu as="div" className="relative -ml-px block">
|
<Menu as="div" className="relative -ml-px block">
|
||||||
<Menu.Button className="cursor-pointer relative inline-flex items-center rounded-r-md border-l border-gray-600 h-full dark:bg-white dark:text-black bg-black text-white dark:hover:text-black hover:text-white w-8 justify-center">
|
<Menu.Button className="cursor-pointer relative inline-flex items-center rounded-r-xl border-l border-gray-600 h-full dark:bg-[#343435] dark:text-white bg-black text-white hover:text-white w-8 justify-center dark:border dark:border-[#B2B2B3]">
|
||||||
<span className="sr-only">Open OS options</span>
|
<span className="sr-only">Open OS options</span>
|
||||||
<ChevronDownIcon className="h-6 w-6" aria-hidden="true" />
|
<ChevronDownIcon className="h-6 w-6" aria-hidden="true" />
|
||||||
</Menu.Button>
|
</Menu.Button>
|
||||||
@ -141,7 +141,7 @@ export default function Dropdown() {
|
|||||||
leaveFrom="transform opacity-100 scale-100"
|
leaveFrom="transform opacity-100 scale-100"
|
||||||
leaveTo="transform opacity-0 scale-95"
|
leaveTo="transform opacity-0 scale-95"
|
||||||
>
|
>
|
||||||
<Menu.Items className="absolute right-0 z-10 mt-1 w-80 text-left origin-top-right rounded-md dark:bg-white dark:text-black bg-black text-white dark:hover:text-black hover:text-white shadow-2xl ring-1 ring-black ring-opacity-5 focus:outline-none overflow-hidden">
|
<Menu.Items className="absolute right-0 z-10 mt-1 w-80 text-left origin-top-right rounded-xl dark:bg-[#343435] dark:text-white bg-black text-white hover:text-white shadow-2xl ring-1 ring-black ring-opacity-5 focus:outline-none overflow-hidden">
|
||||||
<div className="overflow-hidden">
|
<div className="overflow-hidden">
|
||||||
{systems.map((system) => (
|
{systems.map((system) => (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
@ -150,16 +150,16 @@ export default function Dropdown() {
|
|||||||
>
|
>
|
||||||
{({ active }) => (
|
{({ active }) => (
|
||||||
<a
|
<a
|
||||||
href={system.href || ""}
|
href={system.href || ''}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
active
|
active
|
||||||
? "dark:bg-blue-100 bg-gray-900 hover:text-white dark:text-black"
|
? 'dark:bg-black/20 bg-gray-900 hover:text-white'
|
||||||
: "text-white dark:text-black",
|
: 'text-white ',
|
||||||
"flex px-4 py-3 items-center text-white hover:text-white dark:text-black"
|
'flex px-4 py-3 items-center text-white hover:text-white'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<system.logo className="w-3 mr-3 -mt-1 flex-shrink-0" />
|
<system.logo className="w-3 mr-3 -mt-1 flex-shrink-0" />
|
||||||
<span className="text-white dark:text-black font-medium">
|
<span className="text-white font-medium">
|
||||||
{system.name}
|
{system.name}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
@ -171,5 +171,5 @@ export default function Dropdown() {
|
|||||||
</Transition>
|
</Transition>
|
||||||
</Menu>
|
</Menu>
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,31 +1,31 @@
|
|||||||
import React from "react";
|
import React from 'react'
|
||||||
import DownloadApp from "@site/src/containers/DownloadApp";
|
import DownloadApp from '@site/src/containers/DownloadApp'
|
||||||
|
|
||||||
import useBaseUrl from "@docusaurus/useBaseUrl";
|
import useBaseUrl from '@docusaurus/useBaseUrl'
|
||||||
import Layout from "@theme/Layout";
|
import Layout from '@theme/Layout'
|
||||||
import Banner from "@site/src/containers/Banner";
|
import Banner from '@site/src/containers/Banner'
|
||||||
|
|
||||||
import ThemedImage from "@theme/ThemedImage";
|
import ThemedImage from '@theme/ThemedImage'
|
||||||
|
|
||||||
import SocialButton from "@site/src/containers/SocialButton";
|
import SocialButton from '@site/src/containers/SocialButton'
|
||||||
|
|
||||||
import { IoArrowDown } from "react-icons/io5";
|
import { IoArrowDown } from 'react-icons/io5'
|
||||||
|
|
||||||
import Dropdown from "@site/src/containers/Elements/dropdown";
|
import Dropdown from '@site/src/containers/Elements/dropdown'
|
||||||
|
|
||||||
import useIsBrowser from "@docusaurus/useIsBrowser";
|
import useIsBrowser from '@docusaurus/useIsBrowser'
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const isBrowser = useIsBrowser();
|
const isBrowser = useIsBrowser()
|
||||||
|
|
||||||
const handleAnchorLink = () => {
|
const handleAnchorLink = () => {
|
||||||
document
|
document
|
||||||
.getElementById("download-section")
|
.getElementById('download-section')
|
||||||
.scrollIntoView({ behavior: "smooth" });
|
.scrollIntoView({ behavior: 'smooth' })
|
||||||
};
|
}
|
||||||
|
|
||||||
const userAgent = isBrowser && navigator.userAgent;
|
const userAgent = isBrowser && navigator.userAgent
|
||||||
const isBrowserChrome = isBrowser && userAgent.includes("Chrome");
|
const isBrowserChrome = isBrowser && userAgent.includes('Chrome')
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -35,78 +35,37 @@ export default function Home() {
|
|||||||
description="Jan runs 100% offline on your computer, utilizes open-source AI models, prioritizes privacy, and is highly customizable."
|
description="Jan runs 100% offline on your computer, utilizes open-source AI models, prioritizes privacy, and is highly customizable."
|
||||||
>
|
>
|
||||||
<main>
|
<main>
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-12 -mt-1 gap-8 items-center relative min-h-[calc(100vh-96px)] ">
|
<div className="text-center py-24">
|
||||||
<div className="col-span-full lg:col-start-2 lg:col-span-5 text-left relative z-10 px-4 py-6">
|
<h1 className="text-5xl lg:text-8xl !font-normal leading-tight lg:leading-tight mt-2 font-serif">
|
||||||
<img
|
Rethink the Computer
|
||||||
src="/img/homepage/element-hero-blur.webp"
|
</h1>
|
||||||
alt="Element blur"
|
<p className="text-2xl -mt-1 leading-relaxed text-zinc-500">
|
||||||
className="hidden lg:block absolute blur-3xl opacity-30 right-32 -bottom-32"
|
Turn your computer into a{' '}
|
||||||
/>
|
<span className="text-black dark:text-white font-semibold">
|
||||||
<div className="flex items-center space-x-2 mb-3">
|
AI machine
|
||||||
<img alt="Jan Logo" src="img/logo.svg" width={36} height={36} />
|
</span>
|
||||||
<span className="text-zinc-500 text-4xl font-medium">
|
</p>
|
||||||
Meet Jan
|
<div className="mt-10">
|
||||||
</span>
|
{!isBrowserChrome ? (
|
||||||
</div>
|
<div
|
||||||
<h1 className="text-5xl lg:text-7xl font-semibold leading-tight lg:leading-tight mt-2">
|
onClick={() => handleAnchorLink()}
|
||||||
Bringing AI to <br /> your Desktop{" "}
|
className="inline-flex px-4 py-3 rounded-lg text-lg font-semibold cursor-pointer justify-center items-center space-x-2 dark:bg-white dark:text-black bg-black text-white dark:hover:text-black hover:text-white scroll-smooth"
|
||||||
<span className="relative w-16 h-16 inline-block">
|
>
|
||||||
<img
|
<span>Download Jan for PC</span>
|
||||||
src="/img/homepage/element-hero-heading.png"
|
|
||||||
alt="Element hero heading"
|
|
||||||
className="object-contain inline-block"
|
|
||||||
width={64}
|
|
||||||
height={64}
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</h1>
|
|
||||||
<p className="text-2xl mt-3 leading-relaxed text-zinc-500">
|
|
||||||
Open-source ChatGPT alternative that runs{" "}
|
|
||||||
<br className="hidden lg:block" /> 100% offline on your
|
|
||||||
computer.
|
|
||||||
</p>
|
|
||||||
<div className="mt-8"></div>
|
|
||||||
<div className="mt-8">
|
|
||||||
{!isBrowserChrome ? (
|
|
||||||
<div
|
|
||||||
onClick={() => handleAnchorLink()}
|
|
||||||
className="inline-flex px-4 py-3 rounded-lg text-lg font-semibold cursor-pointer justify-center items-center space-x-2 dark:bg-white dark:text-black bg-black text-white dark:hover:text-black hover:text-white scroll-smooth"
|
|
||||||
>
|
|
||||||
<span>Download Jan for PC</span>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<Dropdown />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
onClick={() => handleAnchorLink()}
|
|
||||||
className="hidden lg:inline-block cursor-pointer"
|
|
||||||
>
|
|
||||||
<div className="mt-16 flex items-center space-x-2">
|
|
||||||
<p>Find out more</p>
|
|
||||||
<IoArrowDown size={24} className="animate-bounce-down" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
) : (
|
||||||
</div>
|
<Dropdown />
|
||||||
|
)}
|
||||||
<div className="col-span-full lg:col-span-6 h-full">
|
|
||||||
<div className="relative text-center h-full">
|
|
||||||
<ThemedImage
|
|
||||||
className="w-full object-cover mr-auto h-full"
|
|
||||||
alt="App screenshots"
|
|
||||||
sources={{
|
|
||||||
light: useBaseUrl(
|
|
||||||
"/img/homepage/app-base-screen-light.webp"
|
|
||||||
),
|
|
||||||
dark: useBaseUrl("/img/homepage/app-base-screen-dark.webp"),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<p className="mt-6 text-zinc-500">
|
||||||
|
<span className="text-blue-500 font-bold dark:text-blue-500">
|
||||||
|
400K+
|
||||||
|
</span>{' '}
|
||||||
|
downloads | Free & Open Source
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
{/* <div
|
||||||
className="dark:bg-[#09090B]/20 border-t border-zinc-200 dark:border-gray-800 py-10 lg:py-16"
|
className="dark:bg-[#09090B]/20 border-t border-zinc-200 dark:border-gray-800 py-10 lg:py-16"
|
||||||
id="download-section"
|
id="download-section"
|
||||||
>
|
>
|
||||||
@ -115,9 +74,9 @@ export default function Home() {
|
|||||||
<DownloadApp />
|
<DownloadApp />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> */}
|
||||||
|
|
||||||
<div className="dark:bg-[#09090B]/20 pb-10 lg:pb-36">
|
{/* <div className="dark:bg-[#09090B]/20 pb-10 lg:pb-36">
|
||||||
<div className="container h-full ">
|
<div className="container h-full ">
|
||||||
<div className="w-full lg:w-3/4 mx-auto relative rounded-xl py-10">
|
<div className="w-full lg:w-3/4 mx-auto relative rounded-xl py-10">
|
||||||
<img
|
<img
|
||||||
@ -157,9 +116,9 @@ export default function Home() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> */}
|
||||||
|
|
||||||
<div className="dark:bg-[#27272A] bg-zinc-100 pt-10 lg:pt-20 pb-10">
|
{/* <div className="dark:bg-[#27272A] bg-zinc-100 pt-10 lg:pt-20 pb-10">
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<div className="w-full lg:w-3/4 mx-auto relative">
|
<div className="w-full lg:w-3/4 mx-auto relative">
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8 items-center">
|
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8 items-center">
|
||||||
@ -170,8 +129,8 @@ export default function Home() {
|
|||||||
<p className="text-zinc-600 dark:text-zinc-400 mt-4 text-lg leading-relaxed">
|
<p className="text-zinc-600 dark:text-zinc-400 mt-4 text-lg leading-relaxed">
|
||||||
<b className="text-bold text-black dark:text-white">
|
<b className="text-bold text-black dark:text-white">
|
||||||
10x productivity
|
10x productivity
|
||||||
</b>{" "}
|
</b>{' '}
|
||||||
with customizable AI <br className="hidden lg:block" />{" "}
|
with customizable AI <br className="hidden lg:block" />{' '}
|
||||||
assistants, global hotkeys, and in-line AI.
|
assistants, global hotkeys, and in-line AI.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -182,10 +141,10 @@ export default function Home() {
|
|||||||
alt="App screenshots"
|
alt="App screenshots"
|
||||||
sources={{
|
sources={{
|
||||||
light: useBaseUrl(
|
light: useBaseUrl(
|
||||||
"/img/homepage/desktop-app-light.webp"
|
'/img/homepage/desktop-app-light.webp'
|
||||||
),
|
),
|
||||||
dark: useBaseUrl(
|
dark: useBaseUrl(
|
||||||
"/img/homepage/desktop-app-dark.webp"
|
'/img/homepage/desktop-app-dark.webp'
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -194,9 +153,9 @@ export default function Home() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> */}
|
||||||
|
|
||||||
<div className="dark:bg-[#27272A] bg-zinc-100 lg:pb-20 pb-10 pt-10">
|
{/* <div className="dark:bg-[#27272A] bg-zinc-100 lg:pb-20 pb-10 pt-10">
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<div className="w-full lg:w-3/4 mx-auto relative ">
|
<div className="w-full lg:w-3/4 mx-auto relative ">
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8 items-center">
|
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8 items-center">
|
||||||
@ -210,7 +169,7 @@ export default function Home() {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-zinc-600 dark:text-zinc-400 mt-4 text-lg leading-relaxed">
|
<p className="text-zinc-600 dark:text-zinc-400 mt-4 text-lg leading-relaxed">
|
||||||
Take your AI assistants on the go.{" "}
|
Take your AI assistants on the go.{' '}
|
||||||
<br className="hidden lg:block" /> Seamless integration
|
<br className="hidden lg:block" /> Seamless integration
|
||||||
into your
|
into your
|
||||||
<b className="text-bold text-black dark:text-white">
|
<b className="text-bold text-black dark:text-white">
|
||||||
@ -226,10 +185,10 @@ export default function Home() {
|
|||||||
alt="App screenshots"
|
alt="App screenshots"
|
||||||
sources={{
|
sources={{
|
||||||
light: useBaseUrl(
|
light: useBaseUrl(
|
||||||
"/img/homepage/mobile-app-light.webp"
|
'/img/homepage/mobile-app-light.webp'
|
||||||
),
|
),
|
||||||
dark: useBaseUrl(
|
dark: useBaseUrl(
|
||||||
"/img/homepage/mobile-app-dark.webp"
|
'/img/homepage/mobile-app-dark.webp'
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -238,9 +197,9 @@ export default function Home() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> */}
|
||||||
|
|
||||||
<div className="dark:bg-[#09090B]/20">
|
{/* <div className="dark:bg-[#09090B]/20">
|
||||||
<div className="container py-12 lg:py-32">
|
<div className="container py-12 lg:py-32">
|
||||||
<div className="w-full xl:w-10/12 mx-auto relative">
|
<div className="w-full xl:w-10/12 mx-auto relative">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
@ -266,7 +225,7 @@ export default function Home() {
|
|||||||
Offline and Local First
|
Offline and Local First
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mt-2 text-zinc-600 dark:text-zinc-400 text-lg leading-relaxed">
|
<p className="mt-2 text-zinc-600 dark:text-zinc-400 text-lg leading-relaxed">
|
||||||
Conversations, preferences, and model usage stay on{" "}
|
Conversations, preferences, and model usage stay on{' '}
|
||||||
<br className="hidden lg:block" /> your computer—secure,
|
<br className="hidden lg:block" /> your computer—secure,
|
||||||
exportable, and can be deleted at any time.
|
exportable, and can be deleted at any time.
|
||||||
</p>
|
</p>
|
||||||
@ -278,12 +237,12 @@ export default function Home() {
|
|||||||
OpenAI Compatible
|
OpenAI Compatible
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mt-4 leading-relaxed text-zinc-600 dark:text-zinc-400 text-lg">
|
<p className="mt-4 leading-relaxed text-zinc-600 dark:text-zinc-400 text-lg">
|
||||||
Jan provides an OpenAI-equivalent API{" "}
|
Jan provides an OpenAI-equivalent API{' '}
|
||||||
<br className="hidden lg:block" /> server at
|
<br className="hidden lg:block" /> server at
|
||||||
<b>localhost:</b>
|
<b>localhost:</b>
|
||||||
<span className="bg-blue-600 text-white font-bold py-0.5 px-2 rounded-lg">
|
<span className="bg-blue-600 text-white font-bold py-0.5 px-2 rounded-lg">
|
||||||
1337
|
1337
|
||||||
</span>{" "}
|
</span>{' '}
|
||||||
that can be used as a drop-in replacement with
|
that can be used as a drop-in replacement with
|
||||||
compatible apps.
|
compatible apps.
|
||||||
</p>
|
</p>
|
||||||
@ -332,9 +291,16 @@ export default function Home() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> */}
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
{/* <main>
|
||||||
|
<div className="text-center py-24">
|
||||||
|
<h1 className="font-serif text-8xl">Rethink the Computer</h1>
|
||||||
|
<p>Turn your computer into a AI machine</p>
|
||||||
|
</div>
|
||||||
|
</main> */}
|
||||||
</Layout>
|
</Layout>
|
||||||
</>
|
</>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
@layer base {
|
@layer base {
|
||||||
html[data-theme="light"] {
|
html[data-theme='light'] {
|
||||||
--custom-radial-blur: #e1e7fd;
|
--custom-radial-blur: #e1e7fd;
|
||||||
--ifm-background-color: #fff;
|
--ifm-background-color: #fff;
|
||||||
--ifm-color-primary: #2563eb; /* New Primary Blue */
|
--ifm-color-primary: #2563eb; /* New Primary Blue */
|
||||||
@ -14,7 +14,7 @@
|
|||||||
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1);
|
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
html[data-theme="dark"] {
|
html[data-theme='dark'] {
|
||||||
--custom-radial-blur: #1d1b48;
|
--custom-radial-blur: #1d1b48;
|
||||||
--ifm-background-color: #18181b;
|
--ifm-background-color: #18181b;
|
||||||
--ifm-color-primary: #ffffff; /* New Primary Blue */
|
--ifm-color-primary: #ffffff; /* New Primary Blue */
|
||||||
@ -35,7 +35,7 @@
|
|||||||
body {
|
body {
|
||||||
@apply text-base;
|
@apply text-base;
|
||||||
@apply antialiased;
|
@apply antialiased;
|
||||||
@apply bg-white dark:bg-[#18181B];
|
@apply bg-white dark:bg-[#0C0C0C];
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
|
|||||||
@ -1,15 +1,17 @@
|
|||||||
@import "tailwindcss/base";
|
@import url('https://fonts.googleapis.com/css2?family=Arapey&family=Inter:wght@100..900&display=swap');
|
||||||
@import "tailwindcss/components";
|
|
||||||
@import "tailwindcss/utilities";
|
|
||||||
|
|
||||||
@import "./components/base.scss";
|
@import 'tailwindcss/base';
|
||||||
@import "./components/typography.scss";
|
@import 'tailwindcss/components';
|
||||||
@import "./components/card.scss";
|
@import 'tailwindcss/utilities';
|
||||||
|
|
||||||
@import "./tweaks/navbar.scss";
|
@import './components/base.scss';
|
||||||
@import "./tweaks/breadcrumb.scss";
|
@import './components/typography.scss';
|
||||||
@import "./tweaks/markdown.scss";
|
@import './components/card.scss';
|
||||||
@import "./tweaks/redocusaurus.scss";
|
|
||||||
@import "./tweaks/sidebar.scss";
|
|
||||||
|
|
||||||
@import "../css/custom.css";
|
@import './tweaks/navbar.scss';
|
||||||
|
@import './tweaks/breadcrumb.scss';
|
||||||
|
@import './tweaks/markdown.scss';
|
||||||
|
@import './tweaks/redocusaurus.scss';
|
||||||
|
@import './tweaks/sidebar.scss';
|
||||||
|
|
||||||
|
@import '../css/custom.css';
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
@apply bg-transparent py-0 shadow-none px-0;
|
@apply bg-transparent py-0 shadow-none px-0;
|
||||||
|
|
||||||
&__inner {
|
&__inner {
|
||||||
@apply border border-gray-200 dark:border-gray-800 bg-white/80 dark:bg-[#09090B]/50 backdrop-blur-md flex items-center h-14 px-4 lg:px-8 relative;
|
@apply border-b border-gray-200 dark:border-gray-800 bg-white/80 dark:bg-[#09090B]/50 backdrop-blur-md flex items-center h-14 px-4 lg:px-8 relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__logo {
|
&__logo {
|
||||||
@ -19,7 +19,7 @@
|
|||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
[class*="searchBox_"] {
|
[class*='searchBox_'] {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,23 +1,33 @@
|
|||||||
import React from "react";
|
import React from 'react'
|
||||||
import clsx from "clsx";
|
import clsx from 'clsx'
|
||||||
import ErrorBoundary from "@docusaurus/ErrorBoundary";
|
import ErrorBoundary from '@docusaurus/ErrorBoundary'
|
||||||
import {
|
import {
|
||||||
PageMetadata,
|
PageMetadata,
|
||||||
SkipToContentFallbackId,
|
SkipToContentFallbackId,
|
||||||
ThemeClassNames,
|
ThemeClassNames,
|
||||||
} from "@docusaurus/theme-common";
|
} from '@docusaurus/theme-common'
|
||||||
import { useKeyboardNavigation } from "@docusaurus/theme-common/internal";
|
import { useKeyboardNavigation } from '@docusaurus/theme-common/internal'
|
||||||
import SkipToContent from "@theme/SkipToContent";
|
import SkipToContent from '@theme/SkipToContent'
|
||||||
import AnnouncementBar from "@theme/AnnouncementBar";
|
import AnnouncementBar from '@theme/AnnouncementBar'
|
||||||
import Navbar from "@theme/Navbar";
|
import Navbar from '@theme/Navbar'
|
||||||
import Footer from "@site/src/containers/Footer";
|
import Footer from '@site/src/containers/Footer'
|
||||||
import LayoutProvider from "@theme/Layout/Provider";
|
import LayoutProvider from '@theme/Layout/Provider'
|
||||||
import ErrorPageContent from "@theme/ErrorPageContent";
|
import ErrorPageContent from '@theme/ErrorPageContent'
|
||||||
import styles from "./styles.module.scss";
|
import styles from './styles.module.scss'
|
||||||
import NavBarExtension from "../NavbarExtension";
|
import NavBarExtension from '../NavbarExtension'
|
||||||
import { useLocation } from "react-router-dom";
|
import { useLocation } from 'react-router-dom'
|
||||||
|
|
||||||
const allowedPaths = ["/docs/", "/developer/", "/api-reference/", "/guides/", "/guides", "/docs", "/developer", "/api-reference", "/changelog"];
|
const allowedPaths = [
|
||||||
|
'/docs/',
|
||||||
|
'/developer/',
|
||||||
|
'/api-reference/',
|
||||||
|
'/guides/',
|
||||||
|
'/guides',
|
||||||
|
'/docs',
|
||||||
|
'/developer',
|
||||||
|
'/api-reference',
|
||||||
|
'/changelog',
|
||||||
|
]
|
||||||
|
|
||||||
export default function Layout(props) {
|
export default function Layout(props) {
|
||||||
const {
|
const {
|
||||||
@ -27,12 +37,14 @@ export default function Layout(props) {
|
|||||||
// Not really layout-related, but kept for convenience/retro-compatibility
|
// Not really layout-related, but kept for convenience/retro-compatibility
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
} = props;
|
} = props
|
||||||
useKeyboardNavigation();
|
useKeyboardNavigation()
|
||||||
|
|
||||||
const location = useLocation();
|
const location = useLocation()
|
||||||
|
|
||||||
const isAllowedPath = allowedPaths.some(path => location.pathname.startsWith(path));
|
const isAllowedPath = allowedPaths.some((path) =>
|
||||||
|
location.pathname.startsWith(path)
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutProvider>
|
<LayoutProvider>
|
||||||
@ -42,20 +54,19 @@ export default function Layout(props) {
|
|||||||
|
|
||||||
<AnnouncementBar />
|
<AnnouncementBar />
|
||||||
|
|
||||||
<Navbar/>
|
<Navbar />
|
||||||
|
|
||||||
{isAllowedPath ? <NavBarExtension /> : ""}
|
{isAllowedPath ? <NavBarExtension /> : ''}
|
||||||
|
|
||||||
{/* {console.log("Is allowed path?", location.pathname)} */}
|
{/* {console.log("Is allowed path?", location.pathname)} */}
|
||||||
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
id={SkipToContentFallbackId}
|
id={SkipToContentFallbackId}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
ThemeClassNames.wrapper.main,
|
ThemeClassNames.wrapper.main,
|
||||||
styles.mainWrapper,
|
styles.mainWrapper,
|
||||||
wrapperClassName,
|
wrapperClassName,
|
||||||
isAllowedPath && "mt-0 md:mt-11"
|
isAllowedPath && 'mt-0 md:mt-11'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<ErrorBoundary fallback={(params) => <ErrorPageContent {...params} />}>
|
<ErrorBoundary fallback={(params) => <ErrorPageContent {...params} />}>
|
||||||
@ -65,5 +76,5 @@ export default function Layout(props) {
|
|||||||
|
|
||||||
{!noFooter && <Footer />}
|
{!noFooter && <Footer />}
|
||||||
</LayoutProvider>
|
</LayoutProvider>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,67 +1,68 @@
|
|||||||
// tailwind.config.js
|
// tailwind.config.js
|
||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
content: ["./src/**/*.{js,jsx,ts,tsx}"],
|
content: ['./src/**/*.{js,jsx,ts,tsx}'],
|
||||||
darkMode: ["class", '[data-theme="dark"]'],
|
darkMode: ['class', '[data-theme="dark"]'],
|
||||||
theme: {
|
theme: {
|
||||||
animation: {
|
animation: {
|
||||||
wave: "wave 2.5s linear infinite",
|
'wave': 'wave 2.5s linear infinite',
|
||||||
enter: "enter 200ms ease-out",
|
'enter': 'enter 200ms ease-out',
|
||||||
"slide-in": "slide-in 1.2s cubic-bezier(.41,.73,.51,1.02)",
|
'slide-in': 'slide-in 1.2s cubic-bezier(.41,.73,.51,1.02)',
|
||||||
leave: "leave 150ms ease-in forwards",
|
'leave': 'leave 150ms ease-in forwards',
|
||||||
"bounce-down": "bounce-down 3s infinite",
|
'bounce-down': 'bounce-down 3s infinite',
|
||||||
},
|
},
|
||||||
keyframes: {
|
keyframes: {
|
||||||
wave: {
|
'wave': {
|
||||||
"0%": { transform: "rotate( 0.0deg)" },
|
'0%': { transform: 'rotate( 0.0deg)' },
|
||||||
"10%": { transform: "rotate(14.0deg)" },
|
'10%': { transform: 'rotate(14.0deg)' },
|
||||||
"20%": { transform: "rotate(-8.0deg)" },
|
'20%': { transform: 'rotate(-8.0deg)' },
|
||||||
"30%": { transform: "rotate(14.0deg)" },
|
'30%': { transform: 'rotate(14.0deg)' },
|
||||||
"40%": { transform: "rotate(-4.0deg)" },
|
'40%': { transform: 'rotate(-4.0deg)' },
|
||||||
"50%": { transform: "rotate(10.0deg)" },
|
'50%': { transform: 'rotate(10.0deg)' },
|
||||||
"60%": { transform: "rotate( 0.0deg)" },
|
'60%': { transform: 'rotate( 0.0deg)' },
|
||||||
"100%": { transform: "rotate( 0.0deg)" },
|
'100%': { transform: 'rotate( 0.0deg)' },
|
||||||
},
|
},
|
||||||
enter: {
|
'enter': {
|
||||||
"0%": { transform: "scale(0.8)", opacity: "0" },
|
'0%': { transform: 'scale(0.8)', opacity: '0' },
|
||||||
"100%": { transform: "scale(1)", opacity: "1" },
|
'100%': { transform: 'scale(1)', opacity: '1' },
|
||||||
},
|
},
|
||||||
leave: {
|
'leave': {
|
||||||
"0%": { transform: "scale(1)", opacity: "1" },
|
'0%': { transform: 'scale(1)', opacity: '1' },
|
||||||
"100%": { transform: "scale(0.8)", opacity: "0" },
|
'100%': { transform: 'scale(0.8)', opacity: '0' },
|
||||||
},
|
},
|
||||||
"slide-in": {
|
'slide-in': {
|
||||||
"0%": { transform: "translateY(-100%)" },
|
'0%': { transform: 'translateY(-100%)' },
|
||||||
"100%": { transform: "translateY(0)" },
|
'100%': { transform: 'translateY(0)' },
|
||||||
},
|
},
|
||||||
"bounce-down": {
|
'bounce-down': {
|
||||||
"0%,20%, 50%,80%,100%": { transform: "translateY(0)" },
|
'0%,20%, 50%,80%,100%': { transform: 'translateY(0)' },
|
||||||
"40%": { transform: "translateY(-8px)" },
|
'40%': { transform: 'translateY(-8px)' },
|
||||||
"60%": { transform: "translateY(-4px)" },
|
'60%': { transform: 'translateY(-4px)' },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
container: {
|
container: {
|
||||||
center: true,
|
center: true,
|
||||||
padding: "16px",
|
padding: '16px',
|
||||||
},
|
},
|
||||||
fontFamily: {
|
fontFamily: {
|
||||||
sans: [
|
sans: [
|
||||||
"Inter",
|
'Inter',
|
||||||
"-apple-system",
|
'-apple-system',
|
||||||
"BlinkMacSystemFont",
|
'BlinkMacSystemFont',
|
||||||
"Segoe UI",
|
'Segoe UI',
|
||||||
"Roboto",
|
'Roboto',
|
||||||
"Oxygen-Sans",
|
'Oxygen-Sans',
|
||||||
"Ubuntu,Cantarell",
|
'Ubuntu,Cantarell',
|
||||||
"Helvetica",
|
'Helvetica',
|
||||||
"sans-serif",
|
'sans-serif',
|
||||||
],
|
],
|
||||||
|
serif: ['Arapey'],
|
||||||
},
|
},
|
||||||
extend: {
|
extend: {
|
||||||
backgroundImage: {
|
backgroundImage: {
|
||||||
'custom-img': "url('/img/homepage-new/bg.png')",
|
'custom-img': "url('/img/homepage-new/bg.png')",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [require("tailwindcss-animate")],
|
plugins: [require('tailwindcss-animate')],
|
||||||
};
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user