mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2026-02-20 07:37:26 -05:00
Migrate landing page to app dir (#1587)
* app dir yay * better docs route * fix icon sizing * mobile sidebars * detect webgl in useEffect * separate zxcvbn
This commit is contained in:
@@ -20,7 +20,7 @@ import {
|
||||
} from '@sd/interface';
|
||||
import { getSpacedropState } from '@sd/interface/hooks/useSpacedropState';
|
||||
|
||||
import '@sd/ui/style';
|
||||
import '@sd/ui/style/style.scss';
|
||||
|
||||
import * as commands from './commands';
|
||||
import { createUpdater } from './updater';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Preview } from '@storybook/react';
|
||||
|
||||
import '@sd/ui/style';
|
||||
import '@sd/ui/style.scss';
|
||||
|
||||
const preview: Preview = {
|
||||
parameters: {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import React, { Suspense } from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
|
||||
import '@sd/ui/style';
|
||||
import '@sd/ui/style/style.scss';
|
||||
import '~/patches';
|
||||
|
||||
import App from './App';
|
||||
|
||||
@@ -1,12 +1,29 @@
|
||||
import clsx from 'clsx';
|
||||
import { getPasswordStrength } from '@sd/client';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { type getPasswordStrength } from '@sd/client';
|
||||
|
||||
export interface PasswordMeterProps {
|
||||
password: string;
|
||||
}
|
||||
|
||||
export const PasswordMeter = (props: PasswordMeterProps) => {
|
||||
const { score, scoreText } = getPasswordStrength(props.password);
|
||||
const [getStrength, setGetStrength] = useState<typeof getPasswordStrength | undefined>();
|
||||
const { score, scoreText } = getStrength
|
||||
? getStrength(props.password)
|
||||
: { score: 0, scoreText: 'Loading...' };
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
|
||||
import('@sd/client').then(({ getPasswordStrength }) => {
|
||||
if (cancelled) return;
|
||||
setGetStrength(() => getPasswordStrength);
|
||||
});
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"private": true,
|
||||
"main": "index.tsx",
|
||||
"types": "index.tsx",
|
||||
"sideEffects": false,
|
||||
"scripts": {
|
||||
"lint": "eslint . --cache",
|
||||
"typecheck": "tsc -b"
|
||||
@@ -10,7 +11,7 @@
|
||||
"dependencies": {
|
||||
"@fontsource/inter": "^4.5.13",
|
||||
"@headlessui/react": "^1.7.3",
|
||||
"@icons-pack/react-simple-icons": "^7.2.0",
|
||||
"@icons-pack/react-simple-icons": "^9.1.0",
|
||||
"@phosphor-icons/react": "^2.0.10",
|
||||
"@radix-ui/react-progress": "^1.0.1",
|
||||
"@radix-ui/react-slider": "^1.1.0",
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"version": "1.0.0",
|
||||
"license": "GPL-3.0-only",
|
||||
"private": true,
|
||||
"sideEffects": false,
|
||||
"scripts": {
|
||||
"gen": "node ./scripts/generate.mjs"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
* To regenerate this file, run: pnpm assets gen
|
||||
*/
|
||||
|
||||
'use client';
|
||||
|
||||
import { ReactComponent as Academia } from './Academia.svg';
|
||||
import { ReactComponent as Apple } from './apple.svg';
|
||||
import { ReactComponent as Discord } from './Discord.svg';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "@sd/client",
|
||||
"private": true,
|
||||
"sideEffects": false,
|
||||
"main": "./src/index.ts",
|
||||
"types": "./src/index.ts",
|
||||
"scripts": {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"license": "GPL-3.0-only",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"sideEffects": false,
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./src/forms": "./src/forms/index.ts",
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
'use client';
|
||||
|
||||
import { cva, cx, VariantProps } from 'class-variance-authority';
|
||||
import clsx from 'clsx';
|
||||
import { ComponentProps, forwardRef } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
export interface ButtonBaseProps extends VariantProps<typeof styles> {}
|
||||
export interface ButtonBaseProps extends VariantProps<typeof buttonStyles> {}
|
||||
|
||||
export type ButtonProps = ButtonBaseProps &
|
||||
React.ButtonHTMLAttributes<HTMLButtonElement> & {
|
||||
@@ -22,7 +24,7 @@ type Button = {
|
||||
|
||||
const hasHref = (props: ButtonProps | LinkButtonProps): props is LinkButtonProps => 'href' in props;
|
||||
|
||||
export const styles = cva(
|
||||
export const buttonStyles = cva(
|
||||
[
|
||||
'cursor-default items-center rounded-md border outline-none transition-colors duration-100',
|
||||
'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-70',
|
||||
@@ -73,7 +75,7 @@ export const Button = forwardRef<
|
||||
HTMLButtonElement | HTMLAnchorElement,
|
||||
ButtonProps | LinkButtonProps
|
||||
>(({ className, ...props }, ref) => {
|
||||
className = cx(styles(props), className);
|
||||
className = cx(buttonStyles(props), className);
|
||||
return hasHref(props) ? (
|
||||
<a {...props} ref={ref as any} className={cx(className, 'inline-block no-underline')} />
|
||||
) : (
|
||||
@@ -88,7 +90,7 @@ export const ButtonLink = forwardRef<
|
||||
return (
|
||||
<Link
|
||||
ref={ref}
|
||||
className={styles({
|
||||
className={buttonStyles({
|
||||
size,
|
||||
variant,
|
||||
className: clsx(
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import { Check } from '@phosphor-icons/react';
|
||||
import * as Checkbox from '@radix-ui/react-checkbox';
|
||||
import { cva, VariantProps } from 'class-variance-authority';
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import { CaretRight, Check, Icon, IconProps } from '@phosphor-icons/react';
|
||||
import * as RadixCM from '@radix-ui/react-context-menu';
|
||||
import { cva, VariantProps } from 'class-variance-authority';
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import * as RDialog from '@radix-ui/react-dialog';
|
||||
import { animated, useTransition } from '@react-spring/web';
|
||||
import clsx from 'clsx';
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import { Menu, Transition } from '@headlessui/react';
|
||||
import { ReactComponent as CaretDown } from '@sd/assets/svgs/caret.svg';
|
||||
import { cva, VariantProps } from 'class-variance-authority';
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import * as RadixDM from '@radix-ui/react-dropdown-menu';
|
||||
import clsx from 'clsx';
|
||||
import React, {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import { Eye, EyeSlash, Icon, IconProps, MagnifyingGlass } from '@phosphor-icons/react';
|
||||
import { cva, VariantProps } from 'class-variance-authority';
|
||||
import clsx from 'clsx';
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import * as Radix from '@radix-ui/react-popover';
|
||||
import clsx from 'clsx';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import * as ProgressPrimitive from '@radix-ui/react-progress';
|
||||
import clsx from 'clsx';
|
||||
import { memo } from 'react';
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use client';
|
||||
|
||||
/* eslint-disable tailwindcss/migration-from-tailwind-2 */
|
||||
import * as RadioGroup from '@radix-ui/react-radio-group';
|
||||
import clsx from 'clsx';
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import { Check } from '@phosphor-icons/react';
|
||||
import * as RS from '@radix-ui/react-select';
|
||||
import { ReactComponent as ChevronDouble } from '@sd/assets/svgs/chevron-double.svg';
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import * as SliderPrimitive from '@radix-ui/react-slider';
|
||||
import clsx from 'clsx';
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import * as SwitchPrimitive from '@radix-ui/react-switch';
|
||||
import { cva, VariantProps } from 'class-variance-authority';
|
||||
import { forwardRef } from 'react';
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import * as TabsPrimitive from '@radix-ui/react-tabs';
|
||||
|
||||
import { tw } from './utils';
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import { CheckCircle, Icon, Info, Warning, WarningCircle, X } from '@phosphor-icons/react';
|
||||
import clsx from 'clsx';
|
||||
import { CSSProperties, ForwardedRef, forwardRef, ReactNode, useEffect, useState } from 'react';
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
||||
import clsx from 'clsx';
|
||||
import { PropsWithChildren, ReactNode } from 'react';
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
import { zxcvbn, zxcvbnOptions } from '@zxcvbn-ts/core';
|
||||
import zxcvbnCommonPackage from '@zxcvbn-ts/language-common';
|
||||
import zxcvbnEnPackage from '@zxcvbn-ts/language-en';
|
||||
import clsx from 'clsx';
|
||||
import { forwardRef, useEffect, useState } from 'react';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
@@ -29,29 +26,48 @@ export interface PasswordInputProps extends UseFormFieldProps, Root.InputProps {
|
||||
}
|
||||
|
||||
const PasswordStrengthMeter = (props: { password: string }) => {
|
||||
const [zxcvbn, setZxcvbn] = useState<typeof import('./zxcvbn') | undefined>();
|
||||
|
||||
const [strength, setStrength] = useState<{ label: string; score: number }>();
|
||||
const updateStrength = useDebouncedCallback(
|
||||
() => setStrength(props.password ? getPasswordStrength(props.password) : undefined),
|
||||
100
|
||||
);
|
||||
const updateStrength = useDebouncedCallback(() => {
|
||||
if (!zxcvbn) return;
|
||||
|
||||
setStrength(props.password ? getPasswordStrength(props.password, zxcvbn) : undefined);
|
||||
}, 100);
|
||||
|
||||
// TODO: Remove duplicate in @sd/client
|
||||
function getPasswordStrength(password: string): { label: string; score: number } {
|
||||
function getPasswordStrength(
|
||||
password: string,
|
||||
zxcvbn: typeof import('./zxcvbn')
|
||||
): { label: string; score: number } {
|
||||
const ratings = ['Poor', 'Weak', 'Good', 'Strong', 'Perfect'];
|
||||
|
||||
zxcvbnOptions.setOptions({
|
||||
zxcvbn.zxcvbnOptions.setOptions({
|
||||
dictionary: {
|
||||
...zxcvbnCommonPackage.dictionary,
|
||||
...zxcvbnEnPackage.dictionary
|
||||
...zxcvbn.languageCommon.dictionary,
|
||||
...zxcvbn.languageEn.dictionary
|
||||
},
|
||||
graphs: zxcvbnCommonPackage.adjacencyGraphs,
|
||||
translations: zxcvbnEnPackage.translations
|
||||
graphs: zxcvbn.languageCommon.adjacencyGraphs,
|
||||
translations: zxcvbn.languageEn.translations
|
||||
});
|
||||
|
||||
const result = zxcvbn(password);
|
||||
const result = zxcvbn.zxcvbn(password);
|
||||
return { label: ratings[result.score]!, score: result.score };
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
|
||||
import('./zxcvbn').then((zxcvbn) => {
|
||||
if (cancelled) return;
|
||||
setZxcvbn(zxcvbn);
|
||||
});
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => updateStrength(), [props.password, updateStrength]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use client';
|
||||
|
||||
export * from './Form';
|
||||
export * from './FormField';
|
||||
export * from './CheckBoxField';
|
||||
|
||||
3
packages/ui/src/forms/zxcvbn.ts
Normal file
3
packages/ui/src/forms/zxcvbn.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export { zxcvbn, zxcvbnOptions } from '@zxcvbn-ts/core';
|
||||
export { default as languageCommon } from '@zxcvbn-ts/language-common';
|
||||
export { default as languageEn } from '@zxcvbn-ts/language-en';
|
||||
BIN
pnpm-lock.yaml
generated
BIN
pnpm-lock.yaml
generated
Binary file not shown.
Reference in New Issue
Block a user