mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2026-05-24 00:09:19 -04:00
just a bunch 'o stuff
This commit is contained in:
@@ -40,6 +40,7 @@
|
||||
"byte-size": "^8.1.0",
|
||||
"clsx": "^1.1.1",
|
||||
"immer": "^9.0.6",
|
||||
"jotai": "^1.6.0",
|
||||
"moment": "^2.29.1",
|
||||
"phosphor-react": "^1.3.1",
|
||||
"pretty-bytes": "^5.6.0",
|
||||
@@ -48,11 +49,14 @@
|
||||
"react-dropzone": "^11.3.4",
|
||||
"react-error-boundary": "^3.1.3",
|
||||
"react-hotkeys-hook": "^3.4.4",
|
||||
"react-portal": "^4.2.1",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"react-spline": "^1.2.1",
|
||||
"react-transition-group": "^4.4.2",
|
||||
"react-virtuoso": "^2.2.6",
|
||||
"rooks": "^5.7.1",
|
||||
"tailwindcss": "^3.0.7",
|
||||
"ui": "*",
|
||||
"vite": "^2.4.4",
|
||||
"vite-plugin-filter-replace": "^0.1.9",
|
||||
"vite-plugin-react-svg": "^0.2.0",
|
||||
|
||||
@@ -14,7 +14,7 @@ fn main() {
|
||||
let app = app.handle();
|
||||
|
||||
let window = app.get_window("main").unwrap();
|
||||
window.set_shadow(true);
|
||||
// window.set_shadow(true);
|
||||
|
||||
tauri::async_runtime::spawn(async move {
|
||||
while let Some(event) = core_receiver.recv().await {
|
||||
|
||||
@@ -1,29 +1,28 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import React, {useContext, useEffect, useState} from 'react';
|
||||
import { Route, BrowserRouter as Router, Switch, Redirect } from 'react-router-dom';
|
||||
import { Sidebar } from './components/file/Sidebar';
|
||||
import { TopBar } from './components/layout/TopBar';
|
||||
import { useInputState } from './hooks/useInputState';
|
||||
import { SettingsScreen } from './screens/Settings';
|
||||
import { ExplorerScreen } from './screens/Explorer';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
import { DebugGlobalStore } from './Debug';
|
||||
import { useCoreEvents } from './hooks/useCoreEvents';
|
||||
import { AppState, useAppState } from './store/global';
|
||||
import { Modal } from './components/layout/Modal';
|
||||
import { useKey, useKeyBindings } from 'rooks';
|
||||
// import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { Button } from 'ui';
|
||||
import { ErrorBoundary, FallbackProps } from 'react-error-boundary';
|
||||
import { Button } from './components/primitive';
|
||||
import { useLocationStore, Location } from './store/locations';
|
||||
import { OverviewScreen } from './screens/Overview';
|
||||
import { SpacesScreen } from './screens/Spaces';
|
||||
import {createModal, Modal} from "./components/layout/Modal";
|
||||
|
||||
export const SettingsModal = createModal('settings');
|
||||
|
||||
function ErrorFallback({ error, resetErrorBoundary }: FallbackProps) {
|
||||
return (
|
||||
<div
|
||||
data-tauri-drag-region
|
||||
role="alert"
|
||||
className="flex flex-col items-center justify-center w-screen h-screen p-4 border border-gray-200 rounded-lg dark:border-gray-650 bg-gray-50 dark:bg-gray-350 dark:text-white"
|
||||
className="flex flex-col items-center justify-center w-screen h-screen p-4 border border-gray-200 rounded-lg dark:border-gray-650 bg-gray-50 dark:bg-gray-950 dark:text-white"
|
||||
>
|
||||
<p className="m-3 text-sm font-bold text-gray-400">APP CRASHED</p>
|
||||
<h1 className="text-2xl font-bold">We're past the event horizon...</h1>
|
||||
@@ -53,6 +52,7 @@ export default function App() {
|
||||
// process.exit();
|
||||
// });
|
||||
|
||||
|
||||
return (
|
||||
<ErrorBoundary
|
||||
FallbackComponent={ErrorFallback}
|
||||
@@ -62,15 +62,15 @@ export default function App() {
|
||||
>
|
||||
<Router>
|
||||
<div className="flex flex-row h-screen overflow-hidden text-gray-900 bg-white border border-gray-200 select-none rounded-xl dark:border-gray-500 dark:text-white dark:bg-gray-650">
|
||||
<Modal {...SettingsModal}>
|
||||
<SettingsScreen />
|
||||
</Modal>
|
||||
<DebugGlobalStore />
|
||||
<Sidebar />
|
||||
<div className="flex flex-col w-full min-h-full">
|
||||
<TopBar />
|
||||
<div className="relative flex w-full">
|
||||
<Switch>
|
||||
<Route exact path="/">
|
||||
<Redirect to="/explorer" />
|
||||
</Route>
|
||||
<Route path="/overview">
|
||||
<OverviewScreen />
|
||||
</Route>
|
||||
@@ -80,13 +80,11 @@ export default function App() {
|
||||
<Route path="/explorer">
|
||||
<ExplorerScreen />
|
||||
</Route>
|
||||
<Route path="/settings">
|
||||
<SettingsScreen />
|
||||
</Route>
|
||||
|
||||
</Switch>
|
||||
</div>
|
||||
</div>
|
||||
<Modal />
|
||||
|
||||
</div>
|
||||
</Router>
|
||||
</ErrorBoundary>
|
||||
|
||||
@@ -106,10 +106,7 @@ export const Sidebar: React.FC<SidebarProps> = (props) => {
|
||||
<Icon component={CirclesFour} />
|
||||
Spaces
|
||||
</SidebarLink>
|
||||
<SidebarLink to="/explorer">
|
||||
<Icon component={Folder} />
|
||||
Explorer
|
||||
</SidebarLink>
|
||||
|
||||
<SidebarLink to="/settings">
|
||||
<Icon component={MonitorPlay} />
|
||||
Media
|
||||
@@ -119,8 +116,8 @@ export const Sidebar: React.FC<SidebarProps> = (props) => {
|
||||
<Heading>Locations</Heading>
|
||||
{locations.map((location, index) => {
|
||||
return (
|
||||
<div className="flex flex-row items-center">
|
||||
<SidebarLink className="relative group" key={index} to={`/explorer/${location.name}`}>
|
||||
<div key={index} className="flex flex-row items-center">
|
||||
<SidebarLink className="relative group" to={`/explorer/${location.name}`}>
|
||||
<Icon component={ServerIcon} />
|
||||
{location.name}
|
||||
<div className="flex-grow" />
|
||||
|
||||
@@ -1,35 +1,42 @@
|
||||
import { Transition } from '@headlessui/react';
|
||||
import clsx from 'clsx';
|
||||
import React, { createContext, useState } from 'react';
|
||||
import React, {ComponentProps, createContext, useState} from 'react';
|
||||
import {atom, useAtom, WritableAtom} from "jotai";
|
||||
import {createPortal} from "react-dom";
|
||||
export interface ModalProps {
|
||||
name: string;
|
||||
open: WritableAtom<boolean, boolean>,
|
||||
full?: boolean;
|
||||
}
|
||||
|
||||
export interface ModalProps {}
|
||||
export function createModal(name: string): ModalProps {
|
||||
return { name, open: atom(true) as WritableAtom<boolean, boolean> }
|
||||
}
|
||||
|
||||
const modalContext = createContext({ open: false });
|
||||
export const Modal: React.FC<ModalProps> = (props) => {
|
||||
const [open, setOpen] = useAtom(props.open);
|
||||
|
||||
export const Modal = (props: ModalProps) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
return (
|
||||
<div
|
||||
data-tauri-drag-region
|
||||
onClick={() => setOpen(false)}
|
||||
className={clsx(
|
||||
'transition-opacity w-screen h-screen p-5 absolute t-0 bg-black bg-opacity-30 m-[1px] rounded-lg',
|
||||
'transition-opacity absolute flex w-full h-full p-5 t-0 bg-black bg-opacity-80 m-[1px] rounded-lg z-50',
|
||||
{ 'pointer-events-none hidden': !open }
|
||||
)}
|
||||
>
|
||||
<Transition
|
||||
show={open}
|
||||
enter="transition-translate ease-in-out duration-200"
|
||||
enterFrom="-scale-2"
|
||||
enterTo="scale-0"
|
||||
leave="transition-translate ease-in-out duration-200"
|
||||
leaveFrom="scale-0"
|
||||
leaveTo="-scale-2"
|
||||
// enter="transition-translate ease-in-out duration-200"
|
||||
// enterFrom="-scale-2"
|
||||
// enterTo="scale-0"
|
||||
// leave="transition-translate ease-in-out duration-200"
|
||||
// leaveFrom="scale-0"
|
||||
// leaveTo="-scale-2"
|
||||
>
|
||||
<div className="w-full h-full bg-white rounded-lg shadow-xl dark:bg-gray-850">
|
||||
<h1 className="m-10">hi</h1>
|
||||
<div className="w-full h-full flex flex-grow bg-white rounded-lg shadow-xl dark:bg-gray-850">
|
||||
{props.children}
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
);
|
||||
</div>);
|
||||
};
|
||||
|
||||
@@ -21,6 +21,9 @@ import { appWindow } from '@tauri-apps/api/window';
|
||||
import { HeartIcon } from '@heroicons/react/solid';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
|
||||
import { SettingsModal } from '../../App'
|
||||
import {useAtom} from "jotai";
|
||||
|
||||
export interface TopBarProps extends DefaultProps {}
|
||||
export interface TopBarButtonProps extends ButtonProps {
|
||||
icon: any;
|
||||
@@ -51,12 +54,13 @@ const TopBarButton: React.FC<TopBarButtonProps> = ({ icon: Icon, ...props }) =>
|
||||
};
|
||||
|
||||
export const TopBar: React.FC<TopBarProps> = (props) => {
|
||||
const [settingsOpen, setSettingsOpen] = useAtom(SettingsModal.open)
|
||||
const [goBack] = useExplorerStore((state) => [state.goBack]);
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
data-tauri-drag-region
|
||||
className="flex h-[2.95rem] -mt-0.5 max-w z-50 pl-3 rounded-tr-2xl items-center border-b bg-gray-50 dark:bg-gray-600 border-gray-100 dark:border-gray-800 !bg-opacity-100 backdrop-blur"
|
||||
className="flex h-[2.95rem] -mt-0.5 max-w z-10 pl-3 rounded-tr-2xl items-center border-b bg-gray-50 dark:bg-gray-600 border-gray-100 dark:border-gray-800 !bg-opacity-100 backdrop-blur"
|
||||
>
|
||||
<div className="">
|
||||
<TopBarButton icon={ChevronLeftIcon} onClick={goBack} />
|
||||
@@ -92,7 +96,9 @@ export const TopBar: React.FC<TopBarProps> = (props) => {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<TopBarButton className="mr-[8px]" icon={CogIcon} />
|
||||
<TopBarButton onClick={() => {
|
||||
setSettingsOpen(!settingsOpen);
|
||||
}} className="mr-[8px]" icon={CogIcon} />
|
||||
</div>
|
||||
{/* <div className="h-[1px] flex-shrink-0 max-w bg-gray-200 dark:bg-gray-700" /> */}
|
||||
</>
|
||||
|
||||
@@ -5,6 +5,7 @@ import { invoke } from '@tauri-apps/api';
|
||||
import { IFile } from '../types';
|
||||
import { useExplorerStore } from '../store/explorer';
|
||||
import { Inspector } from '../components/file/Inspector';
|
||||
import {useParams} from "react-router-dom";
|
||||
|
||||
export interface DirectoryResponse {
|
||||
directory: IFile;
|
||||
@@ -12,6 +13,9 @@ export interface DirectoryResponse {
|
||||
}
|
||||
|
||||
export const ExplorerScreen: React.FC<{}> = () => {
|
||||
|
||||
// let { slug } = useParams();
|
||||
|
||||
const [currentDir, tempWatchDir] = useExplorerStore((state) => [
|
||||
state.currentDir,
|
||||
state.tempWatchDir
|
||||
@@ -21,7 +25,6 @@ export const ExplorerScreen: React.FC<{}> = () => {
|
||||
invoke<DirectoryResponse>('get_files', { path: tempWatchDir }).then((res) => {
|
||||
console.log({ res });
|
||||
useExplorerStore.getState().ingestDir(res.directory, res.contents);
|
||||
invoke('get_thumbs_for_directory', { path: tempWatchDir });
|
||||
});
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import { Checkbox } from '../components/primitive/Checkbox';
|
||||
import { Dropdown } from '../components/primitive/Dropdown';
|
||||
import { InputContainer } from '../components/primitive/InputContainer';
|
||||
import { Shortcut } from '../components/primitive/Shortcut';
|
||||
import { useInputState } from '../hooks/useInputState';
|
||||
import { useExplorerStore } from '../store/explorer';
|
||||
import { useAppState } from '../store/global';
|
||||
//@ts-ignore
|
||||
@@ -18,7 +17,7 @@ import { useAppState } from '../store/global';
|
||||
export const SettingsScreen: React.FC<{}> = () => {
|
||||
const fileUploader = useRef<HTMLInputElement | null>(null);
|
||||
|
||||
const config = useAppState()
|
||||
const config = useAppState()
|
||||
|
||||
const [tempWatchDir, setTempWatchDir] = useExplorerStore((state) => [
|
||||
state.tempWatchDir,
|
||||
@@ -51,22 +50,14 @@ const config = useAppState()
|
||||
<Button
|
||||
size="sm"
|
||||
variant="primary"
|
||||
onClick={() => {
|
||||
invoke('scan_dir', {
|
||||
onClick={async () => {
|
||||
await invoke('scan_dir', {
|
||||
path: tempWatchDir
|
||||
});
|
||||
}}
|
||||
>
|
||||
Scan Now
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
invoke('test_scan');
|
||||
}}
|
||||
>
|
||||
Test Scan
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row mt-4 space-x-2">
|
||||
|
||||
@@ -5,36 +5,36 @@ import { Tag } from '../components/primitive/Tag';
|
||||
export const SpacesScreen: React.FC<{}> = (props) => {
|
||||
return (
|
||||
<div className="flex flex-col w-full h-full px-2 py-5">
|
||||
<div className="-mt-[1px] space-x-2 ml-1">
|
||||
<Tag color="red">Videos</Tag>
|
||||
<Tag color="orange">DSLR Photos</Tag>
|
||||
<Tag color="yellow">Camera Roll</Tag>
|
||||
<Tag color="green">NFTs</Tag>
|
||||
<Tag color="pink">Screenshots</Tag>
|
||||
<Tag color="blue">Documents</Tag>
|
||||
<Tag color="purple">Repositories</Tag>
|
||||
</div>
|
||||
<div className="flex flex-wrap p-2 my-3 space-x-2 bg-black rounded">
|
||||
<div className="w-10 h-10 rounded bg-gray-950" />
|
||||
<div className="w-10 h-10 bg-gray-900 rounded" />
|
||||
<div className="w-10 h-10 rounded bg-gray-850" />
|
||||
<div className="w-10 h-10 bg-gray-800 rounded" />
|
||||
<div className="w-10 h-10 rounded bg-gray-750" />
|
||||
<div className="w-10 h-10 bg-gray-700 rounded" />
|
||||
<div className="w-10 h-10 rounded bg-gray-650" />
|
||||
<div className="w-10 h-10 bg-gray-600 rounded" />
|
||||
<div className="w-10 h-10 rounded bg-gray-550" />
|
||||
<div className="w-10 h-10 bg-gray-400 rounded" />
|
||||
<div className="w-10 h-10 rounded bg-gray-450" />
|
||||
<div className="w-10 h-10 bg-gray-400 rounded" />
|
||||
<div className="w-10 h-10 rounded bg-gray-350" />
|
||||
<div className="w-10 h-10 bg-gray-300 rounded" />
|
||||
<div className="w-10 h-10 rounded bg-gray-250" />
|
||||
{/* <div className="w-10 h-10 bg-gray-200 rounded" />
|
||||
<div className="w-10 h-10 rounded bg-gray-150" />
|
||||
<div className="w-10 h-10 bg-gray-100 rounded" />
|
||||
<div className="w-10 h-10 rounded bg-gray-50" /> */}
|
||||
</div>
|
||||
{/*<div className="-mt-[1px] space-x-2 ml-1">*/}
|
||||
{/* <Tag color="red">Videos</Tag>*/}
|
||||
{/* <Tag color="orange">DSLR Photos</Tag>*/}
|
||||
{/* <Tag color="yellow">Camera Roll</Tag>*/}
|
||||
{/* <Tag color="green">NFTs</Tag>*/}
|
||||
{/* <Tag color="pink">Screenshots</Tag>*/}
|
||||
{/* <Tag color="blue">Documents</Tag>*/}
|
||||
{/* <Tag color="purple">Repositories</Tag>*/}
|
||||
{/*</div>*/}
|
||||
{/*<div className="flex flex-wrap p-2 my-3 space-x-2 bg-black rounded">*/}
|
||||
{/* <div className="w-10 h-10 rounded bg-gray-950" />*/}
|
||||
{/* <div className="w-10 h-10 bg-gray-900 rounded" />*/}
|
||||
{/* <div className="w-10 h-10 rounded bg-gray-850" />*/}
|
||||
{/* <div className="w-10 h-10 bg-gray-800 rounded" />*/}
|
||||
{/* <div className="w-10 h-10 rounded bg-gray-750" />*/}
|
||||
{/* <div className="w-10 h-10 bg-gray-700 rounded" />*/}
|
||||
{/* <div className="w-10 h-10 rounded bg-gray-650" />*/}
|
||||
{/* <div className="w-10 h-10 bg-gray-600 rounded" />*/}
|
||||
{/* <div className="w-10 h-10 rounded bg-gray-550" />*/}
|
||||
{/* <div className="w-10 h-10 bg-gray-400 rounded" />*/}
|
||||
{/* <div className="w-10 h-10 rounded bg-gray-450" />*/}
|
||||
{/* <div className="w-10 h-10 bg-gray-400 rounded" />*/}
|
||||
{/* <div className="w-10 h-10 rounded bg-gray-350" />*/}
|
||||
{/* <div className="w-10 h-10 bg-gray-300 rounded" />*/}
|
||||
{/* <div className="w-10 h-10 rounded bg-gray-250" />*/}
|
||||
{/* /!* <div className="w-10 h-10 bg-gray-200 rounded" />*/}
|
||||
{/* <div className="w-10 h-10 rounded bg-gray-150" />*/}
|
||||
{/* <div className="w-10 h-10 bg-gray-100 rounded" />*/}
|
||||
{/* <div className="w-10 h-10 rounded bg-gray-50" /> *!/*/}
|
||||
{/*</div>*/}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
{
|
||||
"extends": "config/tsconfig/tauri.json",
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules"]
|
||||
"exclude": ["node_modules"],
|
||||
"compilerOptions": {
|
||||
"jsx": "react"
|
||||
}
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
module.exports = require("config/eslint-preset");
|
||||
module.exports = require("@calcom/config/eslint-preset");
|
||||
|
||||
7
apps/docs/.gitignore
vendored
Normal file
7
apps/docs/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
node_modules
|
||||
.next
|
||||
.DS_Store
|
||||
yarn-error.log
|
||||
dist
|
||||
examples
|
||||
packages
|
||||
1
apps/docs/.nvmrc
Normal file
1
apps/docs/.nvmrc
Normal file
@@ -0,0 +1 @@
|
||||
14.17
|
||||
2
apps/docs/.prettierignore
Normal file
2
apps/docs/.prettierignore
Normal file
@@ -0,0 +1,2 @@
|
||||
.next
|
||||
node_modules
|
||||
21
apps/docs/LICENSE
Normal file
21
apps/docs/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Shu Ding
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,30 +1,75 @@
|
||||
## Getting Started
|
||||
<!-- PROJECT LOGO -->
|
||||
<div align="right">
|
||||
<a href="https://github.com/calcom/cal.com">
|
||||
<img src="https://user-images.githubusercontent.com/8019099/133430653-24422d2a-3c8d-4052-9ad6-0580597151ee.png" alt="Logo">
|
||||
</a>
|
||||
<a href="https://cal.com">Website</a>
|
||||
·
|
||||
<a href="https://github.com/calcom/docs/issues">Community Support</a>
|
||||
</div>
|
||||
|
||||
First, run the development server:
|
||||
# Cal.com Documentation
|
||||
|
||||
```bash
|
||||
The official product, support and developer documentation, containing information and guides about using the product as well as support for self-hosted installations. This documentation site runs on [Nextra](https://nextra.vercel.app), so you may refer to their documentation should you need information on anything that isn't covered here.
|
||||
|
||||
## Prerequisites
|
||||
- Git
|
||||
- Node.js & npm
|
||||
- Yarn
|
||||
|
||||
## Installation
|
||||
Firstly, clone the repository using Git:
|
||||
```console
|
||||
git clone https://github.com/calcom/docs.git
|
||||
```
|
||||
|
||||
Now, you can install the dependencies with yarn:
|
||||
```console
|
||||
yarn install
|
||||
```
|
||||
|
||||
## Editing
|
||||
To create, edit and delete documentation pages, you can simply create markdown (.mdx) files in the `pages/` folder. You can edit Markdown with any text editor, but VS Code and WebStorm have side-by-side previews so you can see your formatted content whilst writing markdown.
|
||||
|
||||
You will also need to add it as an entry to the `meta.json` file found in whichever directory that the .mdx file is in.
|
||||
|
||||
## Local Development
|
||||
|
||||
```console
|
||||
yarn dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
|
||||
|
||||
You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
|
||||
## Build
|
||||
|
||||
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`.
|
||||
```console
|
||||
yarn build
|
||||
```
|
||||
|
||||
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
|
||||
This command generates static content into the `build` directory and can be served using any static content hosting service.
|
||||
|
||||
## Learn More
|
||||
## How to easily contribute
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
## Existing Page
|
||||
1. From the documentation's GitHub repository, head to the folder called 'pages' and open it.
|
||||
2. From here you can view all current pages on the documentation site. Select the page you would like to contribute to.
|
||||
3. You should now be able to view the page you have selected. Located at the top right of the page will be a pencil icon. Pressing this will bring you up an editor to edit and make changes. You can add formatting using the buttons at the top, which will automatically insert the relevant markdown content needed to style the text.
|
||||
4. From here make the changes you wish to make.
|
||||
5. At the bottom of the screen will be a 'Propose Changes' box, fill in all the relevant details such as title and description then press the green 'Propose Changes' button.
|
||||
6. Your changes have been saved, to submit them for review, located on your screen, press the green 'Create Pull Request' button.
|
||||
7. Fill in all the relevant details such as title and description and after finalize the submission.
|
||||
|
||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||
You have now successfully edited and submitted changes to our documentation site.
|
||||
|
||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
|
||||
## Creating a New Page
|
||||
|
||||
## Deploy on Vercel
|
||||
1. From the documentation's GitHub repository, head to the folder called 'pages' and open it.
|
||||
2. From here you can view all current pages on the documentation site. At the top of your screen press the 'New file' button.
|
||||
3. You should now be able to view the page you have created. Remember when renaming the document to put .mdx at the end of the file name.
|
||||
4. From here make the changes you wish to make. Such as creating a title, sub-title and body text.
|
||||
5. At the bottom of the screen will be a 'Propose Changes' box, fill in all the relevant details such as title and description then press the green 'Propose Changes' button.
|
||||
6. Your changes have been saved, to submit them for review, located on your screen, press the greem 'Create Pull Request' button.
|
||||
7. Fill in all the relevant details such as title and description and after finalize the submission.
|
||||
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_source=github.com&utm_medium=referral&utm_campaign=turborepo-readme) from the creators of Next.js.
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
|
||||
You have now successfully created and submitted changes to our documentation site.
|
||||
|
||||
6
apps/docs/next-env.d.ts
vendored
6
apps/docs/next-env.d.ts
vendored
@@ -1,6 +0,0 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/types/global" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||
@@ -1,5 +1,8 @@
|
||||
const withTM = require("next-transpile-modules")(["ui"]);
|
||||
|
||||
module.exports = withTM({
|
||||
reactStrictMode: true,
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const withNextra = require('nextra')({
|
||||
theme: 'nextra-theme-docs',
|
||||
themeConfig: './theme.config.js',
|
||||
unstable_staticImage: true
|
||||
});
|
||||
|
||||
module.exports = withNextra();
|
||||
|
||||
@@ -3,23 +3,27 @@
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev --port 3001",
|
||||
"dev": "next dev --port 6001",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "12.0.3",
|
||||
"next": "^12.0.9",
|
||||
"nextra": "^1.1.0",
|
||||
"nextra-theme-docs": "^2.0.0-beta.5",
|
||||
"prism-react-renderer": "^1.3.1",
|
||||
"prismjs": "^1.26.0",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"ui": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "17.0.37",
|
||||
"config": "*",
|
||||
"eslint": "7.32.0",
|
||||
"next-transpile-modules": "9.0.0",
|
||||
"tsconfig": "*",
|
||||
"@types/react": "17.0.37",
|
||||
"typescript": "^4.5.3"
|
||||
}
|
||||
}
|
||||
|
||||
12
apps/docs/pages/_app.js
Normal file
12
apps/docs/pages/_app.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import 'nextra-theme-docs/style.css';
|
||||
import './style.css';
|
||||
import Prism from 'prism-react-renderer/prism';
|
||||
|
||||
(typeof global !== 'undefined' ? global : window).Prism = Prism;
|
||||
|
||||
require('prismjs/components/prism-typescript');
|
||||
require('prismjs/components/prism-rust');
|
||||
|
||||
export default function Nextra({ Component, pageProps }) {
|
||||
return <Component {...pageProps} />;
|
||||
}
|
||||
105
apps/docs/pages/architecture/ideas.mdx
Normal file
105
apps/docs/pages/architecture/ideas.mdx
Normal file
@@ -0,0 +1,105 @@
|
||||
import Callout from 'nextra-theme-docs/callout';
|
||||
|
||||
# Ideas
|
||||
|
||||
<Callout emoji="👾">
|
||||
**Space Invaders** is a 1978 shoot 'em up arcade game developed by Tomohiro Nishikado.
|
||||
</Callout>
|
||||
|
||||
> A self hosted, bulletproof, personal cloud.
|
||||
|
||||
> Bringing the magic of cloud services like iCloud and google photos to your local devices.
|
||||
|
||||
> Don’t think in drives.
|
||||
|
||||
> A pure rust core brings efficiency and compatibility to complex file management system.
|
||||
|
||||
### Architecture
|
||||
|
||||
```javascript
|
||||
import '../styles/fonts.css';
|
||||
import '../styles/globals.css';
|
||||
```
|
||||
|
||||
```rust
|
||||
pub enum Action {
|
||||
SCAN_DIR,
|
||||
ENCRYPT_FILE,
|
||||
UPLOAD_FILE,
|
||||
}
|
||||
```
|
||||
|
||||
- **meta_integrity_hash**<br />
|
||||
`location + path`<br />
|
||||
This allows us to quickly assume a file we have already scanned still exists at that location.<br />
|
||||
_Note: Could potentiallty be replaced by a unique constraint on location+path_
|
||||
- **sample_byte_integrity_hash**<br />
|
||||
`100 * 100 byte samples at equal points throughout file`<br />
|
||||
this is used to find duplicates quickly
|
||||
- **byte_integrity_hash**<br />
|
||||
`full byte-to-byte checksum on file contents`<br />
|
||||
this is used to confirm duplicates
|
||||
|
||||
path must be stored so we can handle system delete events and update database accordingly
|
||||
^ of course but that’s a simple query on destructured volume/location/path
|
||||
|
||||
duplicate files should have a new File created but it receives no metadata, the parent File, aka the first instance discovered, consumes all metadata and master_file_id determines this link
|
||||
|
||||
add deleted_at to File
|
||||
|
||||
.spacedrive file can exist in a directory to identify it as something other than a directory, such as a single file with a custom UI
|
||||
|
||||
we can also define hard coded enhancements to the visual display of directories based on context
|
||||
|
||||
If a new file has the same sampled_byte_integrity hash on the currently loaded volume we check to see if it still exists at that other location. if so, we assign as a duplicate. if not, we count it as a move and update the original File to the new location.
|
||||
|
||||
after every file is updated we run a set of checks, or routines.
|
||||
or a file being updated puts it into a “touched” state queuing it up for inspection routines
|
||||
|
||||
database mutations are processed as commits, through an enum of commit types, we take data and commit it to database
|
||||
|
||||
wanted state for missing files
|
||||
|
||||
sync server uses redis to queue sync chunks
|
||||
|
||||
file types are an enum to allow for extended functionality
|
||||
|
||||
```rust
|
||||
pub enum FileType {
|
||||
File,
|
||||
RichFile
|
||||
Directory,
|
||||
Package,
|
||||
Alias,
|
||||
}
|
||||
|
||||
pub enum Package {
|
||||
WebPage,
|
||||
ThumbnailMedia,
|
||||
PreviewMedia,
|
||||
Custom
|
||||
}
|
||||
```
|
||||
|
||||
### Promotion
|
||||
|
||||
_show a pile of drives_
|
||||
“if this is you, you’ll know how much of a pain it is to deal with this much data. We’re in a world now where independent creatives are the new normal, our data is steadily accumulating but the tooling hasn’t caught up yet”
|
||||
|
||||
“Cloud services like Google Photos and iCloud have great features, beautiful UI—but you’re locked in with a very limited capacity. Many people have multiple cloud accounts each with their own restrictions. Drives that aren’t backed up, collecting dust and at risk of failure.
|
||||
|
||||
“Spacedrive is a beautiful interface to organize and consume an unlimited amount of data, bringing each and every one of your devices together to form your own cloud. It’s incredible to see it all come together.
|
||||
|
||||
We’re in a world now where independent creatives are the new normal, our data is steadily accumulating but the tooling hasn’t caught up yet. Cloud services like Google Photos and iCloud have great features, beautiful UI—but you’re locked in with a very limited capacity. Many people have multiple cloud accounts, drives that aren’t backed up and collecting dust, data at risk of loss. I wanted a solution that didn’t tie me to any one provider, a photo album shouldn’t exist only in my iCloud account, it should be universal and permanent. I believe open source technology is the solution to this, with incredibly an versatile and secure architecture
|
||||
|
||||
“a beautiful, intentionally crafted user interface to effortlessly and continually archive your vast wealth of memories, creations, and data. a digital legacy that is will stand the test of time, and be truly yours.”
|
||||
|
||||
### Storage Device Presets
|
||||
|
||||
To improve index quality these presets can be automatically applied to the indexer to avoid paths and handle individual files by a ruleset uniquely
|
||||
|
||||
- Macintosh HD
|
||||
- Windows C:/
|
||||
- Linux??
|
||||
|
||||
Drop from index button on dropdown
|
||||
3
apps/docs/pages/architecture/meta.json
Normal file
3
apps/docs/pages/architecture/meta.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"migrations": "Migrations"
|
||||
}
|
||||
3
apps/docs/pages/design/meta.json
Normal file
3
apps/docs/pages/design/meta.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"migrations": "Migrations"
|
||||
}
|
||||
4
apps/docs/pages/developer/meta.json
Normal file
4
apps/docs/pages/developer/meta.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"migrations": "Migrations"
|
||||
}
|
||||
|
||||
18
apps/docs/pages/features/meta.json
Normal file
18
apps/docs/pages/features/meta.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"library": "The Library",
|
||||
"locations": "Locations",
|
||||
"search": "Search",
|
||||
"spaces": "Spaces",
|
||||
"smart-tags": "Smart Tags",
|
||||
"sync": "Sync",
|
||||
"encryption": "Encryption",
|
||||
"key-manager": "Key Manager",
|
||||
"albums": "Albums",
|
||||
"extensions": "Extensions",
|
||||
"encoder": "Encoder",
|
||||
"media-viewer": "Media Viewer",
|
||||
"preview-generation": "Preview Generation",
|
||||
"statistics": "Statistics",
|
||||
"timeline": "Timeline",
|
||||
"workers": "Workers"
|
||||
}
|
||||
25
apps/docs/pages/index.mdx
Normal file
25
apps/docs/pages/index.mdx
Normal file
@@ -0,0 +1,25 @@
|
||||
import Bleed from 'nextra-theme-docs/bleed';
|
||||
import Callout from 'nextra-theme-docs/callout';
|
||||
|
||||
# SpaceDrive
|
||||
|
||||
#### Official Documentation
|
||||
|
||||
<Callout emoji="🪐">We're in pre-alpha v0.0.12 [Download Now]()</Callout>
|
||||
|
||||
Welcome to the SpaceDrive project documentation. These docs outline the product specification, technical
|
||||
architecture and development guides.
|
||||
|
||||
<Bleed>
|
||||

|
||||
</Bleed>
|
||||
### What is it?
|
||||
|
||||
SpaceDrive is an open source virtual filesystem, a personal cloud powered by your everyday devices. Feature-rich benefits of the cloud, only its owned and hosted by you—with security, privacy and ownership as a foundation. SpaceDrive makes it possible to create a **limitless directory** of your digital life that will stand the test of time.
|
||||
|
||||
#### A single source of truth, for every file you own.
|
||||
|
||||
For each client you install, you'll have another node in your personal network. They all share a single encrypted database and work as a team to perform tasks. Prioritizing peer-to-peer LAN connections but always using end-to-end encryption to synchronize in realtime.
|
||||
|
||||
As for UI, it has everything you'd expect from a file explorer and more; a native photo viewer, video and audio player. But also _specific_ support for VODs, git repositories, social media backups, NFTs, screenshots, webpage snapshots, links, notes and more. Community extensions can add support for different filetypes and tailored file viewers.
|
||||
@@ -1,10 +0,0 @@
|
||||
import { Button } from "ui";
|
||||
|
||||
export default function Docs() {
|
||||
return (
|
||||
<div>
|
||||
<h1>Docs</h1>
|
||||
<Button />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
4
apps/docs/pages/meta.json
Normal file
4
apps/docs/pages/meta.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"index": "Home",
|
||||
"features": "Features"
|
||||
}
|
||||
7
apps/docs/pages/style.css
Normal file
7
apps/docs/pages/style.css
Normal file
@@ -0,0 +1,7 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans:wght@700&display=swap');h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-family: 'Noto Sans', sans-serif;
|
||||
}
|
||||
BIN
apps/docs/public/android-chrome-192x192.png
Normal file
BIN
apps/docs/public/android-chrome-192x192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.0 KiB |
BIN
apps/docs/public/android-chrome-256x256.png
Normal file
BIN
apps/docs/public/android-chrome-256x256.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
BIN
apps/docs/public/android-chrome-384x384.png
Normal file
BIN
apps/docs/public/android-chrome-384x384.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
BIN
apps/docs/public/android-chrome-512x512.png
Normal file
BIN
apps/docs/public/android-chrome-512x512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
9
apps/docs/public/browserconfig.xml
Normal file
9
apps/docs/public/browserconfig.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="/mstile-150x150.png"/>
|
||||
<TileColor>#292929</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
||||
19
apps/docs/public/site.webmanifest
Normal file
19
apps/docs/public/site.webmanifest
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "SpaceDrive Docs",
|
||||
"short_name": "SpaceDrive",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#292929",
|
||||
"background_color": "#292929",
|
||||
"display": "standalone"
|
||||
}
|
||||
32
apps/docs/theme.config.js
Normal file
32
apps/docs/theme.config.js
Normal file
@@ -0,0 +1,32 @@
|
||||
export default {
|
||||
github: 'https://github.com/jamiepine/spacedrive',
|
||||
docsRepositoryBase: 'https://github.com/jamiepine/spacedrive/',
|
||||
titleSuffix: ' | SpaceDrive',
|
||||
logo: (
|
||||
<>
|
||||
<span className="hidden mr-2 font-extrabold md:inline">SpaceDrive</span>
|
||||
<span className="hidden font-normal text-gray-600 md:inline">
|
||||
The Virtual Private Filesystem
|
||||
</span>
|
||||
</>
|
||||
),
|
||||
search: true,
|
||||
prevLinks: true,
|
||||
nextLinks: true,
|
||||
footer: true,
|
||||
footerEditLink: 'Edit this page on GitHub',
|
||||
footerText: <>© {new Date().getFullYear()} Jamie Pine. All rights reserved.</>,
|
||||
head: (
|
||||
<>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta httpEquiv="Content-Language" content="en" />
|
||||
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#000000" />
|
||||
<meta name="msapplication-TileColor" content="#ff0000" />
|
||||
</>
|
||||
)
|
||||
};
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"extends": "config/tsconfig/nextjs.json",
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
3623
apps/docs/yarn.lock
Normal file
3623
apps/docs/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"dev": "next dev -p 9003",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
|
||||
BIN
packages/core/Cargo.lock
generated
BIN
packages/core/Cargo.lock
generated
Binary file not shown.
@@ -39,8 +39,8 @@ CREATE TABLE IF NOT EXISTS files (
|
||||
uri TEXT NOT NULL,
|
||||
is_dir BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
meta_integrity_hash TEXT NOT NULL UNIQUE ON CONFLICT IGNORE,
|
||||
sampled_byte_integrity_hash TEXT NOT NULL,
|
||||
byte_integrity_hash TEXT NOT NULL,
|
||||
sampled_byte_integrity_hash TEXT,
|
||||
byte_integrity_hash TEXT,
|
||||
name TEXT,
|
||||
extension TEXT,
|
||||
size_in_bytes TEXT NOT NULL,
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
import * as React from "react";
|
||||
export * from "./Button";
|
||||
|
||||
export * from "./primitive";
|
||||
// export * from "./screens";
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"@types/react": "^17.0.37",
|
||||
"@types/react-dom": "^17.0.11",
|
||||
"tsconfig": "*",
|
||||
"typescript": "^4.5.3"
|
||||
"typescript": "^4.5.3",
|
||||
"react": "^17.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
import * as React from "react";
|
||||
export const Button = () => {
|
||||
return <button>Boop</button>;
|
||||
};
|
||||
100
packages/ui/primitive/Button.tsx
Normal file
100
packages/ui/primitive/Button.tsx
Normal file
@@ -0,0 +1,100 @@
|
||||
import React from 'react';
|
||||
import { ButtonHTMLAttributes, useState } from 'react';
|
||||
import { Switch } from '@headlessui/react';
|
||||
import clsx from 'clsx';
|
||||
|
||||
const sizes = {
|
||||
default: 'py-1 px-3 text-md font-medium',
|
||||
sm: 'py-1 px-2 text-sm font-medium'
|
||||
};
|
||||
|
||||
const variants = {
|
||||
default: `
|
||||
bg-gray-50
|
||||
shadow-sm
|
||||
hover:bg-gray-100
|
||||
active:bg-gray-50
|
||||
dark:bg-gray-650
|
||||
dark:hover:bg-gray-600
|
||||
dark:active:bg-gray-700
|
||||
dark:active:opacity-80
|
||||
|
||||
border-gray-100
|
||||
hover:border-gray-200
|
||||
active:border-gray-200
|
||||
dark:border-gray-600
|
||||
dark:active:border-gray-600
|
||||
dark:hover:border-gray-600
|
||||
|
||||
text-gray-700
|
||||
hover:text-gray-900
|
||||
active:text-gray-600
|
||||
dark:text-gray-200
|
||||
dark:active:text-white
|
||||
dark:hover:text-white
|
||||
`,
|
||||
gray: `
|
||||
bg-gray-100
|
||||
shadow-sm
|
||||
hover:bg-gray-200
|
||||
active:bg-gray-100
|
||||
dark:bg-gray-800
|
||||
dark:hover:bg-gray-700
|
||||
dark:active:bg-gray-700
|
||||
dark:active:opacity-80
|
||||
|
||||
border-gray-200
|
||||
hover:border-gray-300
|
||||
active:border-gray-200
|
||||
dark:border-gray-700
|
||||
dark:active:border-gray-600
|
||||
dark:hover:border-gray-600
|
||||
|
||||
text-gray-700
|
||||
hover:text-gray-900
|
||||
active:text-gray-600
|
||||
dark:text-gray-200
|
||||
dark:active:text-white
|
||||
dark:hover:text-white
|
||||
|
||||
`,
|
||||
primary:
|
||||
'bg-primary text-white shadow-sm border-primary-600 dark:border-primary-400 active:bg-primary-600 active:border-primary-700 hover:bg-primary-400 hover:border-primary-500',
|
||||
selected: `bg-gray-100 dark:bg-gray-500
|
||||
text-black hover:text-black active:text-black dark:hover:text-white dark:text-white
|
||||
`
|
||||
};
|
||||
|
||||
export type ButtonVariant = keyof typeof variants;
|
||||
export type ButtonSize = keyof typeof sizes;
|
||||
|
||||
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
variant?: ButtonVariant;
|
||||
size?: ButtonSize;
|
||||
loading?: boolean;
|
||||
icon?: React.ReactNode;
|
||||
noPadding?: boolean;
|
||||
noBorder?: boolean;
|
||||
pressEffect?: boolean;
|
||||
justifyLeft?: boolean;
|
||||
}
|
||||
|
||||
export const Button: React.FC<ButtonProps> = ({ loading, ...props }) => {
|
||||
return (
|
||||
<button
|
||||
{...props}
|
||||
className={clsx(
|
||||
'flex border rounded-md transition-colors duration-100 cursor-default',
|
||||
{ 'opacity-5': loading, '!p-1': props.noPadding },
|
||||
{ 'justify-center': !props.justifyLeft },
|
||||
sizes[props.size || 'default'],
|
||||
variants[props.variant || 'default'],
|
||||
{ 'active:translate-y-[1px]': props.pressEffect },
|
||||
{ 'border-0': props.noBorder },
|
||||
props.className
|
||||
)}
|
||||
>
|
||||
{props.children}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
1
packages/ui/primitive/index.ts
Normal file
1
packages/ui/primitive/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './Button';
|
||||
Reference in New Issue
Block a user