Skip to content
Merged
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
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

[![npm version](https://img.shields.io/npm/v/@earthyscience/netcdf4-wasm.svg)](https://www.npmjs.com/package/@earthyscience/netcdf4-wasm)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/EarthyScience/netcdf4-wasm/blob/main/LICENSE)
[![NetCDF4](https://img.shields.io/badge/NetCDF4-Compatible-4B8BBE)](https://www.unidata.ucar.edu/software/netcdf/)
[![NetCDF4](https://img.shields.io/badge/NetCDF4-Compatible-008B8B)](https://www.unidata.ucar.edu/software/netcdf/)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.x-3178c6)](https://www.typescriptlang.org/)
[![WebAssembly](https://img.shields.io/badge/WebAssembly-654FF0)](https://webassembly.org/)
[![Emscripten](https://img.shields.io/badge/Emscripten-3.x-000000)](https://emscripten.org/)
[![Emscripten](https://img.shields.io/badge/Emscripten-4.0.23-0000)](https://emscripten.org/)
[![Jest](https://img.shields.io/badge/Jest-29.x-C21325)](https://jestjs.io/)
[![ts-jest](https://img.shields.io/badge/ts--jest-29.x-3178c6)](https://kulshekhar.github.io/ts-jest/)

Expand All @@ -24,6 +24,10 @@
- 🚀 High-performance WASM compilation
- 📝 Complete TypeScript type definitions


> [!TIP]
> Want to do more? Plot, visualize, and explore your data at [browzarr.io](https://browzarr.io/)

## Installation

```bash
Expand Down
1 change: 1 addition & 0 deletions docs/next-js/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,4 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts
*.wasm
172 changes: 160 additions & 12 deletions docs/next-js/app/globals.css
Original file line number Diff line number Diff line change
@@ -1,26 +1,174 @@
@import "tailwindcss";
@import "tw-animate-css";

:root {
--background: #ffffff;
--foreground: #171717;
--radius: 0.625rem;

--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);

--card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0);

--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);

--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);

--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);

--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);

--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);

--destructive: oklch(0.577 0.245 27.325);

--border: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);

--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);

--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
}

@media (prefers-color-scheme: dark) {
:root {
--background: rgb(29, 29, 29);
--foreground: oklch(0.985 0 0);

--card: oklch(0.205 0 0);
--card-foreground: oklch(0.985 0 0);

--popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0);

--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);

--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);

--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);

--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);

--destructive: oklch(0.704 0.191 22.216);

--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.556 0 0);

--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);

--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.556 0 0);
}
}

.dark {
--background: rgb(29, 29, 29);
--foreground: oklch(0.985 0 0);
--card: oklch(0.205 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.556 0 0);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.556 0 0);
}

@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
}

@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
@layer base {
* {
@apply border-border outline-ring/50;
}
}

body {
background: var(--background);
color: var(--foreground);
font-family: Arial, Helvetica, sans-serif;
}
body {
@apply bg-background text-foreground font-sans;
}
}
14 changes: 14 additions & 0 deletions docs/next-js/app/hooks/copy-wasm.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import fs from 'fs';
import path from 'path';

const src = 'node_modules/@earthyscience/netcdf4-wasm/dist';
const dest = 'public/';

fs.mkdirSync(dest, { recursive: true });

fs.readdirSync(src)
.filter(f => f.endsWith('.wasm'))
.forEach(f => {
fs.copyFileSync(path.join(src, f), path.join(dest, f));
console.log(`✓ ${f}`);
});
8 changes: 2 additions & 6 deletions docs/next-js/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Image from "next/image";
import LocalNetCDFMeta from "../components/loading/LocalNetCDFMeta";

export default function Home() {
return (
Expand All @@ -23,12 +24,7 @@ export default function Home() {
priority
/>
</div>

<div className="flex flex-col items-center gap-6 text-center">
<h1 className="max-w-full text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50">
Let&apos;s get started!
</h1>
</div>
<LocalNetCDFMeta />
</main>
</div>
);
Expand Down
22 changes: 22 additions & 0 deletions docs/next-js/components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "",
"css": "app/globals.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "lucide",
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"registries": {}
}
36 changes: 36 additions & 0 deletions docs/next-js/components/loading/BrowzarrCTA.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react';
import Link from 'next/link';
import { Button } from '@/components/ui/button';

interface BrowzarrCTAProps {
message?: string;
buttonText?: string;
className?: string;
}

export default function BrowzarrCTA({
message = "Reading is just the beginning. Explore your data!",
buttonText = "Try browzarr.io",
className = ""
}: BrowzarrCTAProps) {
return (
<div className={`flex flex-col items-center gap-3 p-4 ${className}`}>
<p className="text-center text-sm text-gray-600 dark:text-gray-400">
{message}
</p>
<Link
aria-label="browzarr.io"
href="https://browzarr.io/"
target="_blank"
rel="noopener noreferrer"
>
<Button
size="sm"
className="bg-gradient-to-tr from-pink-500 to-yellow-500 text-white shadow-lg hover:shadow-xl transition-shadow cursor-pointer"
>
{buttonText}
</Button>
</Link>
</div>
);
}
72 changes: 72 additions & 0 deletions docs/next-js/components/loading/LocalNetCDFMeta.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
'use client';

import React, { ChangeEvent, useState } from 'react';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { MetaNetCDFAccordion } from './MetaNetCDFAccordion';
import { NetCDF4 } from '@earthyscience/netcdf4-wasm';
import BrowzarrCTA from './BrowzarrCTA';
const LocalNetCDFMeta = () => {
const [variables, setVariables] = useState<Record<string, unknown> | null>(null);
const [attributes, setAttributes] = useState<Record<string, unknown> | null>(null);
const [metadata, setMetadata] = useState<Record<string, unknown>[] | null>(null);

const handleFileSelect = async (
event: ChangeEvent<HTMLInputElement>
) => {
const files = event.target.files;
if (!files || files.length === 0) return;

const file = files[0];

try {
const data = await NetCDF4.fromBlobLazy(file);

const [variables, attrs, metadata] = await Promise.all([
data.getVariables(),
data.getGlobalAttributes(),
data.getFullMetadata(),
]);

setVariables(variables);
setAttributes(attrs);
setMetadata(metadata);

} catch (error) {
console.error('Error loading NetCDF file:', error);
alert('Failed to load NetCDF file. Check console for details.');
}
};

return (
<div className="grid w-full max-w-sm items-center gap-3 p-4 py-0">
<Label
htmlFor="netcdf-file"
className="justify-self-center font-semibold"
>
NetCDF file
</Label>

<Input
id="netcdf-file"
type="file"
accept=".nc,.netcdf,.nc3,.nc4"
onChange={handleFileSelect}
className="cursor-pointer"
/>

{variables && attributes && metadata && (
<MetaNetCDFAccordion
variables={variables}
attributes={attributes}
metadata={metadata}
/>
)
}
<BrowzarrCTA />

</div>
);
};

export default LocalNetCDFMeta;
Loading