Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: SQL Formatter #63

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ Here is the list of all utilities:
- [Number Base Changer](https://jam.dev/utilities/number-base-changer)
- [CSS Inliner for Email](https://jam.dev/utilities/css-inliner-for-email)
- [Regex Tester](https://jam.dev/utilities/regex-tester)
- [Image Resizer](https://jam.dev/utilities/image-resizer)
- [CSS Units Converter](https://jam.dev/utilities/css-units-converter)
- [SQL Formatter](https://jam.dev/utilities/sql-formatter)

### Built With

Expand All @@ -54,6 +57,7 @@ Here is the list of all utilities:
- [Papa Parse](https://www.papaparse.com/)
- [js-yaml](https://github.com/nodeca/js-yaml)
- [curlconverter](https://github.com/curlconverter/curlconverter)
- [sql-formatter](https://github.com/sql-formatter-org/sql-formatter)

## Getting Started

Expand All @@ -78,6 +82,14 @@ Navigate to the project directory:
cd jam-dev-utilities
```

For macOS users with ARM architecture (M series processors), it's crucial to install these dependencies using `brew` to ensure full compatibility with the `node-canvas` library. This step is essential to prevent potential failures during the `npm install` process.

If you don't have Homebrew installed, you can find it at [brew.sh](https://brew.sh/)

```bash
brew install pkg-config cairo pango libpng jpeg giflib librsvg pixman python-setuptools
```

Install the dependencies:

```bash
Expand Down
8 changes: 5 additions & 3 deletions components/ds/ComboboxComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ interface ComboboxProps {
data: { value: string; label: string }[];
onSelect(value: string): void;
defaultValue?: string;
disabled?: boolean;
}

export function Combobox(props: ComboboxProps) {
Expand All @@ -38,16 +39,17 @@ export function Combobox(props: ComboboxProps) {
role="combobox"
aria-expanded={open}
className="justify-between"
disabled={props.disabled}
>
{selectedItem ? selectedItem.label : "Select base..."}
{selectedItem ? selectedItem.label : "Select..."}
<CaretSortIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="p-0 h-auto">
<Command>
<CommandInput placeholder="Search base..." />
<CommandInput placeholder="Search..." />
<CommandList className="h-auto">
<CommandEmpty>Base not found.</CommandEmpty>
<CommandEmpty>Nothing to see here.</CommandEmpty>
<CommandGroup>
{props.data.map((item) => (
<CommandItem
Expand Down
133 changes: 133 additions & 0 deletions components/ds/ImageUploadComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
"use client";
import { DragEvent, useCallback, useMemo, useRef, useState } from "react";
import UploadIcon from "@/components/icons/UploadIcon";

type Status = "idle" | "loading" | "error" | "unsupported" | "hover";

const MAX_FILE_SIZE = 4 * 1024 * 1024;
interface ImageUploadProps {
onFileSelect: (file: File) => void;
maxFileSize?: number;
}

const ImageUploadComponent = ({
onFileSelect,
maxFileSize = MAX_FILE_SIZE,
}: ImageUploadProps) => {
const [status, setStatus] = useState<Status>("idle");
const inputRef = useRef<HTMLInputElement>(null);

const formattedMaxSize = useMemo((): string => {
const sizeInMB = maxFileSize / (1024 * 1024);
return Number.isInteger(sizeInMB)
? `${sizeInMB}MB`
: `${sizeInMB.toFixed(2)}MB`;
}, [maxFileSize]);

const handleDrop = useCallback(
(event: DragEvent<HTMLDivElement>) => {
event.preventDefault();

const file = event.dataTransfer.files[0];
if (!file || !file.type.startsWith("image/")) {
setStatus("unsupported");
return;
}

if (file.size > maxFileSize) {
setStatus("error");
return;
}

setStatus("loading");
onFileSelect(file);
setStatus("idle");
},
[onFileSelect, maxFileSize]
);

const handleDragOver = useCallback(
(event: React.DragEvent<HTMLDivElement>) => {
event.preventDefault();
setStatus("hover");
},
[]
);

const handleDragLeave = useCallback(() => {
setStatus("idle");
}, []);

const handleClick = () => {
inputRef.current?.click();
};

const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (file) {
if (!file.type.startsWith("image/")) {
setStatus("unsupported");
return;
}

if (file.size > maxFileSize) {
setStatus("error");
return;
}

setStatus("loading");
onFileSelect(file);
setStatus("idle");
}
};

return (
<div
onDrop={handleDrop}
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
onClick={handleClick}
className="flex flex-col border border-dashed border-border p-6 text-center text-muted-foreground rounded-lg min-h-40 items-center justify-center bg-muted cursor-pointer mb-2"
>
<input
ref={inputRef}
type="file"
accept="image/*"
className="hidden"
onChange={handleFileChange}
/>
<UploadIcon />
{statusComponents[status](formattedMaxSize)}
</div>
);
};

const StatusComponent = ({
title,
message,
}: {
title: string;
message?: string;
}) => (
<div>
<p>{title}</p>
<p>{message || "\u00A0"}</p>
</div>
);

const statusComponents: Record<Status, (maxSize: string) => JSX.Element> = {
idle: (maxSize) => (
<StatusComponent
title="Drag and drop your image here, or click to select"
message={`Max size ${maxSize}`}
/>
),
loading: () => <StatusComponent title="Loading..." />,
error: (maxSize) => (
<StatusComponent title="Image is too big!" message={`${maxSize} max`} />
),
unsupported: () => <StatusComponent title="Please provide a valid image" />,
hover: () => <StatusComponent title="Drop it like it's hot! 🔥" />,
};

export { ImageUploadComponent };
68 changes: 68 additions & 0 deletions components/seo/CssUnitsConverter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
export default function CssUnitsConverter() {
return (
<div className="content-wrapper">
<section>
<h2>CSS Units Converter by Jam.dev</h2>
<p>
Jam's free tool for converting CSS units. Whether you need to convert
from pixels (px) to rem, vw, or other units, this tool makes it easy
to switch between different CSS units with precision. It's designed
for developers and designers who need to ensure their web layouts are
consistent across various screen sizes and devices.
</p>
</section>

<section>
<h2>How to Use:</h2>
<ul>
<li>
Enter the value you want to convert in the "Input Value" field.
</li>
<li>Select the unit of the value from the "From Unit" dropdown.</li>
<li>
Choose the unit to which you want to convert from the "To Unit"
dropdown.
</li>
<li>
If converting to or from units like vw, vh, vmin, or vmax, specify
the container width in pixels.
</li>
<li>Click "Convert" to see the result.</li>
<li>
You can copy the converted value by clicking the "Copy" button.
</li>
</ul>
</section>

<section>
<h2>Why CSS Unit Conversions Matter</h2>
<p>
Converting CSS units is essential for creating responsive and
accessible web designs. Different units serve different purposes:
</p>
<ul>
<li>
<b>Pixels (px):</b> Ideal for fixed-size elements, but not always
suitable for responsive designs.
</li>
<li>
<b>Rems:</b> These relative units scale based on the root or parent
element, making it easier to create flexible and scalable designs.
</li>
<li>
<b>Viewport Units (vw, vh, vmin, vmax):</b> These units are based on
the size of the viewport, allowing for designs that adapt fluidly to
different screen sizes. They're particularly useful for setting
dimensions that should be a percentage of the viewport's width or
height.
</li>
</ul>
<p>
By using the right units, you can ensure your designs are both
visually consistent and adaptable, enhancing the user experience
across a wide range of devices.
</p>
</section>
</div>
);
}
Loading