Finalize responsive new web
127
docs/src/components/Elements/downloadLink.js
Normal file
@ -0,0 +1,127 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import axios from "axios";
|
||||
|
||||
const systemsTemplate = [
|
||||
{
|
||||
name: "Download for Mac (M1/M2)",
|
||||
logo: require("@site/static/img/apple-logo-white.png").default,
|
||||
fileFormat: "{appname}-mac-arm64-{tag}.dmg",
|
||||
},
|
||||
{
|
||||
name: "Download for Mac (Intel)",
|
||||
logo: require("@site/static/img/apple-logo-white.png").default,
|
||||
fileFormat: "{appname}-mac-x64-{tag}.dmg",
|
||||
},
|
||||
{
|
||||
name: "Download for Windows",
|
||||
logo: require("@site/static/img/windows-logo-white.png").default,
|
||||
fileFormat: "{appname}-win-x64-{tag}.exe",
|
||||
},
|
||||
{
|
||||
name: "Download for Linux",
|
||||
logo: require("@site/static/img/linux-logo-white.png").default,
|
||||
fileFormat: "{appname}-linux-amd64-{tag}.deb",
|
||||
},
|
||||
];
|
||||
|
||||
function classNames(...classes) {
|
||||
return classes.filter(Boolean).join(" ");
|
||||
}
|
||||
|
||||
export default function DownloadLink() {
|
||||
const [systems, setSystems] = useState(systemsTemplate);
|
||||
const [defaultSystem, setDefaultSystem] = useState(systems[0]);
|
||||
|
||||
const getLatestReleaseInfo = async (repoOwner, repoName) => {
|
||||
const url = `https://api.github.com/repos/${repoOwner}/${repoName}/releases/latest`;
|
||||
try {
|
||||
const response = await axios.get(url);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const extractAppName = (fileName) => {
|
||||
// Extract appname using a regex that matches the provided file formats
|
||||
const regex = /^(.*?)-(?:mac|win|linux)-(?:arm64|x64|amd64)-.*$/;
|
||||
const match = fileName.match(regex);
|
||||
return match ? match[1] : null;
|
||||
};
|
||||
|
||||
const changeDefaultSystem = async (systems) => {
|
||||
const userAgent = navigator.userAgent;
|
||||
|
||||
const arc = await navigator?.userAgentData?.getHighEntropyValues([
|
||||
"architecture",
|
||||
]);
|
||||
|
||||
if (userAgent.includes("Windows")) {
|
||||
// windows user
|
||||
setDefaultSystem(systems[2]);
|
||||
} else if (userAgent.includes("Linux")) {
|
||||
// linux user
|
||||
setDefaultSystem(systems[3]);
|
||||
} else if (
|
||||
userAgent.includes("Mac OS") &&
|
||||
arc &&
|
||||
arc.architecture === "arm"
|
||||
) {
|
||||
setDefaultSystem(systems[0]);
|
||||
} else {
|
||||
setDefaultSystem(systems[1]);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const updateDownloadLinks = async () => {
|
||||
try {
|
||||
const releaseInfo = await getLatestReleaseInfo("janhq", "jan");
|
||||
|
||||
// Extract appname from the first asset name
|
||||
const firstAssetName = releaseInfo.assets[0].name;
|
||||
const appname = extractAppName(firstAssetName);
|
||||
|
||||
if (!appname) {
|
||||
console.error(
|
||||
"Failed to extract appname from file name:",
|
||||
firstAssetName
|
||||
);
|
||||
changeDefaultSystem(systems);
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove 'v' at the start of the tag_name
|
||||
const tag = releaseInfo.tag_name.startsWith("v")
|
||||
? releaseInfo.tag_name.substring(1)
|
||||
: releaseInfo.tag_name;
|
||||
|
||||
const updatedSystems = systems.map((system) => {
|
||||
const downloadUrl = system.fileFormat
|
||||
.replace("{appname}", appname)
|
||||
.replace("{tag}", tag);
|
||||
return {
|
||||
...system,
|
||||
href: `https://github.com/janhq/jan/releases/download/${releaseInfo.tag_name}/${downloadUrl}`,
|
||||
};
|
||||
});
|
||||
|
||||
setSystems(updatedSystems);
|
||||
changeDefaultSystem(updatedSystems);
|
||||
} catch (error) {
|
||||
console.error("Failed to update download links:", error);
|
||||
}
|
||||
};
|
||||
|
||||
updateDownloadLinks();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="mt-2">
|
||||
<a href={defaultSystem.href}>
|
||||
<span className="text-blue-600 font-bold">Download Jan</span>
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -76,6 +76,7 @@ export default function Dropdown() {
|
||||
setDefaultSystem(systems[1]);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const updateDownloadLinks = async () => {
|
||||
try {
|
||||
|
||||
@ -5,38 +5,12 @@ import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
|
||||
import useBaseUrl from "@docusaurus/useBaseUrl";
|
||||
import Layout from "@theme/Layout";
|
||||
import AnnoncementBanner from "@site/src/components/Announcement";
|
||||
import {
|
||||
CloudArrowUpIcon,
|
||||
CursorArrowRaysIcon,
|
||||
ShieldCheckIcon,
|
||||
CpuChipIcon,
|
||||
ClipboardDocumentIcon,
|
||||
CubeTransparentIcon,
|
||||
ComputerDesktopIcon,
|
||||
FolderPlusIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import { AiOutlineGithub, AiOutlineTwitter } from "react-icons/ai";
|
||||
|
||||
import { AiOutlineGithub } from "react-icons/ai";
|
||||
|
||||
import ThemedImage from "@theme/ThemedImage";
|
||||
|
||||
const features = [
|
||||
{
|
||||
name: "Personal AI that runs on your computer",
|
||||
desc: "Jan runs directly on your local machine, offering privacy, convenience and customizability.",
|
||||
},
|
||||
{
|
||||
name: "Extendable via App and Plugin framework",
|
||||
desc: "Jan has a versatile app and plugin framework, allowing you to customize it to your needs.",
|
||||
},
|
||||
{
|
||||
name: "Private and offline, your data never leaves your machine",
|
||||
desc: "Your conversations and data are with an AI that runs on your computer, where only you have access.",
|
||||
},
|
||||
{
|
||||
name: "No subscription fees, the AI runs on your computer",
|
||||
desc: "Say goodbye to monthly subscriptions or usage-based APIs. Jan runs 100% free on your own hardware.",
|
||||
},
|
||||
];
|
||||
import DownloadLink from "@site/src/components/Elements/downloadLink";
|
||||
|
||||
export default function Home() {
|
||||
const { siteConfig } = useDocusaurusContext();
|
||||
@ -45,19 +19,18 @@ export default function Home() {
|
||||
<AnnoncementBanner />
|
||||
<Layout
|
||||
title={`${siteConfig.tagline}`}
|
||||
description="Jan runs Large Language Models locally on Windows, Mac and Linux.
|
||||
Available on Desktop and Cloud-Native."
|
||||
description="Jan runs Large Language Models locally on Windows, Mac and Linux. Available on Desktop and Cloud-Native."
|
||||
>
|
||||
<main className="bg-gray-50 dark:bg-gray-950/95 relative">
|
||||
<div className="relative">
|
||||
{/* <ThemedImage
|
||||
<ThemedImage
|
||||
alt="App screenshot"
|
||||
sources={{
|
||||
light: useBaseUrl("/img/bg-hero-light.svg"),
|
||||
dark: useBaseUrl("/img/bg-hero-dark.svg"),
|
||||
}}
|
||||
className="absolute w-full h-full opacity-10 dark:opacity-20 top-0 object-cover blur-3xl"
|
||||
/> */}
|
||||
/>
|
||||
<div className="container py-16">
|
||||
<div className="grid grid-cols-1 items-center gap-4">
|
||||
<div className="relative z-10 text-center ">
|
||||
@ -72,7 +45,6 @@ export default function Home() {
|
||||
</p>
|
||||
</a>
|
||||
</div> */}
|
||||
|
||||
<h1 className="bg-gradient-to-r dark:from-white from-black to-gray-500 dark:to-gray-400 bg-clip-text text-4xl lg:text-6xl font-bold leading-tight text-transparent dark:text-transparent lg:leading-tight">
|
||||
Own your AI
|
||||
</h1>
|
||||
@ -108,7 +80,6 @@ export default function Home() {
|
||||
</div>
|
||||
|
||||
<div className="text-center relative ">
|
||||
{/* <div className="el-blur-hero absolute -left-40 w-full top-1/2 -translate-y-1/2" /> */}
|
||||
<div className="p-3 border dark:border-gray-500 border-gray-400 inline-block rounded-lg">
|
||||
<ThemedImage
|
||||
alt="App screenshot"
|
||||
@ -124,36 +95,142 @@ export default function Home() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* <div className="container mt-10 mb-20 text-center">
|
||||
<div className="container mt-10 mb-20 text-center">
|
||||
<h2>AI that you control</h2>
|
||||
<p className="text-base mt-2 w-full lg:w-2/5 mx-auto leading-relaxed">
|
||||
Private. Local. Infinitely Customizable.
|
||||
</p>
|
||||
<div className="grid text-left lg:grid-cols-2 mt-16 gap-16">
|
||||
{features.map((feat, i) => {
|
||||
return (
|
||||
<div
|
||||
className="flex gap-x-4 p-8 rounded-3xl border bg-gray-100 border-gray-100 dark:border-[#202231] dark:bg-[#111217]"
|
||||
key={i}
|
||||
>
|
||||
<div>
|
||||
<h5>{feat.name}</h5>
|
||||
<p className="mt-2">{feat.desc}</p>
|
||||
<div className="grid text-left lg:grid-cols-2 mt-16 gap-4">
|
||||
<div className="card relative min-h-[380px] lg:min-h-[460px]">
|
||||
<img
|
||||
src="/img/card-element.png"
|
||||
alt="Element"
|
||||
className="absolute w-full bottom-0 left-0"
|
||||
/>
|
||||
<div class="p-8 relative z-40">
|
||||
<h5>Personal AI that runs on your computer</h5>
|
||||
<p className="mt-2">
|
||||
Jan runs directly on your local machine, offering privacy,
|
||||
convenience and customizability.
|
||||
</p>
|
||||
<ThemedImage
|
||||
alt="Group Chat"
|
||||
sources={{
|
||||
light: useBaseUrl("/img/group-chat-light.png"),
|
||||
dark: useBaseUrl("/img/group-chat-dark.png"),
|
||||
}}
|
||||
className="mt-10"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<div className="card relative min-h-[380px] lg:min-h-[460px]">
|
||||
<div className="p-8">
|
||||
<h5>Extendable via App and Plugin framework</h5>
|
||||
<p className="mt-2">
|
||||
Jan has a versatile app and plugin framework, allowing you
|
||||
to customize it to your needs.
|
||||
</p>
|
||||
</div>
|
||||
</div> */}
|
||||
<div class="container">
|
||||
<div class="flex">
|
||||
<ThemedImage
|
||||
alt="Framework"
|
||||
sources={{
|
||||
light: useBaseUrl("/img/card-framework-light.png"),
|
||||
dark: useBaseUrl("/img/card-framework-dark.png"),
|
||||
}}
|
||||
className="w-11/12 ml-auto mt-auto"
|
||||
/>
|
||||
</div>
|
||||
<div className="card relative min-h-[380px] lg:min-h-[460px]">
|
||||
<div className="p-8">
|
||||
<h5>
|
||||
Private and offline, your data never leaves your machine
|
||||
</h5>
|
||||
<p className="mt-2">
|
||||
Your conversations and data are with an AI that runs on your
|
||||
computer, where only you have access.
|
||||
</p>
|
||||
</div>
|
||||
<ThemedImage
|
||||
alt="Group Chat"
|
||||
sources={{
|
||||
light: useBaseUrl("/img/card-nitro-light.png"),
|
||||
dark: useBaseUrl("/img/card-nitro-dark.png"),
|
||||
}}
|
||||
className="w-3/4 mx-auto mt-auto"
|
||||
/>
|
||||
</div>
|
||||
<div className="card relative min-h-[380px] lg:min-h-[460px]">
|
||||
<div className="p-8">
|
||||
<h5>No subscription fees, the AI runs on your computer</h5>
|
||||
<p className="mt-2">
|
||||
Say goodbye to monthly subscriptions or usage-based APIs.
|
||||
Jan runs 100% free on your own hardware.
|
||||
</p>
|
||||
</div>
|
||||
<ThemedImage
|
||||
alt="Group Chat"
|
||||
sources={{
|
||||
light: useBaseUrl("/img/card-free-light.png"),
|
||||
dark: useBaseUrl("/img/card-free-dark.png"),
|
||||
}}
|
||||
className="w-full mt-auto mx-auto"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container lg:px-20 py-20 text-center lg:text-left">
|
||||
<div class="flex flex-col lg:flex-row space-y-20 lg:space-y-0">
|
||||
<div>
|
||||
<h1 className="text-7xl">Your AI, forever.</h1>
|
||||
<p>Apps come and go, but your AI and data should last. </p>
|
||||
<p className="text-2xl mt-2">
|
||||
Apps come and go, but your AI and data should last.{" "}
|
||||
</p>
|
||||
<div class="w-full lg:w-3/4 mt-8">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-10 lg:gap-24">
|
||||
<div>
|
||||
<img
|
||||
src="/img/ic-park-solid-unlock.svg"
|
||||
alt="Icon - Lock"
|
||||
className="w-8 mb-4 mx-auto lg:mx-0"
|
||||
/>
|
||||
<p>
|
||||
Jan uses open, standard and non-proprietary files stored
|
||||
locally on your device.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<img
|
||||
src="img/ic-baseline-control-camera.svg"
|
||||
alt="Icon - Camera"
|
||||
className="w-8 mb-4 mx-auto lg:mx-0"
|
||||
/>
|
||||
<p>
|
||||
You have total control over your AI, which means you can
|
||||
use Jan offline and switch to another app easily if you
|
||||
want.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container py-20 text-center">
|
||||
</div>
|
||||
|
||||
<div className="w-full lg:w-80 text-center">
|
||||
<ThemedImage
|
||||
alt="App screenshot"
|
||||
sources={{
|
||||
light: useBaseUrl("/img/jan-icon-light.png"),
|
||||
dark: useBaseUrl("/img/jan-icon-dark.png"),
|
||||
}}
|
||||
className="w-40 lg:w-full mx-auto"
|
||||
/>
|
||||
<p className="mt-1 font-bold">100% free on your own hardware</p>
|
||||
<DownloadLink />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container pb-20 pt-10 text-center">
|
||||
<h2>
|
||||
We are open-source. <br /> Join Jan community.
|
||||
</h2>
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
0px 1px 2px 0px #525154 inset;
|
||||
}
|
||||
.card {
|
||||
@apply p-8 rounded-3xl border bg-gray-100 border-gray-100 dark:border-[#202231] dark:bg-[#111217];
|
||||
@apply rounded-3xl border bg-gray-100 border-gray-100 dark:border-[#202231] dark:bg-[#111217];
|
||||
|
||||
&-link {
|
||||
display: inline-flex;
|
||||
|
||||
BIN
docs/static/img/card-element.png
vendored
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
docs/static/img/card-framework-dark.png
vendored
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
docs/static/img/card-framework-light.png
vendored
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
docs/static/img/card-free-dark.png
vendored
Normal file
|
After Width: | Height: | Size: 236 KiB |
BIN
docs/static/img/card-free-light.png
vendored
Normal file
|
After Width: | Height: | Size: 181 KiB |
BIN
docs/static/img/card-nitro-dark.png
vendored
Normal file
|
After Width: | Height: | Size: 73 KiB |
BIN
docs/static/img/card-nitro-light.png
vendored
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
docs/static/img/group-chat-dark.png
vendored
Normal file
|
After Width: | Height: | Size: 145 KiB |
BIN
docs/static/img/group-chat-light.png
vendored
Normal file
|
After Width: | Height: | Size: 139 KiB |
4
docs/static/img/ic-baseline-control-camera.svg
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="36" height="37" viewBox="0 0 36 37" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M23.31 8.41986L20.655 11.0599L18 8.41986L15.345 11.0599L12.69 8.41986L18 3.10986L23.31 8.41986ZM27.69 23.4199L25.05 20.7649L27.69 18.1099L25.05 15.4549L27.69 12.7999L33 18.1099L27.69 23.4199ZM12.69 27.7999L15.345 25.1599L18 27.7999L20.655 25.1599L23.31 27.7999L18 33.1099L12.69 27.7999ZM8.31 12.7999L10.95 15.4549L8.31 18.1099L10.95 20.7649L8.31 23.4199L3 18.1099L8.31 12.7999Z" fill="#3B82F6"/>
|
||||
<path d="M18 22.6099C20.4853 22.6099 22.5 20.5951 22.5 18.1099C22.5 15.6246 20.4853 13.6099 18 13.6099C15.5147 13.6099 13.5 15.6246 13.5 18.1099C13.5 20.5951 15.5147 22.6099 18 22.6099Z" fill="#3B82F6"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 712 B |
10
docs/static/img/ic-park-solid-unlock.svg
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
<svg width="36" height="37" viewBox="0 0 36 37" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="mask0_206_5233" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="3" y="1" width="30" height="34">
|
||||
<path d="M29.25 16.6458H6.75C5.92157 16.6458 5.25 17.3173 5.25 18.1458V31.6458C5.25 32.4742 5.92157 33.1458 6.75 33.1458H29.25C30.0784 33.1458 30.75 32.4742 30.75 31.6458V18.1458C30.75 17.3173 30.0784 16.6458 29.25 16.6458Z" fill="white" stroke="white" stroke-width="3" stroke-linejoin="round"/>
|
||||
<path d="M10.5 16.6097V10.6135C10.4963 6.76224 13.4423 3.53499 17.3145 3.14799C21.1868 2.76099 24.7253 5.34024 25.5 9.11424" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M18 22.6099V27.1099" stroke="black" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_206_5233)">
|
||||
<path d="M0 0.109863H36V36.1099H0V0.109863Z" fill="#3B82F6"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 940 B |
BIN
docs/static/img/jan-icon-dark.png
vendored
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
docs/static/img/jan-icon-light.png
vendored
Normal file
|
After Width: | Height: | Size: 30 KiB |