mirror of
https://github.com/sigmasternchen/tagify
synced 2025-03-14 22:58:55 +00:00
feat: begin of gui stuff, loading repository in gui works
This commit is contained in:
parent
7ed8d49f55
commit
05bf42c2e3
15 changed files with 189 additions and 18 deletions
|
@ -1,9 +1,14 @@
|
|||
import * as React from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import RepositoryProvider from "./components/RepositoryProvider";
|
||||
import Home from "./views/Home";
|
||||
|
||||
function render() {
|
||||
ReactDOM.render(
|
||||
<h2>Hello from React!</h2>, document.body
|
||||
<RepositoryProvider>
|
||||
<Home />
|
||||
</RepositoryProvider>,
|
||||
document.getElementById("root")
|
||||
);
|
||||
}
|
||||
|
||||
|
|
12
src/components/MediaList/index.tsx
Normal file
12
src/components/MediaList/index.tsx
Normal file
|
@ -0,0 +1,12 @@
|
|||
import React, {FunctionComponent} from "react";
|
||||
|
||||
export type MediaListProps = {
|
||||
}
|
||||
|
||||
const MediaList: FunctionComponent<MediaListProps> = () => {
|
||||
return (
|
||||
<div></div>
|
||||
)
|
||||
}
|
||||
|
||||
export default MediaList
|
42
src/components/RepositoryProvider/index.tsx
Normal file
42
src/components/RepositoryProvider/index.tsx
Normal file
|
@ -0,0 +1,42 @@
|
|||
import React, {FunctionComponent, useContext, useEffect, useState} from "react";
|
||||
import Repository from "../../repository";
|
||||
import {ipcRenderer} from 'electron';
|
||||
|
||||
const OPEN_REPOSITORY_MESSAGE_NAME = "MSG_OPEN_REPO"
|
||||
|
||||
const RepositoryContext = React.createContext<Repository|null>(null)
|
||||
|
||||
export const useRepository = () => useContext(RepositoryContext)
|
||||
|
||||
type RepositoryProviderProps = {
|
||||
}
|
||||
|
||||
const RepositoryProvider: FunctionComponent<RepositoryProviderProps> = ({children}) => {
|
||||
const [repository, setRepository] = useState<Repository|null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
const listener = (event: any, data: any) => {
|
||||
console.log(data)
|
||||
const _path = data as string
|
||||
if (_path) {
|
||||
setRepository(new Repository(_path))
|
||||
} else {
|
||||
setRepository(null)
|
||||
}
|
||||
}
|
||||
|
||||
ipcRenderer.on(OPEN_REPOSITORY_MESSAGE_NAME, listener)
|
||||
return () => {
|
||||
// cleanup
|
||||
ipcRenderer.removeListener(OPEN_REPOSITORY_MESSAGE_NAME, listener)
|
||||
}
|
||||
}, [setRepository])
|
||||
|
||||
return (
|
||||
<RepositoryContext.Provider value={repository}>
|
||||
{children}
|
||||
</RepositoryContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export default RepositoryProvider
|
37
src/components/Sidebar/index.tsx
Normal file
37
src/components/Sidebar/index.tsx
Normal file
|
@ -0,0 +1,37 @@
|
|||
import React, {FunctionComponent, useEffect, useState} from "react";
|
||||
import {useRepository} from "../RepositoryProvider";
|
||||
import {CountedTag} from "../../database/query";
|
||||
|
||||
export type SidebarProps = {
|
||||
}
|
||||
|
||||
const Sidebar: FunctionComponent<SidebarProps> = () => {
|
||||
const repository = useRepository()
|
||||
|
||||
const [tags, setTags] = useState<CountedTag[]>([])
|
||||
|
||||
useEffect(() => {
|
||||
console.log("sidebar use effect")
|
||||
|
||||
if (repository) {
|
||||
repository.get().then(d => {
|
||||
console.log(d)
|
||||
setTags(d.query().countedTags())
|
||||
}).catch(console.log)
|
||||
}
|
||||
}, [repository])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ul>
|
||||
{
|
||||
tags.map(t => (
|
||||
<li>{t.name} ({t.count})</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Sidebar
|
|
@ -1,5 +1,5 @@
|
|||
const KEY_DIRECTORIES = "directories"
|
||||
const KEY_FILES = "files"
|
||||
export const KEY_DIRECTORIES = "directories"
|
||||
export const KEY_FILES = "files"
|
||||
|
||||
const KEY_FILE_PATH = "path"
|
||||
const KEY_FILE_TAGS = "tags"
|
||||
export const KEY_FILE_PATH = "path"
|
||||
export const KEY_FILE_TAGS = "tags"
|
|
@ -1,4 +1,9 @@
|
|||
class Database {
|
||||
import {KEY_DIRECTORIES, KEY_FILES} from "./config-keys";
|
||||
import {Directory} from "./directory";
|
||||
import {MediaFile} from "./file";
|
||||
import {Query} from "./query";
|
||||
|
||||
export class Database {
|
||||
private directories: Directory[]
|
||||
private files: MediaFile[]
|
||||
|
||||
|
@ -70,4 +75,4 @@ class Database {
|
|||
|
||||
return obj
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
class Directory {
|
||||
export class Directory {
|
||||
private readonly path: string
|
||||
|
||||
constructor(path: string) {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
enum MediaFileType {
|
||||
export enum MediaFileType {
|
||||
unknown,
|
||||
video,
|
||||
image
|
||||
}
|
||||
|
||||
function FileTypeFromExtension(name: string): MediaFileType {
|
||||
export function FileTypeFromExtension(name: string): MediaFileType {
|
||||
while (name.indexOf(".") >= 0) {
|
||||
name = name.substring(name.indexOf(".") + 1)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
class MediaFile {
|
||||
import {FileTypeFromExtension, MediaFileType} from "./file-type";
|
||||
import {KEY_FILE_PATH, KEY_FILE_TAGS} from "./config-keys";
|
||||
|
||||
export class MediaFile {
|
||||
private readonly path: string
|
||||
private readonly type: MediaFileType
|
||||
private tags: string[]
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
type CountedTag = {
|
||||
import {MediaFile} from "./file";
|
||||
import {MediaFileType} from "./file-type";
|
||||
|
||||
export type CountedTag = {
|
||||
name: string,
|
||||
count: number
|
||||
}
|
||||
|
||||
|
||||
class Query {
|
||||
export class Query {
|
||||
private readonly files: MediaFile[]
|
||||
|
||||
public constructor(files: MediaFile[]) {
|
||||
|
|
|
@ -5,5 +5,7 @@
|
|||
<title>Tagify</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
39
src/index.ts
39
src/index.ts
|
@ -1,9 +1,11 @@
|
|||
import { app, BrowserWindow } from 'electron';
|
||||
import {app, BrowserWindow, dialog, Menu} from 'electron';
|
||||
// This allows TypeScript to pick up the magic constant that's auto-generated by Forge's Webpack
|
||||
// plugin that tells the Electron app where to look for the Webpack-bundled app code (depending on
|
||||
// whether you're running in development or production).
|
||||
declare const MAIN_WINDOW_WEBPACK_ENTRY: string;
|
||||
|
||||
export const OPEN_REPOSITORY_MESSAGE_NAME = "MSG_OPEN_REPO"
|
||||
|
||||
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
|
||||
if (require('electron-squirrel-startup')) { // eslint-disable-line global-require
|
||||
app.quit();
|
||||
|
@ -13,7 +15,11 @@ const createWindow = (): void => {
|
|||
// Create the browser window.
|
||||
const mainWindow = new BrowserWindow({
|
||||
height: 600,
|
||||
width: 800,
|
||||
width: 1300,
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false
|
||||
}
|
||||
});
|
||||
|
||||
// and load the index.html of the app.
|
||||
|
@ -21,6 +27,35 @@ const createWindow = (): void => {
|
|||
|
||||
// Open the DevTools.
|
||||
mainWindow.webContents.openDevTools();
|
||||
|
||||
const menu = Menu.buildFromTemplate([
|
||||
{
|
||||
label: 'File',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Open Repository',
|
||||
click: menuItem => {
|
||||
dialog.showOpenDialog({
|
||||
title: "Open Repository",
|
||||
properties: [
|
||||
"openDirectory",
|
||||
]
|
||||
}).then(result => {
|
||||
if (result.canceled || result.filePaths.length != 1) {
|
||||
return
|
||||
}
|
||||
mainWindow.webContents.send(OPEN_REPOSITORY_MESSAGE_NAME, result.filePaths[0])
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Exit',
|
||||
click: menuItem => app.quit()
|
||||
}
|
||||
]
|
||||
}
|
||||
])
|
||||
Menu.setApplicationMenu(menu);
|
||||
};
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import * as fsPromises from "fs/promises";
|
||||
import {Database} from "../database/database";
|
||||
import {FileTypeFromExtension, MediaFileType} from "../database/file-type";
|
||||
|
||||
const DB_FILE = ".tagdb.json"
|
||||
const DB_FILE = ".tagdb"
|
||||
|
||||
class Repository {
|
||||
private readonly path: string
|
||||
|
@ -57,4 +59,6 @@ class Repository {
|
|||
|
||||
return untagged.filter((v, i, s) => s.indexOf(v) == i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Repository
|
23
src/views/Home/index.tsx
Normal file
23
src/views/Home/index.tsx
Normal file
|
@ -0,0 +1,23 @@
|
|||
import React, {FunctionComponent, useState} from "react";
|
||||
import Sidebar from "../../components/Sidebar";
|
||||
import MediaList from "../../components/MediaList";
|
||||
import {MediaFile} from "../../database/file";
|
||||
|
||||
export type HomeProps = {
|
||||
}
|
||||
|
||||
const Home: FunctionComponent<HomeProps> = () => {
|
||||
|
||||
const [selected, setSelected] = useState<MediaFile|null>(null)
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Sidebar />
|
||||
{ !selected &&
|
||||
<MediaList />
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Home
|
|
@ -14,4 +14,5 @@ module.exports = {
|
|||
resolve: {
|
||||
extensions: ['.js', '.ts', '.jsx', '.tsx', '.css']
|
||||
},
|
||||
target: 'electron-renderer'
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue