Skip to content

Commit

Permalink
Merge pull request #3 from segersniels/refactor/remix
Browse files Browse the repository at this point in the history
♻️ Rework to remix
  • Loading branch information
segersniels authored Aug 5, 2024
2 parents 4a56818 + 93b0a69 commit f24b87f
Show file tree
Hide file tree
Showing 48 changed files with 12,044 additions and 5,187 deletions.
84 changes: 84 additions & 0 deletions apps/web/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* This is intended to be a basic starting point for linting in your app.
* It relies on recommended configs out of the box for simplicity, but you can
* and should modify this configuration to best suit your team's needs.
*/

/** @type {import('eslint').Linter.Config} */
module.exports = {
root: true,
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
ecmaFeatures: {
jsx: true,
},
},
env: {
browser: true,
commonjs: true,
es6: true,
},
ignorePatterns: ["!**/.server", "!**/.client"],

// Base config
extends: ["eslint:recommended"],

overrides: [
// React
{
files: ["**/*.{js,jsx,ts,tsx}"],
plugins: ["react", "jsx-a11y"],
extends: [
"plugin:react/recommended",
"plugin:react/jsx-runtime",
"plugin:react-hooks/recommended",
"plugin:jsx-a11y/recommended",
],
settings: {
react: {
version: "detect",
},
formComponents: ["Form"],
linkComponents: [
{ name: "Link", linkAttribute: "to" },
{ name: "NavLink", linkAttribute: "to" },
],
"import/resolver": {
typescript: {},
},
},
},

// Typescript
{
files: ["**/*.{ts,tsx}"],
plugins: ["@typescript-eslint", "import"],
parser: "@typescript-eslint/parser",
settings: {
"import/internal-regex": "^~/",
"import/resolver": {
node: {
extensions: [".ts", ".tsx"],
},
typescript: {
alwaysTryTypes: true,
},
},
},
extends: [
"plugin:@typescript-eslint/recommended",
"plugin:import/recommended",
"plugin:import/typescript",
],
},

// Node
{
files: [".eslintrc.cjs"],
env: {
node: true,
},
},
],
};
6 changes: 0 additions & 6 deletions apps/web/.eslintrc.json

This file was deleted.

8 changes: 8 additions & 0 deletions apps/web/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
node_modules

/.cache
/build
.env
.dev.vars

.wrangler
39 changes: 21 additions & 18 deletions apps/web/src/helpers/generate.ts → apps/web/app/.server/ai.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import OpenAI from 'openai';

const FILES_TO_IGNORE = [
'package-lock.json',
'yarn.lock',
Expand Down Expand Up @@ -55,14 +57,11 @@ export function prepareDiff(diff: string, minify = false) {

export function generateSystemMessage(gitmojis: string) {
return `
You will be provided a git diff or code snippet and you are expected to provide a suitable commit message.
When reviewing the diff or code, focus on identifying the main purpose of the changes.
Are they fixing a bug, adding a new feature, improving performance or readability, or something else?
Use this information to craft a concise and detailed gitmoji commit message that clearly describes what the provided code or diff does.
You will be provided a git diff or code snippet and you are expected to provide a suitable gitmoji commit message.
Describe the change to the best of your capabilities in one short sentence. Don't go into too much detail.
If a user provides anything else than a diff or code snippet, just ignore their request and provide a fitting message that explains what they need to provide a diff or code snippet.
When reviewing a diff, pay attention to the changed filenames and extract the context of the changes.
This will help you create a more relevant and informative commit message.
Here are some examples of how you can interpret some changed filenames:
Expand All @@ -79,17 +78,21 @@ export function generateSystemMessage(gitmojis: string) {
Always start your commit message with a gitmoji followed by the message starting with a capital letter.
Never mention filenames or function names in the message.
Don't do this:
- :bug: Fix issue in calculateTotalPrice function
- :zap: Improve performance of calculateTopProducts function
- :lipstick: Refactor styling for calculateCartTotal function
- :memo: Update documentation for getProductById function
Do this:
- :bug: Fix issue with shopping cart checkout process
- :zap: Improve performance of search functionality
- :lipstick: Refactor styling for product details page
- :memo: Update documentation for API endpoints
`;
}

export async function createChatCompletion(
apiKey: string,
messages: OpenAI.ChatCompletionMessageParam[]
) {
const openai = new OpenAI({
apiKey,
});

const response = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages,
});

return response.choices[0].message;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use server';

import Gitmoji from 'types/Gitmoji';
import BackupList from 'resources/gitmojis.json';

Expand Down
58 changes: 58 additions & 0 deletions apps/web/app/components/style-select.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectTrigger,
SelectValue,
} from 'components/ui/select';
import Style from 'enums/Style';
import { cn } from 'lib/utils';

const STYLE_OPTIONS = [
{
display: 'Emoji',
value: Style.Emoji,
},
{
display: 'Code',
value: Style.Code,
},
];

interface Props {
className?: string;
style: Style;
setStyle: (style: Style) => void;
}

export default function StyleSelect(props: Props) {
const { className, style, setStyle } = props;

return (
<div>
<Select
onValueChange={(value: Style) => setStyle(value)}
value={style}
defaultValue={style}
>
<SelectTrigger className={cn('w-32', className)}>
<SelectValue placeholder="Select gitmoji style" />
</SelectTrigger>

<SelectContent>
<SelectGroup>
<SelectLabel>Gitmoji Style</SelectLabel>

{STYLE_OPTIONS.map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.display}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</div>
);
}
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use client';

import * as React from 'react';
import { CaretSortIcon, CheckIcon } from '@radix-ui/react-icons';
import * as SelectPrimitive from '@radix-ui/react-select';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use client';

import * as React from 'react';
import * as SeparatorPrimitive from '@radix-ui/react-separator';

Expand Down
File renamed without changes.
18 changes: 18 additions & 0 deletions apps/web/app/entry.client.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* By default, Remix will handle hydrating your app on the client for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/file-conventions/entry.client
*/

import { RemixBrowser } from "@remix-run/react";
import { startTransition, StrictMode } from "react";
import { hydrateRoot } from "react-dom/client";

startTransition(() => {
hydrateRoot(
document,
<StrictMode>
<RemixBrowser />
</StrictMode>
);
});
43 changes: 43 additions & 0 deletions apps/web/app/entry.server.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* By default, Remix will handle generating the HTTP Response for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/file-conventions/entry.server
*/

import type { AppLoadContext, EntryContext } from '@remix-run/cloudflare';
import { RemixServer } from '@remix-run/react';
import { isbot } from 'isbot';
import { renderToReadableStream } from 'react-dom/server';

export default async function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
// This is ignored so we can keep it in the template for visibility. Feel
// free to delete this parameter in your app if you're not using it!
// eslint-disable-next-line @typescript-eslint/no-unused-vars
loadContext: AppLoadContext
) {
const body = await renderToReadableStream(
<RemixServer context={remixContext} url={request.url} />,
{
signal: request.signal,
onError(error: unknown) {
// Log streaming rendering errors from inside the shell
console.error(error);
responseStatusCode = 500;
},
}
);

if (isbot(request.headers.get('user-agent') || '')) {
await body.allReady;
}

responseHeaders.set('Content-Type', 'text/html');
return new Response(body, {
headers: responseHeaders,
status: responseStatusCode,
});
}
File renamed without changes.
23 changes: 23 additions & 0 deletions apps/web/app/hooks/use-enter-submit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { type RefObject, useRef } from 'react';

export default function useEnterSubmit(): {
formRef: RefObject<HTMLFormElement>;
onKeyDown: (event: React.KeyboardEvent<HTMLTextAreaElement>) => void;
} {
const formRef = useRef<HTMLFormElement>(null);

const handleKeyDown = (
event: React.KeyboardEvent<HTMLTextAreaElement>
): void => {
if (
event.key === 'Enter' &&
!event.shiftKey &&
!event.nativeEvent.isComposing
) {
formRef.current?.requestSubmit();
event.preventDefault();
}
};

return { formRef, onKeyDown: handleKeyDown };
}
57 changes: 57 additions & 0 deletions apps/web/app/hooks/use-local-forage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import localForage from 'localforage';
import { useCallback, useEffect, useState } from 'react';

localForage.config({
name: 'genmoji',
});

export default function useLocalForage<T>(
key: string,
initialValue: T
): [T, (value: T) => void, boolean] {
const event = `event:${key}`;
const [isInitialized, setIsInitialized] = useState(false);
const [storedValue, setStoredValue] = useState(initialValue);

const retrieve = useCallback(async () => {
try {
const value: T | null = await localForage.getItem(key);
setStoredValue(value == null ? initialValue : value);
} catch (err) {
console.error(err);
}
}, [initialValue, setStoredValue, key]);

const store = useCallback(
async (value: T) => {
try {
setStoredValue(value);
await localForage.setItem(key, value);
} catch (err) {
console.error(err);
} finally {
window.dispatchEvent(new Event(event));
}
},
[key, event, setStoredValue]
);

useEffect(() => {
if (isInitialized) {
return;
}

retrieve();
setIsInitialized(true);
}, [isInitialized, retrieve]);

useEffect(() => {
window.addEventListener(event, retrieve);

return () => {
window.removeEventListener(event, retrieve);
};
}, [event, retrieve]);

return [storedValue, store, isInitialized];
}
Loading

0 comments on commit f24b87f

Please sign in to comment.