Skip to content

Commit

Permalink
improve a bit more with design and usablility
Browse files Browse the repository at this point in the history
  • Loading branch information
Stefan Werner committed Nov 11, 2023
1 parent 28056ef commit 8b8dc32
Show file tree
Hide file tree
Showing 19 changed files with 249 additions and 149 deletions.
6 changes: 3 additions & 3 deletions web/src/App.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React, { useState } from 'react'
import React from 'react'
import { QueryClient, QueryClientProvider } from 'react-query'
import './App.css'

import Fractal from './ui/Fractal'
import { Puzzle } from './ui/Puzzle'
import Fractal from './ui/viewer/Fractal'
import { Puzzle } from './ui/editor/Puzzle'
import { Editor } from './ui/editor/Editor'

import { useRoutes } from 'raviger'
Expand Down
97 changes: 97 additions & 0 deletions web/src/lib/convertToAntdTreeData.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import ReactMarkdown from 'react-markdown'
import React from 'react'
import { postProcessTitle } from './position'

export const generateExpandedKeys = (path) => {
const segments = path.split('-')
const keys = []

for (let i = 1; i <= segments.length; i++) {
keys.push(segments.slice(0, i).join('-'))
}

return keys
}
const customSort = (a, b) => {
if (a === '.text') return -1
if (b === '.text') return 1
if (a === '_text') return 1
if (b === '_text') return -1
return Number(a) - Number(b)
}
export const convertToAntdTreeData = (node, prefix = '') => {
const result = []

if (!node) return []
const sortedKeys = Object.keys(node).sort(customSort)
for (let key of sortedKeys) {
if (key === '.' || key === '_') continue
const childNode = node[key]
const currentKey = prefix ? `${prefix}-${key}` : key
const isObject = typeof childNode === 'object'

let title = key
if (key.includes('text')) {
title = (
<div
style={{
textAlign: 'justify',
textAlignLast: 'none',
background: '#fff2d4',
}}
>
{' '}
<ReactMarkdown>{postProcessTitle(node[key])}</ReactMarkdown>
</div>
)
}
if (isObject) {
title = postProcessTitle(childNode?.['.']) ?? ''
}

let treeNode = {
title: title,
key: currentKey,
icon: isObject ? key : key === 'text' ? '◬' : '▰',
}

// Check if the node has children (ignoring special keys like "." and "_")
if (
typeof childNode === 'object' &&
key !== '.' &&
key !== '_' &&
!key.includes('text')
) {
treeNode.children = convertToAntdTreeData(childNode, currentKey)
}

result.push(treeNode)
}

return result
}

export const nestTexts = (path, texts) => {
if (!texts) return {}
if (!path) return texts

const keys = path.split('/').filter(Boolean) // Split by '/' and filter out empty strings
let currentObject = {}

keys.reduce((obj, key, index) => {
if (index === keys.length - 1) {
// If we are at the last key in the path
obj[key] = Object.fromEntries(
Object.entries(texts).map(([key, value]) => [
['.', '_'].includes(key) ? key + 'text' : key,
['.', '_'].includes(key) ? value : { text: value },
]),
)
} else {
obj[key] = {} // Else create an empty object for the next level
}
return obj[key] // Return the nested object for the next iteration
}, currentObject)

return currentObject
}
2 changes: 1 addition & 1 deletion web/src/lib/useMuuriGrid.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useEffect } from 'react'
import Muuri from 'muuri'
import { idToSize, idToZIndex, positionToId } from '../ui/Puzzle'
import { idToSize, idToZIndex, positionToId } from '../ui/editor/Puzzle'

const useMuuriGrid = (gridRef, options, size, props) => {
useEffect(() => {
Expand Down
91 changes: 91 additions & 0 deletions web/src/ui/ControlContainer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import React, { useEffect, useRef } from 'react'
import Muuri from 'muuri'
import '../../muuri.css'

const areas = {
leftTriangle: {
vertices: [
{ x: 0, y: window.innerHeight }, // Bottom left
{ x: 0, y: 0 }, // Top left
{ x: window.innerWidth / 2, y: 0 }, // Middle top
],
},
rightTriangle: {
vertices: [
{ x: window.innerWidth, y: window.innerHeight }, // right left
{ x: window.innerWidth, y: 0 }, // Top right
{ x: window.innerWidth / 2, y: 0 }, // Middle top
],
},
}

function calculatePositionInArea(item, area) {
if (area.vertices) {
// Assuming area is a triangle
const [v1, v2, v3] = area.vertices

// Randomly choose a point inside the triangle
const r1 = Math.random()
const r2 = Math.random()
const sqrtR1 = Math.sqrt(r1)

const x =
(1 - sqrtR1) * v1.x + sqrtR1 * (1 - r2) * v2.x + sqrtR1 * r2 * v3.x
const y =
(1 - sqrtR1) * v1.y + sqrtR1 * (1 - r2) * v2.y + sqrtR1 * r2 * v3.y

return { x, y }
}
}

function determineAreaForItem(item, areas, index, totalItems) {
// Example: Alternate between left and right triangles
if (index % 2 === 0) {
return areas.leftTriangle
} else {
return areas.rightTriangle
}
}

function layout(grid) {
const items = grid.getItems()

items.forEach((item) => {
// Decide in which area the item should be
const area = determineAreaForItem(item, areas)

// Calculate position based on the area
const position = calculatePositionInArea(item, area)

// Set the item's left and top CSS properties
item.getElement().style.left = `${position.x}px`
item.getElement().style.top = `${position.y}px`
})

// Update the grid after positioning items
grid.refreshItems().layout()
}

const ControlContainer = ({ children }) => {
const gridRef = useRef(null)

useEffect(() => {
if (!gridRef.current) return
const grid = new Muuri(gridRef.current, {
dragEnabled: true,
rounding: true,
width: 1000,
layout,
})

return () => grid.destroy()
}, [gridRef])

return (
<div ref={gridRef} className="grid">
{children}
</div>
)
}

export { ControlContainer }
2 changes: 1 addition & 1 deletion web/src/ui/ShareModal.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react'
import React, { useState } from 'react'
import { Modal, Button, Input } from 'antd'
import { ShareAltOutlined, CopyOutlined } from '@ant-design/icons'
import { removeMultipleSlashes } from '../lib/nesting'
Expand Down
File renamed without changes.
39 changes: 21 additions & 18 deletions web/src/ui/editor/Controls.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState } from 'react'
import { Button, Menu, Popconfirm, Slider, Space } from 'antd'
import { Button, Menu, Popconfirm, Slider } from 'antd'
import { DeleteOutlined } from '@ant-design/icons'

const ControlBar = {
Expand Down Expand Up @@ -146,27 +146,30 @@ const UserInteractionMenu = ({ params, onDeleteAction }) => {
position: 'fixed',
left: 0,
top: '10vh',
height: '30vh',
overflowY: "scroll"
height: '30vh',
overflowY: 'scroll',
}}
>
<Menu mode="vertical" className=" red">
{(params?.actions ??[]).map((action, index) => [action, index]).reverse().map(([action, index]) => (
<Menu.Item key={index} className="user-action red">
{(params?.actions ?? [])
.map((action, index) => [action, index])
.reverse()
.map(([action, index]) => (
<Menu.Item key={index} className="user-action red">
{index}
<Popconfirm
title="Are you sure to delete this action?"
onConfirm={() => onDeleteAction(index)}
okText="Yes"
cancelText="No"
>
<Button type="link" style={{color: "#fff"}}>
<DeleteOutlined />
</Button>
</Popconfirm>
{action.source}{JSON.stringify(action.target)}
</Menu.Item>
))}
<Popconfirm
title="Are you sure to delete this action?"
onConfirm={() => onDeleteAction(index)}
okText="Yes"
cancelText="No"
>
<Button type="link" style={{ color: '#fff' }}>
<DeleteOutlined />
</Button>
</Popconfirm>
{action.source}{JSON.stringify(action.target)}
</Menu.Item>
))}
</Menu>
</div>
)
Expand Down
1 change: 0 additions & 1 deletion web/src/ui/editor/Editor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { ExperimentsView } from './ExperimentsView'
import { PuzzleView } from './PuzzleView'
import TextModal from './TextModal'
import MetaModal from './MetaModal'
var debounce = require('lodash.debounce')

let taskId = null
const setTaskId = (tI) => (taskId = tI)
Expand Down
3 changes: 1 addition & 2 deletions web/src/ui/editor/ExperimentsView.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import React from 'react'
import { Button } from 'antd'
import { navigate } from 'raviger'
import BibTeXViewer from '../BibtexViewer'
import BibTeXViewer from './BibtexViewer'

export function ExperimentsView(props) {
//console.log(props)
const [isGood, setIsGood] = React.useState({})
return (
<>
Expand Down
11 changes: 6 additions & 5 deletions web/src/ui/Puzzle.jsx → web/src/ui/editor/Puzzle.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React, { useEffect, useRef, useState } from 'react'
import Muuri from 'muuri'
import '../puzzle.css'
import { stringToColour } from '../lib/color'
import { postProcessTitle } from '../lib/position'
import useMuuriGrid from '../lib/useMuuriGrid'
import calculateFontSize from '../lib/FontSize'
import '../../puzzle.css'
import { stringToColour } from '../../lib/color'
import { postProcessTitle } from '../../lib/position'
import useMuuriGrid from '../../lib/useMuuriGrid'
import calculateFontSize from '../../lib/FontSize'

// Define the base length for the largest triangle
const BASE_LENGTH = window.innerHeight * 0.5 // Modify as needed
Expand Down Expand Up @@ -168,6 +168,7 @@ const MutableTriangle = ({
overflowWrap: 'break-word',
width: size,
transform: 'translateX(-25%)',
zIndex: 1000000000 - 1000 * nest,
}}
title={title} // Full title as a tooltip
onMouseDown={(e) => {
Expand Down
2 changes: 1 addition & 1 deletion web/src/ui/editor/PuzzleView.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState } from 'react'
import { Puzzle } from '../Puzzle'
import { Puzzle } from './Puzzle'
import PuzzleControls from './Controls'

export function PuzzleView(props) {
Expand Down
4 changes: 1 addition & 3 deletions web/src/ui/editor/TreeView.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import React, { useState } from 'react'
import { Tree } from 'antd'
import { convertToAntdTreeData } from '../Tooltips'
import { convertToAntdTreeData } from '../../lib/convertToAntdTreeData'

export function TreeView(props) {
const treeData = convertToAntdTreeData(props.state)
const [expandedKeys, setExpandedKeys] = useState([])
const [openedKeys, setOpenedKeys] = useState(null)
const onExpand = (expandedKeysValue) => {
console.log('onExpand', expandedKeysValue)
setExpandedKeys(expandedKeysValue)
Expand All @@ -21,7 +20,6 @@ export function TreeView(props) {
titleHeight={'10px'}
loadData={async (node) => {
console.log(node)
setOpenedKeys(node.key.replace(/-/g, '/').slice(0, -2))
}}
/>
)
Expand Down
2 changes: 1 addition & 1 deletion web/src/ui/editor/TriangleView.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react'
import Fractal from '../Fractal'
import Fractal from '../viewer/Fractal'

export function TriangleView(props) {
return <Fractal PRESET_DATA={props.state} />
Expand Down
8 changes: 4 additions & 4 deletions web/src/ui/Fractal.jsx → web/src/ui/viewer/Fractal.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import React, { useEffect, useRef, useState, useMemo, useCallback } from 'react'
import { useQuery } from 'react-query'
import Triangle from './Triangle'
import { mergeDeep, lookupDeep, shiftIn, slashIt } from '../lib/nesting'
import { parseHash } from '../lib/read_link_params'
import { mergeDeep, lookupDeep, shiftIn, slashIt } from '../../lib/nesting'
import { parseHash } from '../../lib/read_link_params'

import { TransformWrapper, TransformComponent } from 'react-zoom-pan-pinch'
import { go, beamDataTo } from '../lib/navigate'
import { go, beamDataTo } from '../../lib/navigate'

import { Tooltips } from './Tooltips'
import { MAX_LEVEL } from '../config/const'
import { MAX_LEVEL } from '../../config/const'
import { MobileControls } from './MobileControls'
import { MuuriComponent } from './MuuriComponent'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useEffect, useState } from 'react'
import ShareModal from './ShareModal'
import ShareModal from '../ShareModal'
import { Button, Input } from 'antd'
import { SearchOutlined } from '@ant-design/icons'
import { useNavigate } from 'raviger'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useEffect, useRef } from 'react'
import Muuri from 'muuri'
import '../muuri.css'
import '../../muuri.css'
import { Pin } from './Pin'

const MuuriComponent = ({ labels, setHiddenId }) => {
Expand Down
2 changes: 1 addition & 1 deletion web/src/ui/Pin.jsx → web/src/ui/viewer/Pin.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react'
import LeaderLine from 'leader-line'
import useLinkedElementsStore from '../lib/PinnedElements'
import useLinkedElementsStore from '../../lib/PinnedElements'

function findElementById(id) {
let currentId = id
Expand Down
Loading

0 comments on commit 8b8dc32

Please sign in to comment.