Skip to content

Commit

Permalink
Merge pull request #43 from Pkcarreno/feat/vim-motions
Browse files Browse the repository at this point in the history
Multiple features
  • Loading branch information
Pkcarreno authored Oct 12, 2024
2 parents ff5a530 + c1c9230 commit 12f62c0
Show file tree
Hide file tree
Showing 26 changed files with 381 additions and 179 deletions.
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,24 @@ It's:
>
> Although JSOD aims to provide a safe environment, there may be inappropriate or malicious behavior when executing third-party code.
## Motivation

I wanted to have a tool where I could create and run JS code with no extra friction, no text editors, no login screens, no opening the browser console. Plus, I wanted my code to not run on an external server and to be able to share my creations with others privately.

JSOD is a super flexible calculator if you already know JS. You can do data manipulation without having to start your development environment, great for testing logic as you create. Or you can even create a calculator tailored to your needs and share it with your friends or embed it in your web page as a demo.

## Limitations

For JavaScript execution, [QuickJS-NG](https://quickjs-ng.github.io/quickjs/) is used via [quickjs-emscripten](https://github.com/justjake/quickjs-emscripten). QuickJS-NG aims to be compatible with the latest ECMAScript specifications (for reference, [here you can see the progress of these features](https://quickjs-ng.github.io/quickjs/es_features)).

As for the APIs provided by the environment (browser/Node.js) they depend on the implementation of **quickjs-emscripten** in the project and is currently work in progress. Below is the list of priority APIs to be integrated:

- [ ] fetch
- [ ] timeout
- [ ] interval

Note: You can open an issue and suggest any other API you consider necessary.

## Folder Structure

Follow [Bulletproof-react project structure](https://github.com/alan2207/bulletproof-react/blob/master/docs/project-structure.md).
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@
"@radix-ui/react-progress": "^1.1.0",
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-switch": "^1.1.1",
"@radix-ui/react-tabs": "^1.1.1",
"@radix-ui/react-toggle": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.3",
"@replit/codemirror-vim": "^6.2.1",
"@uiw/codemirror-extensions-basic-setup": "^4.23.5",
"@uiw/codemirror-extensions-langs": "^4.23.5",
"@uiw/codemirror-themes": "^4.23.5",
Expand Down
51 changes: 51 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 27 additions & 0 deletions src/components/ui/switch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import * as SwitchPrimitives from '@radix-ui/react-switch';
import * as React from 'react';

import { cn } from '@/lib/utils';

const Switch = React.forwardRef<
React.ElementRef<typeof SwitchPrimitives.Root>,
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
>(({ className, ...props }, ref) => (
<SwitchPrimitives.Root
className={cn(
'focus-visible:ring-ring focus-visible:ring-offset-background data-[state=checked]:bg-primary data-[state=unchecked]:bg-input peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
className,
)}
{...props}
ref={ref}
>
<SwitchPrimitives.Thumb
className={cn(
'bg-background pointer-events-none block size-5 rounded-full shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0',
)}
/>
</SwitchPrimitives.Root>
));
Switch.displayName = SwitchPrimitives.Root.displayName;

export { Switch };
2 changes: 1 addition & 1 deletion src/components/ui/tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const TabsList = React.forwardRef<
<TabsPrimitive.List
ref={ref}
className={cn(
'bg-muted text-muted-foreground inline-flex h-10 items-center justify-center rounded-md p-1',
'bg-muted text-background inline-flex h-10 items-center justify-center rounded-md p-1',
className,
)}
{...props}
Expand Down
11 changes: 10 additions & 1 deletion src/features/editor/components/editor/cm-extensions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { esLint, javascript } from '@codemirror/lang-javascript';
import { linter, lintGutter } from '@codemirror/lint';
import { vim } from '@replit/codemirror-vim';
import { basicSetup } from '@uiw/codemirror-extensions-basic-setup';
import type { ReactCodeMirrorProps } from '@uiw/react-codemirror';
import { worker as globalsWorker } from 'globals';
Expand All @@ -25,7 +26,11 @@ const newLinter = async () => {
return new eslint.Linter();
};

export const getExtensions = async () => {
interface getExtensionsProps {
vimMode: boolean;
}

export const getExtensions = async (props: getExtensionsProps) => {
const extensions: ReactCodeMirrorProps['extensions'] = [
basicSetup({
foldGutter: false,
Expand All @@ -41,5 +46,9 @@ export const getExtensions = async () => {
linter(esLint(await newLinter(), EsLintConfig)),
];

if (props?.vimMode) {
extensions.unshift(vim());
}

return extensions;
};
10 changes: 7 additions & 3 deletions src/features/editor/components/editor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { debounce } from '@/lib/debounce';

import { useUntrustedMode } from '../../hooks/use-untrusted-mode';
import { useCodeStore } from '../../stores/editor';
import { useSettingsStore } from '../../stores/settings';
import { themeInit } from './theme';

const CodeMirror = lazy(() => import('@uiw/react-codemirror'));
Expand All @@ -17,6 +18,7 @@ const lightTheme = themeInit({ theme: 'light' });
export const CodemirrorEditor = () => {
const { themeMode } = useTheme();
const { code, setCode } = useCodeStore();
const { vimMode } = useSettingsStore();
const { isUntrustedMode, isUnedited, setUnedited } = useUntrustedMode();
const codeRef = useRef<string | null>(null);
const [extensions, setExtensions] = useState<
Expand All @@ -25,9 +27,11 @@ export const CodemirrorEditor = () => {

const getMemoExtensions = useMemo(async () => {
const lib = await import('./cm-extensions');
const res = await lib.getExtensions();
const res = await lib.getExtensions({
vimMode,
});
return res;
}, []);
}, [vimMode]);

const loadExtensions = async () => {
const ext = await getMemoExtensions;
Expand All @@ -36,7 +40,7 @@ export const CodemirrorEditor = () => {

useEffect(() => {
loadExtensions();
}, []);
}, [vimMode]);

codeRef.current = code;

Expand Down
21 changes: 9 additions & 12 deletions src/features/editor/components/output/log-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,7 @@ import React from 'react';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { CONSOLE_AVAILABLE_HANDLERS } from '@/features/editor/config/constants';
import type {
consoleOutput,
Loggable,
SystemError,
} from '@/features/editor/types';
import type { Log, Loggable, SystemError } from '@/features/editor/types';
import { cn } from '@/lib/utils';

import { FormatOutput } from './format-output';
Expand Down Expand Up @@ -56,7 +52,10 @@ const Container: React.FC<ContainerProps> = ({
...props
}) => {
return (
<div className={cn(containerVariants({ variant, className }))} {...props}>
<div
className={cn('py-0.5', containerVariants({ variant, className }))}
{...props}
>
{children}
</div>
);
Expand Down Expand Up @@ -115,7 +114,7 @@ const Value: React.FC<ValueProps> = ({ variant, value, repeats, duration }) => {
};

interface Props {
type: consoleOutput['type'];
type: Log['type'];
value: Loggable | SystemError;
repeats: number;
duration: number;
Expand All @@ -131,14 +130,12 @@ export const LogItem: React.FC<Props> = ({
}) => {
const isDetailsString = typeof details === 'string';

const consoleAvailableHandlersAsString: readonly consoleOutput['type'][] = [
...CONSOLE_AVAILABLE_HANDLERS,
'systemError',
];
const consoleAvailableHandlersAsString: readonly Log['type'][] =
CONSOLE_AVAILABLE_HANDLERS;
const isVariantTypeSupported =
!!consoleAvailableHandlersAsString.includes(type);

const variantType: consoleOutput['type'] | 'default' = isVariantTypeSupported
const variantType: Log['type'] | 'default' = isVariantTypeSupported
? type
: 'default';

Expand Down
88 changes: 0 additions & 88 deletions src/features/editor/components/output/log-renderer.tsx

This file was deleted.

Loading

0 comments on commit 12f62c0

Please sign in to comment.