feat: render selected document
This commit is contained in:
parent
9ab224f70c
commit
acf93695d3
@ -18,3 +18,16 @@ func GetDocumentCollection() *DocumentCollection {
|
|||||||
func (collection *DocumentCollection) AddDocument(document Entity) {
|
func (collection *DocumentCollection) AddDocument(document Entity) {
|
||||||
collection.Documents = append(collection.Documents, document)
|
collection.Documents = append(collection.Documents, document)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (collection *DocumentCollection) GetDocumentById(id string) Entity {
|
||||||
|
var foundDocument Entity
|
||||||
|
|
||||||
|
for _, d := range collection.Documents {
|
||||||
|
if d.Id == id {
|
||||||
|
foundDocument = d
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return foundDocument
|
||||||
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'server-only'
|
import 'server-only'
|
||||||
import MainHead from '../components/MainHead'
|
import MainHead from '../components/MainHead'
|
||||||
|
import DocumentRenderer from '../components/workspace/DocumentRenderer'
|
||||||
import Navigation from '../components/workspace/Navigation'
|
import Navigation from '../components/workspace/Navigation'
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
@ -16,8 +17,8 @@ export default function Home() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="mx-auto px-4 sm:px-6 md:px-8">
|
<div className="mx-auto px-4 sm:px-6 md:px-8">
|
||||||
<div className="py-4">
|
<div className="py-4">
|
||||||
<div className="h-96 rounded-lg border-4 border-dashed border-gray-200">
|
<div className=" min-h-96 rounded-lg border-4 border-dashed border-gray-200">
|
||||||
{/* Add canvas */}
|
<DocumentRenderer />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
44
frontend/components/workspace/DocumentRenderer.tsx
Normal file
44
frontend/components/workspace/DocumentRenderer.tsx
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useEffect, useRef } from "react"
|
||||||
|
import { useProject } from "../../context/Project/provider"
|
||||||
|
|
||||||
|
|
||||||
|
const loadImage = (path: string): Promise<HTMLImageElement> => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const image = new Image()
|
||||||
|
image.src = path
|
||||||
|
image.onload = () => resolve(image)
|
||||||
|
image.onerror = (error) => reject(error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const DocumentRenderer = () => {
|
||||||
|
const { getSelectedDocument } = useProject()
|
||||||
|
const canvasRef = useRef<HTMLCanvasElement>(null)
|
||||||
|
|
||||||
|
const applyDocumentToCanvas = async (path: string) => {
|
||||||
|
const image = await loadImage(path)
|
||||||
|
|
||||||
|
const canvas = canvasRef.current
|
||||||
|
if (!canvas) return
|
||||||
|
canvas.width = image.naturalWidth
|
||||||
|
canvas.height = image.naturalHeight
|
||||||
|
|
||||||
|
const context = canvas.getContext('2d')
|
||||||
|
if (!context) return
|
||||||
|
context.drawImage(image, 10, 10, image.width, image.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const selectedDocument = getSelectedDocument()
|
||||||
|
const documentPath = selectedDocument?.path
|
||||||
|
if (documentPath) applyDocumentToCanvas(selectedDocument.path)
|
||||||
|
}, [getSelectedDocument])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<canvas ref={canvasRef}></canvas>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DocumentRenderer
|
@ -43,14 +43,20 @@ function classNames(...classes: any[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Sidebar() {
|
function Sidebar() {
|
||||||
const [selectedItemId, setSelectedItemId] = useState('')
|
|
||||||
const [selectedGroupId, setSelectedGroupId] = useState('')
|
const [selectedGroupId, setSelectedGroupId] = useState('')
|
||||||
const [isAddNewDocumentInputShowing, setIsAddNewDocumentInputShowing] = useState(false)
|
const [isAddNewDocumentInputShowing, setIsAddNewDocumentInputShowing] = useState(false)
|
||||||
const [isAddNewGroupInputShowing, setIsAddNewGroupInputShowing] = useState(false)
|
const [isAddNewGroupInputShowing, setIsAddNewGroupInputShowing] = useState(false)
|
||||||
const addDocumentTextInput = useRef<HTMLInputElement>(null)
|
const addDocumentTextInput = useRef<HTMLInputElement>(null)
|
||||||
const addGroupTextInput = useRef<HTMLInputElement>(null)
|
const addGroupTextInput = useRef<HTMLInputElement>(null)
|
||||||
|
|
||||||
const { documents, groups, requestAddDocument, requestAddDocumentGroup } = useProject()
|
const {
|
||||||
|
documents,
|
||||||
|
groups,
|
||||||
|
requestAddDocument,
|
||||||
|
requestAddDocumentGroup,
|
||||||
|
selectedDocumentId,
|
||||||
|
setSelectedDocumentId
|
||||||
|
} = useProject()
|
||||||
|
|
||||||
const navigation = getNavigationProps(documents, groups)
|
const navigation = getNavigationProps(documents, groups)
|
||||||
|
|
||||||
@ -75,7 +81,7 @@ function Sidebar() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onItemClickHandler = (itemId: string) => {
|
const onItemClickHandler = (itemId: string) => {
|
||||||
setSelectedItemId(itemId)
|
setSelectedDocumentId(itemId)
|
||||||
setSelectedGroupId(getParentGroupIdFromItemId(itemId))
|
setSelectedGroupId(getParentGroupIdFromItemId(itemId))
|
||||||
setIsAddNewDocumentInputShowing(false)
|
setIsAddNewDocumentInputShowing(false)
|
||||||
setIsAddNewGroupInputShowing(false)
|
setIsAddNewGroupInputShowing(false)
|
||||||
@ -96,12 +102,15 @@ function Sidebar() {
|
|||||||
const response = await requestAddDocument(groupId, documentName)
|
const response = await requestAddDocument(groupId, documentName)
|
||||||
if (!response.id) return
|
if (!response.id) return
|
||||||
|
|
||||||
setSelectedItemId(response.id)
|
|
||||||
|
setSelectedDocumentId(response.id)
|
||||||
|
|
||||||
|
|
||||||
setSelectedGroupId(groupId)
|
setSelectedGroupId(groupId)
|
||||||
setIsAddNewDocumentInputShowing(false)
|
setIsAddNewDocumentInputShowing(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onConfirmAddGroupClickHandler = async(e: React.MouseEvent) => {
|
const onConfirmAddGroupClickHandler = async (e: React.MouseEvent) => {
|
||||||
const groupName = addGroupTextInput.current?.value
|
const groupName = addGroupTextInput.current?.value
|
||||||
if (!groupName) return
|
if (!groupName) return
|
||||||
|
|
||||||
@ -132,7 +141,7 @@ function Sidebar() {
|
|||||||
>
|
>
|
||||||
<XMarkIcon className="h-4 w-5" aria-hidden="true" />
|
<XMarkIcon className="h-4 w-5" aria-hidden="true" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onConfirmAddGroupClickHandler}
|
onClick={onConfirmAddGroupClickHandler}
|
||||||
@ -219,7 +228,7 @@ function Sidebar() {
|
|||||||
role='button'
|
role='button'
|
||||||
onClick={() => onItemClickHandler(child.id)}
|
onClick={() => onItemClickHandler(child.id)}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
child.id === selectedItemId
|
child.id === selectedDocumentId
|
||||||
? 'bg-gray-900 text-white'
|
? 'bg-gray-900 text-white'
|
||||||
: 'text-gray-300 hover:bg-gray-700 hover:text-white',
|
: 'text-gray-300 hover:bg-gray-700 hover:text-white',
|
||||||
'group w-full flex items-center pr-2 py-2 text-left font-medium text-sm rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 p-2'
|
'group w-full flex items-center pr-2 py-2 text-left font-medium text-sm rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 p-2'
|
||||||
|
@ -14,6 +14,7 @@ type Props = { children: ReactNode, projectProps: ProjectProps }
|
|||||||
export function ProjectProvider({ children, projectProps }: Props) {
|
export function ProjectProvider({ children, projectProps }: Props) {
|
||||||
const [ documents, setDocuments ] = useState<ipc.Document[]>(projectProps.documents)
|
const [ documents, setDocuments ] = useState<ipc.Document[]>(projectProps.documents)
|
||||||
const [ groups, setGroups ] = useState<ipc.Group[]>(projectProps.groups)
|
const [ groups, setGroups ] = useState<ipc.Group[]>(projectProps.groups)
|
||||||
|
const [selectedDocumentId, setSelectedDocumentId] = useState<string>('')
|
||||||
|
|
||||||
const updateDocuments = async () => {
|
const updateDocuments = async () => {
|
||||||
GetDocuments().then(response => {
|
GetDocuments().then(response => {
|
||||||
@ -35,14 +36,19 @@ export function ProjectProvider({ children, projectProps }: Props) {
|
|||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getSelectedDocument = () => documents.find(d => d.id === selectedDocumentId)
|
||||||
|
|
||||||
if (!documents.length || !groups.length) updateDocuments()
|
if (!documents.length || !groups.length) updateDocuments()
|
||||||
|
|
||||||
const value = {
|
const value = {
|
||||||
id: '',
|
id: '',
|
||||||
documents,
|
documents,
|
||||||
groups,
|
groups,
|
||||||
|
getSelectedDocument,
|
||||||
requestAddDocument,
|
requestAddDocument,
|
||||||
requestAddDocumentGroup,
|
requestAddDocumentGroup,
|
||||||
|
selectedDocumentId,
|
||||||
|
setSelectedDocumentId,
|
||||||
}
|
}
|
||||||
|
|
||||||
return <ProjectContext.Provider value={value}>
|
return <ProjectContext.Provider value={value}>
|
||||||
|
@ -7,6 +7,9 @@ export type ProjectProps = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type ProjectContextType = {
|
export type ProjectContextType = {
|
||||||
|
getSelectedDocument: () => ipc.Document | undefined
|
||||||
requestAddDocument: (groupId: string, documentName: string) => Promise<ipc.Document>,
|
requestAddDocument: (groupId: string, documentName: string) => Promise<ipc.Document>,
|
||||||
requestAddDocumentGroup: (groupName: string) => Promise<ipc.Group>,
|
requestAddDocumentGroup: (groupName: string) => Promise<ipc.Group>,
|
||||||
|
selectedDocumentId: string,
|
||||||
|
setSelectedDocumentId: (id: string) => void,
|
||||||
} & ProjectProps
|
} & ProjectProps
|
37
main.go
37
main.go
@ -2,7 +2,10 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
app "textualize/core/App"
|
app "textualize/core/App"
|
||||||
document "textualize/core/Document"
|
document "textualize/core/Document"
|
||||||
@ -11,6 +14,7 @@ import (
|
|||||||
"github.com/wailsapp/wails/v2"
|
"github.com/wailsapp/wails/v2"
|
||||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||||
"github.com/wailsapp/wails/v2/pkg/options"
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/options/assetserver"
|
||||||
"github.com/wailsapp/wails/v2/pkg/options/mac"
|
"github.com/wailsapp/wails/v2/pkg/options/mac"
|
||||||
"github.com/wailsapp/wails/v2/pkg/options/windows"
|
"github.com/wailsapp/wails/v2/pkg/options/windows"
|
||||||
)
|
)
|
||||||
@ -18,6 +22,26 @@ import (
|
|||||||
//go:embed frontend/out frontend/out/_next/static
|
//go:embed frontend/out frontend/out/_next/static
|
||||||
var assets embed.FS
|
var assets embed.FS
|
||||||
|
|
||||||
|
type FileLoader struct {
|
||||||
|
http.Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
func ClientFileLoader() *FileLoader {
|
||||||
|
return &FileLoader{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *FileLoader) ServeHTTP(res http.ResponseWriter, req *http.Request) {
|
||||||
|
var err error
|
||||||
|
requestedFilename := req.URL.Path
|
||||||
|
fileData, err := os.ReadFile(requestedFilename)
|
||||||
|
if err != nil {
|
||||||
|
res.WriteHeader(http.StatusBadRequest)
|
||||||
|
res.Write([]byte(fmt.Sprintf("Could not load file %s", requestedFilename)))
|
||||||
|
}
|
||||||
|
|
||||||
|
res.Write(fileData)
|
||||||
|
}
|
||||||
|
|
||||||
//go:embed build/appicondark.png
|
//go:embed build/appicondark.png
|
||||||
var icon []byte
|
var icon []byte
|
||||||
|
|
||||||
@ -43,11 +67,14 @@ func main() {
|
|||||||
StartHidden: false,
|
StartHidden: false,
|
||||||
HideWindowOnClose: false,
|
HideWindowOnClose: false,
|
||||||
BackgroundColour: &options.RGBA{R: 255, G: 255, B: 255, A: 255},
|
BackgroundColour: &options.RGBA{R: 255, G: 255, B: 255, A: 255},
|
||||||
Assets: assets,
|
AssetServer: &assetserver.Options{
|
||||||
Menu: nil,
|
Assets: assets,
|
||||||
Logger: nil,
|
Handler: ClientFileLoader(),
|
||||||
LogLevel: logger.DEBUG,
|
},
|
||||||
OnStartup: app.Startup,
|
Menu: nil,
|
||||||
|
Logger: nil,
|
||||||
|
LogLevel: logger.DEBUG,
|
||||||
|
OnStartup: app.Startup,
|
||||||
// OnDomReady: app.domReady,
|
// OnDomReady: app.domReady,
|
||||||
// OnBeforeClose: app.beforeClose,
|
// OnBeforeClose: app.beforeClose,
|
||||||
// OnShutdown: app.shutdown,
|
// OnShutdown: app.shutdown,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user