Compare commits

..

27 commits
0.1.0 ... main

Author SHA1 Message Date
rzmk
1feca4d720
build: update to magika 0.2.8 2024-03-06 11:53:10 -05:00
rzmk
ca183c07aa
build: update dependencies & format code 2024-03-04 21:03:10 -05:00
rzmk
4b2bd9ddae
chore: release v0.1.2 2024-02-26 22:46:46 -05:00
rzmk
80f32172a7
build: update dependencies 2024-02-26 22:44:49 -05:00
rzmk
7f99660309
ui: add tooltips & clear table button 2024-02-26 21:51:11 -05:00
rzmk
199abf5553
build: use 'release' instead for release-it shorthand due to habit 2024-02-21 19:08:00 -05:00
rzmk
95d7aecfbe
build: add 'rel' shorthand for release-it 2024-02-21 18:53:31 -05:00
rzmk
287767fa19
build: remove blank screen on installation 2024-02-21 18:52:43 -05:00
rzmk
0f8ce56de1
docs: fix typo & clarify disclaimer 2024-02-21 16:04:42 -05:00
rzmk
a30968fe7d
docs: clarify using tauri v2 beta 2024-02-21 13:01:54 -05:00
rzmk
688f8e9e5d
build: update tauri dependencies 2024-02-21 12:41:49 -05:00
rzmk
274b1a7e20
ci: update environment variable names & .gitignore 2024-02-20 13:27:52 -05:00
rzmk
5db40d07a5
feat: add updater 2024-02-20 13:09:51 -05:00
rzmk
9f463f658f
ci: include aarch64-apple-darwin target 2024-02-20 12:25:14 -05:00
rzmk
0d0abd7209
ci: fix YAML indentation 2024-02-20 12:19:15 -05:00
rzmk
9a9e756940
ci: add aarch64 macOS builds for releases 2024-02-20 12:18:46 -05:00
rzmk
875f11f4c9
chore: release v0.1.1 2024-02-20 11:46:52 -05:00
rzmk
8fd5b9a0c6
fix: enable access to broken link 2024-02-20 11:45:29 -05:00
rzmk
cf4eb123a5
build: clarify description & add repository link in src-tauri/Cargo.toml 2024-02-20 11:12:31 -05:00
rzmk
474cd1427c
build: use latest beta for now, expecting linux build error 2024-02-20 11:12:29 -05:00
rzmk
a44bbd541d
build: attempt conditional package use for linux, clarify text 2024-02-20 11:12:26 -05:00
rzmk
f4a60c75a4
ci: disable next telemetry 2024-02-20 11:11:43 -05:00
rzmk
3b7b2c5cab
ci: add v2 linux dependencies 2024-02-20 11:11:26 -05:00
rzmk
614f726062
feat: add dropdown for selecting column to search by 2024-02-20 11:09:08 -05:00
Mueez Khan
b814426d7d
ci: use different dependencies for Linux 2024-02-20 03:36:11 -05:00
rzmk
fce848c5ca
chore: remove unnecessary files in /public 2024-02-20 03:12:52 -05:00
rzmk
23c1c5c7f3
ci: update ubuntu CI settings 2024-02-20 03:08:23 -05:00
18 changed files with 1132 additions and 1106 deletions

View file

@ -5,9 +5,9 @@ on:
tags: tags:
- "*" - "*"
workflow_dispatch: workflow_dispatch:
env:
# This is the example from the readme. TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
# On each push to the `release` branch it will create or update a GitHub release, build your app, and upload the artifacts to the release. TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
jobs: jobs:
publish-tauri: publish-tauri:
@ -16,9 +16,17 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [macos-latest, ubuntu-20.04, windows-latest] settings:
- platform: "macos-latest"
args: "--target x86_64-apple-darwin"
- platform: "macos-latest"
args: "--target aarch64-apple-darwin"
- platform: "ubuntu-latest"
args: "--bundles appimage,deb,updater"
- platform: "windows-latest"
args: ""
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.settings.platform }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -31,15 +39,17 @@ jobs:
version: 8 version: 8
- name: install Rust stable - name: install Rust stable
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
with:
targets: aarch64-apple-darwin
- name: install dependencies (ubuntu only) - name: install dependencies (ubuntu only)
if: matrix.platform == 'ubuntu-20.04' if: matrix.settings.platform == 'ubuntu-latest'
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev javascriptcoregtk-4.1 libsoup-3.0 webkit2gtk-4.1 librsvg2-dev patchelf
- name: install frontend dependencies - name: install frontend dependencies
run: pnpm install run: pnpm install && pnpm exec next telemetry disable
- uses: tauri-apps/tauri-action@v0 - uses: tauri-apps/tauri-action@v0
env: env:
@ -47,6 +57,7 @@ jobs:
with: with:
tagName: v__VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version tagName: v__VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version
releaseName: "v__VERSION__" releaseName: "v__VERSION__"
releaseBody: "See the assets to download this version of fformat and install." releaseBody: "Learn about this release at https://github.com/rzmk/fformat/releases"
releaseDraft: true releaseDraft: true
prerelease: false prerelease: false
args: ${{ matrix.settings.args }}

View file

@ -19,8 +19,8 @@ A desktop app integrated with Google's deep learning model [Magika](https://gith
- **Powered by a deep learning model from Google's Magika team** - **Powered by a deep learning model from Google's Magika team**
- **Run offline locally:** Once you've installed fformat, you may run it without an internet connection. - **Run offline locally:** Once you've installed fformat, you may run it without an internet connection.
- **Interactive data table**: After magika detects potential file content types for all of your files, you may view more info about the results. - **Interactive data table**: After Magika detects potential file content types for all of your files, you may view more info about the results.
- **Organized metadata:** Learn about your file's path, potential file content types, and score representing a probability that the file content types is as expected. - **Organized metadata:** Learn about your file's path, potential file content types, and score representing a probability that the file content type is as expected.
- **Drag & drop files:** Choose between dropping one or more files simply dragging and dropping them into fformat. - **Drag & drop files:** Choose between dropping one or more files simply dragging and dropping them into fformat.
- **Light & dark themes:** Toggle your theme by clicking on the sun and moon icon. - **Light & dark themes:** Toggle your theme by clicking on the sun and moon icon.
- **Low file size:** fformat is only a few megabytes. - **Low file size:** fformat is only a few megabytes.
@ -28,7 +28,7 @@ A desktop app integrated with Google's deep learning model [Magika](https://gith
## 📚 Tech Stack ## 📚 Tech Stack
- [Magika](https://github.com/google/magika) - Deep learning model (using JavaScript browser API) from Google - [Magika](https://github.com/google/magika) - Deep learning model (using JavaScript browser API) from Google
- [Tauri v2](https://beta.tauri.app) - Desktop/Mobile app framework - [Tauri v2 Beta](https://beta.tauri.app) - Desktop/Mobile app framework
- [Next.js](https://nextjs.org/) - Web framework built with React - [Next.js](https://nextjs.org/) - Web framework built with React
- [TypeScript](https://www.typescriptlang.org/) - Programming language - [TypeScript](https://www.typescriptlang.org/) - Programming language
- [Rust](https://www.rust-lang.org/) - Programming language - [Rust](https://www.rust-lang.org/) - Programming language
@ -44,19 +44,19 @@ Download the relevant installer for your system from the [releases page](https:/
## 🤝 Contributing ## 🤝 Contributing
Contributions are welcome! If you have any ideas, fixes, or suggestions, please open an [issue](https://github.com/rzmk/fformat/issues) or submit a [pull request](https://github.com/rzmk/fformat/pulls). Contributions are welcome! If you have any ideas, fixes, or suggestions, please open an [issue](https://github.com/rzmk/fformat/issues) or submit a [pull request](https://github.com/rzmk/fformat/pulls). Issues and pull requests may or may not be completed/merged.
Some documentation that may be useful include: Some documentation that may be useful include:
- [Tauri v2 docs](https://beta.tauri.app) - [Tauri v2 Beta docs](https://beta.tauri.app)
- [shadcn/ui docs](https://ui.shadcn.com/docs) - [shadcn/ui docs](https://ui.shadcn.com/docs)
- [Magika repo](https://github.com/google/magika) - [Magika repo](https://github.com/google/magika)
## Disclaimer ## Disclaimer
This project is not affiliated with Google. fformat is not affiliated with Google, nor is fformat endorsed by Google.
By using this project you acknowledge the following: By using fformat you accept and acknowledge the following:
- fformat may display content (e.g., from Magika, links) that does not reflect the views of the project owner. - fformat may display content (e.g., from Magika, external links) that does not reflect the views of the author of fformat.
- fformat may display inaccurate information that seem factual but is not and other false/inaccurate information (e.g., inaccurate file content types from Magika's detection). - fformat may display inaccurate information that seem factual but is not such as inaccurate file content types from Magika's output (therefore denoting fformat as detecting "potential" file content types).

View file

@ -1,12 +1,13 @@
{ {
"name": "fformat", "name": "fformat",
"version": "0.1.0", "version": "0.1.2",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
"build": "next build", "build": "next build",
"start": "next start", "start": "next start",
"lint": "next lint" "lint": "next lint",
"release": "release-it"
}, },
"dependencies": { "dependencies": {
"@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dialog": "^1.0.5",
@ -14,14 +15,15 @@
"@radix-ui/react-scroll-area": "^1.0.5", "@radix-ui/react-scroll-area": "^1.0.5",
"@radix-ui/react-separator": "^1.0.3", "@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-slot": "^1.0.2",
"@tanstack/react-table": "^8.12.0", "@radix-ui/react-tooltip": "^1.0.7",
"@tanstack/react-table": "^8.13.2",
"@tauri-apps/api": "2.0.0-beta.1", "@tauri-apps/api": "2.0.0-beta.1",
"@tauri-apps/plugin-dialog": "2.0.0-beta.0", "@tauri-apps/plugin-dialog": "2.0.0-beta.0",
"@tauri-apps/plugin-fs": "github:tauri-apps/tauri-plugin-fs#v2", "@tauri-apps/plugin-fs": "github:tauri-apps/tauri-plugin-fs#v2",
"@tauri-apps/plugin-shell": "github:tauri-apps/tauri-plugin-shell#v2", "@tauri-apps/plugin-shell": "github:tauri-apps/tauri-plugin-shell#v2",
"class-variance-authority": "^0.7.0", "class-variance-authority": "^0.7.0",
"lucide-react": "^0.334.0", "lucide-react": "^0.334.0",
"magika": "^0.2.5", "magika": "^0.2.8",
"next": "14.1.0", "next": "14.1.0",
"next-themes": "^0.2.1", "next-themes": "^0.2.1",
"react": "^18.2.0", "react": "^18.2.0",
@ -32,12 +34,12 @@
"@release-it/bumper": "^6.0.1", "@release-it/bumper": "^6.0.1",
"@release-it/conventional-changelog": "^8.0.1", "@release-it/conventional-changelog": "^8.0.1",
"@tauri-apps/cli": "2.0.0-beta.1", "@tauri-apps/cli": "2.0.0-beta.1",
"@types/node": "^20.11.19", "@types/node": "^20.11.24",
"@types/react": "^18.2.56", "@types/react": "^18.2.63",
"@types/react-dom": "^18.2.19", "@types/react-dom": "^18.2.20",
"autoprefixer": "^10.4.17", "autoprefixer": "^10.4.18",
"clsx": "^2.1.0", "clsx": "^2.1.0",
"eslint": "^8.56.0", "eslint": "^8.57.0",
"eslint-config-next": "14.1.0", "eslint-config-next": "14.1.0",
"postcss": "^8.4.35", "postcss": "^8.4.35",
"release-it": "^17.1.1", "release-it": "^17.1.1",

916
pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 283 64"><path fill="black" d="M141 16c-11 0-19 7-19 18s9 18 20 18c7 0 13-3 16-7l-7-5c-2 3-6 4-9 4-5 0-9-3-10-7h28v-3c0-11-8-18-19-18zm-9 15c1-4 4-7 9-7s8 3 9 7h-18zm117-15c-11 0-19 7-19 18s9 18 20 18c6 0 12-3 16-7l-8-5c-2 3-5 4-8 4-5 0-9-3-11-7h28l1-3c0-11-8-18-19-18zm-10 15c2-4 5-7 10-7s8 3 9 7h-19zm-39 3c0 6 4 10 10 10 4 0 7-2 9-5l8 5c-3 5-9 8-17 8-11 0-19-7-19-18s8-18 19-18c8 0 14 3 17 8l-8 5c-2-3-5-5-9-5-6 0-10 4-10 10zm83-29v46h-9V5h9zM37 0l37 64H0L37 0zm92 5-27 48L74 5h10l18 30 17-30h10zm59 12v10l-3-1c-6 0-10 4-10 10v15h-9V17h9v9c0-5 6-9 13-9z"/></svg>

Before

Width:  |  Height:  |  Size: 629 B

View file

@ -2,3 +2,6 @@
# will have compiled files and executables # will have compiled files and executables
/target/ /target/
/gen/schemas /gen/schemas
# personal utility for cargo deny
deny.toml

863
src-tauri/Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,10 +1,9 @@
[package] [package]
name = "fformat" name = "fformat"
version = "0.1.0" version = "0.1.0"
description = "File format identifier." description = "Potential file content type identifier."
authors = ["rzmk"] authors = ["rzmk"]
license = "" repository = "https://github.com/rzmk/fformat"
repository = ""
edition = "2021" edition = "2021"
rust-version = "1.70" rust-version = "1.70"
@ -15,15 +14,15 @@ name = "app_lib"
crate-type = ["staticlib", "cdylib", "rlib"] crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies] [build-dependencies]
tauri-build = { version = "2.0.0-beta.2", features = [] } tauri-build = { version = "2.0.0-beta", features = [] }
[dependencies] [dependencies]
serde_json = "1.0" serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
tauri = { version = "2.0.0-beta.3", features = [] } tauri = { version = "2.0.0-beta", features = [] }
tauri-plugin-shell = { git = "https://github.com/tauri-apps/plugins-workspace.git", rev = "a31ef8e67e25d233cf463efb65428d7e0893e404" } tauri-plugin-shell = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
tauri-plugin-fs = { git = "https://github.com/tauri-apps/plugins-workspace.git", rev = "a31ef8e67e25d233cf463efb65428d7e0893e404" } tauri-plugin-fs = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
tauri-plugin-dialog = { git = "https://github.com/tauri-apps/plugins-workspace.git", rev = "a31ef8e67e25d233cf463efb65428d7e0893e404" } tauri-plugin-dialog = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
[profile.release] [profile.release]
panic = "abort" # Strip expensive panic clean-up logic panic = "abort" # Strip expensive panic clean-up logic

View file

@ -1,5 +1,3 @@
use tauri_plugin_shell;
#[cfg_attr(mobile, tauri::mobile_entry_point)] #[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() { pub fn run() {
tauri::Builder::default() tauri::Builder::default()

View file

@ -34,10 +34,18 @@
}, },
"plugins": { "plugins": {
"shell": { "shell": {
"open": "https://github\\.com/rzmk/fformat" "open": "^https://github\\.com/rzmk"
},
"updater": {
"active": true,
"endpoints": [
"https://github.com/rzmk/fformat/releases/latest/download/latest.json"
],
"dialog": true,
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDE5NkYxRUMxOTBFRkE1REQKUldUZHBlK1F3UjV2R1ZTUStEVXRBVE1NdnN6YUZIWFhJMUZuUzFwWTlCeDRCVzU1d1VsNEVkeWkK"
} }
}, },
"identifier": "com.fformat.dev", "identifier": "com.fformat.dev",
"productName": "fformat", "productName": "fformat",
"version": "0.1.0" "version": "0.1.2"
} }

View file

@ -11,14 +11,17 @@ export type Prediction = {
export const columns: ColumnDef<Prediction>[] = [ export const columns: ColumnDef<Prediction>[] = [
{ {
accessorKey: "path", accessorKey: "path",
id: "path",
header: "Path", header: "Path",
}, },
{ {
accessorKey: "label", accessorKey: "label",
id: "label",
header: "Label", header: "Label",
}, },
{ {
accessorKey: "score", accessorKey: "score",
id: "score",
header: "Score", header: "Score",
}, },
]; ];

View file

@ -1,7 +1,5 @@
"use client"; "use client";
import { Button } from "@/components/ui/button";
import { import {
ColumnDef, ColumnDef,
ColumnFiltersState, ColumnFiltersState,
@ -11,6 +9,7 @@ import {
getPaginationRowModel, getPaginationRowModel,
useReactTable, useReactTable,
} from "@tanstack/react-table"; } from "@tanstack/react-table";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { import {
Table, Table,
@ -20,19 +19,39 @@ import {
TableHeader, TableHeader,
TableRow, TableRow,
} from "@/components/ui/table"; } from "@/components/ui/table";
import { useState } from "react"; import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { DataTableViewOptions } from "@/components/DT/DataTableViewOptions"; import { DataTableViewOptions } from "@/components/DT/DataTableViewOptions";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { LucideScanSearch, Trash2 } from "lucide-react";
import { useState } from "react";
interface DataTableProps<TData, TValue> { interface DataTableProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[]; columns: ColumnDef<TData, TValue>[];
data: TData[]; data: TData[];
setData: React.Dispatch<React.SetStateAction<TData[]>>;
} }
export function DataTable<TData, TValue>({ export function DataTable<TData, TValue>({
columns, columns,
data, data,
setData,
}: DataTableProps<TData, TValue>) { }: DataTableProps<TData, TValue>) {
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]); const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
const [searchColumn, setSearchColumn] = useState("label");
const table = useReactTable({ const table = useReactTable({
data, data,
columns, columns,
@ -47,22 +66,85 @@ export function DataTable<TData, TValue>({
return ( return (
<div> <div>
{" "} <div className="flex justify-between gap-8 py-4">
<div className="flex items-center gap-8 py-4"> <div className="flex gap-2">
<Input <Input
placeholder="Search through labels..." placeholder={`Search column '${
columns.filter(
(column) => column.id === searchColumn
)[0].header
}'...`}
value={ value={
(table table
.getColumn("label") .getColumn(searchColumn)
?.getFilterValue() as string) ?? "" ?.getFilterValue() as string
} }
onChange={(event) => onChange={(event) =>
table table
.getColumn("label") .getColumn(searchColumn)
?.setFilterValue(event.target.value) ?.setFilterValue(event.target.value)
} }
className="max-w-sm" className="max-w-sm"
/> />
<DropdownMenu>
<DropdownMenuTrigger>
<TooltipProvider delayDuration={0}>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="outline" size="icon">
<LucideScanSearch
strokeWidth={1.25}
/>
<span className="sr-only">
Choose a column to search
</span>
</Button>
</TooltipTrigger>
<TooltipContent>
Choose a column to search
</TooltipContent>
</Tooltip>
</TooltipProvider>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuLabel>Search Column</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuRadioGroup
defaultValue={searchColumn}
value={searchColumn}
onValueChange={setSearchColumn}
>
{columns
.filter(
(column) => column.id && column.header
)
.map((column, index) => (
<DropdownMenuRadioItem
key={index}
value={column.id!}
>
{column.header!.toString()}
</DropdownMenuRadioItem>
))}
</DropdownMenuRadioGroup>
</DropdownMenuContent>
</DropdownMenu>
<TooltipProvider delayDuration={0}>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="destructive"
size="icon"
onClick={() => setData([])}
>
<Trash2 strokeWidth={1.25} />
<span className="sr-only">Clear table</span>
</Button>
</TooltipTrigger>
<TooltipContent>Clear table</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
<DataTableViewOptions table={table} /> <DataTableViewOptions table={table} />
</div> </div>
<div className="rounded-md border"> <div className="rounded-md border">
@ -96,7 +178,10 @@ export function DataTable<TData, TValue>({
} }
> >
{row.getVisibleCells().map((cell: any) => ( {row.getVisibleCells().map((cell: any) => (
<TableCell key={cell.id} className="text-left"> <TableCell
key={cell.id}
className="text-left"
>
{flexRender( {flexRender(
cell.column.columnDef.cell, cell.column.columnDef.cell,
cell.getContext() cell.getContext()

View file

@ -3,12 +3,10 @@
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Loader } from "@/components/ui/loader"; import { Loader } from "@/components/ui/loader";
//@ts-ignore
import { Magika } from "magika"; import { Magika } from "magika";
import { listen } from "@tauri-apps/api/event"; import { listen } from "@tauri-apps/api/event";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { readFile } from "@tauri-apps/plugin-fs"; import { readFile } from "@tauri-apps/plugin-fs";
//@ts-ignore
import { open } from "@tauri-apps/plugin-dialog"; import { open } from "@tauri-apps/plugin-dialog";
import { columns } from "@/components/DT/columns"; import { columns } from "@/components/DT/columns";
import { DataTable } from "@/components/DT/data-table"; import { DataTable } from "@/components/DT/data-table";
@ -19,9 +17,7 @@ const MagikaProcess = () => {
useEffect(() => { useEffect(() => {
if (loading) return; if (loading) return;
const unlisten = listen( listen("tauri://file-drop", async ({ payload }: any) => {
"tauri://file-drop",
async ({ payload }: any) => {
setLoading(true); setLoading(true);
const filepaths: string[] = payload.paths; const filepaths: string[] = payload.paths;
const filepredictions: any[] = []; const filepredictions: any[] = [];
@ -33,8 +29,7 @@ const MagikaProcess = () => {
setPredictions(filepredictions); setPredictions(filepredictions);
setLoading(false); setLoading(false);
} });
);
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, []); }, []);
@ -43,9 +38,13 @@ const MagikaProcess = () => {
const fileBytes = await readFile(filepath); const fileBytes = await readFile(filepath);
const magika = new Magika(); const magika = new Magika();
await magika.load({}); await magika.load({});
const prediction = await magika.identifyBytes(fileBytes); const result = await magika.identifyBytes(
prediction.path = filepath; new Uint16Array(fileBytes.buffer)
return prediction; );
return {
path: filepath,
result: result,
};
} catch (e) { } catch (e) {
console.error( console.error(
`Error while getting prediction for ${filepath}: ${e}` `Error while getting prediction for ${filepath}: ${e}`
@ -68,7 +67,6 @@ const MagikaProcess = () => {
} }
setPredictions(filePredictions); setPredictions(filePredictions);
} else if (selected === null) { } else if (selected === null) {
// user cancelled the selection
console.log("User cancelled selection"); console.log("User cancelled selection");
} else { } else {
// user selected a single file // user selected a single file
@ -90,7 +88,7 @@ const MagikaProcess = () => {
fformat fformat
</h2> </h2>
<p className="text-md w-fit border-b text-muted-foreground"> <p className="text-md w-fit border-b text-muted-foreground">
Examine file formats Identify potential file content types
</p> </p>
</div> </div>
<div className="mb-4"> <div className="mb-4">
@ -110,7 +108,11 @@ const MagikaProcess = () => {
</p> </p>
</div> </div>
{predictions.length > 0 && ( {predictions.length > 0 && (
<DataTable columns={columns} data={predictions} /> <DataTable
columns={columns}
data={predictions}
setData={setPredictions}
/>
)} )}
</div> </div>
</div> </div>

View file

@ -11,28 +11,47 @@ import {
} from "@/components/ui/dialog"; } from "@/components/ui/dialog";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Separator } from "@/components/ui/separator"; import { Separator } from "@/components/ui/separator";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { open } from "@tauri-apps/plugin-shell"; import { open } from "@tauri-apps/plugin-shell";
const Settings = () => { const Settings = () => {
return ( return (
<Dialog> <Dialog>
<DialogTrigger asChild> <DialogTrigger>
{/* <SettingsIcon strokeWidth={1.25} /> */} {/* <SettingsIcon strokeWidth={1.25} /> */}
<TooltipProvider delayDuration={0}>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="icon"> <Button variant="ghost" size="icon">
<Info strokeWidth={1.25} /> <Info strokeWidth={1.25} />
<span className="sr-only">About fformat</span>
</Button> </Button>
</TooltipTrigger>
<TooltipContent side="right">
About fformat
</TooltipContent>
</Tooltip>
</TooltipProvider>
</DialogTrigger> </DialogTrigger>
<DialogContent> <DialogContent>
<DialogHeader> <DialogHeader>
<DialogTitle>fformat</DialogTitle> <DialogTitle>fformat</DialogTitle>
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
Examine file formats on your local device. Identify potential file content types on your device.
</p> </p>
<Separator /> <Separator />
<ul className="list-disc text-sm text-muted-foreground ml-4 mt-2"> <ul className="list-disc text-sm text-muted-foreground ml-4 mt-2">
<li>Not all content types are supported.</li>
<li> <li>
Built with magika, Tauri, shadcn/ui, Next.js, Rust, Not all content types are supported, and inferences
may be inaccurate.
</li>
<li>
Built with Magika, Tauri, shadcn/ui, Next.js, Rust,
& TypeScript. & TypeScript.
</li> </li>
</ul> </ul>

View file

@ -3,13 +3,24 @@
import { Moon, Sun } from "lucide-react"; import { Moon, Sun } from "lucide-react";
import { useTheme } from "next-themes"; import { useTheme } from "next-themes";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
const ThemeSwitch = () => { const ThemeSwitch = () => {
const { theme, setTheme } = useTheme(); const { theme, setTheme } = useTheme();
return ( return (
<TooltipProvider delayDuration={0}>
<Tooltip>
<TooltipTrigger asChild>
<Button <Button
onClick={() => setTheme(theme === "light" ? "dark" : "light")} onClick={() =>
setTheme(theme === "light" ? "dark" : "light")
}
variant="ghost" variant="ghost"
size="icon" size="icon"
> >
@ -17,6 +28,10 @@ const ThemeSwitch = () => {
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" /> <Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span className="sr-only">Toggle theme</span> <span className="sr-only">Toggle theme</span>
</Button> </Button>
</TooltipTrigger>
<TooltipContent side="right">Toggle theme</TooltipContent>
</Tooltip>
</TooltipProvider>
); );
}; };

View file

@ -0,0 +1,30 @@
"use client"
import * as React from "react"
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
import { cn } from "@/lib/utils"
const TooltipProvider = TooltipPrimitive.Provider
const Tooltip = TooltipPrimitive.Root
const TooltipTrigger = TooltipPrimitive.Trigger
const TooltipContent = React.forwardRef<
React.ElementRef<typeof TooltipPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => (
<TooltipPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
))
TooltipContent.displayName = TooltipPrimitive.Content.displayName
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }