Franknoirot/pretty buttons (#550)
This commit is contained in:
@ -47,15 +47,52 @@
|
|||||||
@apply hover:bg-cool-20;
|
@apply hover:bg-cool-20;
|
||||||
}
|
}
|
||||||
|
|
||||||
.smallScrollbar::-webkit-scrollbar {
|
.toolbarButtons::-webkit-scrollbar {
|
||||||
@apply h-0.5;
|
@apply h-0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.smallScrollbar {
|
.toolbarButtons {
|
||||||
@apply overflow-x-auto;
|
@apply flex items-center overflow-x-auto;
|
||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toolbarButtons button {
|
||||||
|
@apply text-chalkboard-90 bg-chalkboard-10/50 border-chalkboard-50 whitespace-nowrap;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
@apply gap-1.5 p-0.5 pr-1;
|
||||||
|
@apply rounded-sm;
|
||||||
|
}
|
||||||
|
:global(.dark) .toolbarButtons button {
|
||||||
|
@apply text-chalkboard-30 bg-chalkboard-90/50 border-chalkboard-50;
|
||||||
|
}
|
||||||
|
.toolbarButtons button:hover {
|
||||||
|
@apply text-cool-90 bg-cool-10;
|
||||||
|
}
|
||||||
|
:global(.sketch) .toolbarButtons button:hover {
|
||||||
|
@apply text-fern-90 bg-fern-10;
|
||||||
|
}
|
||||||
|
.toolbarButtons button:disabled {
|
||||||
|
@apply text-chalkboard-70 bg-chalkboard-30;
|
||||||
|
}
|
||||||
|
.toolbarButtons button:disabled:hover {
|
||||||
|
@apply !bg-inherit !text-inherit cursor-not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.dark) .toolbarButtons button {
|
||||||
|
@apply text-chalkboard-20 border-chalkboard-50;
|
||||||
|
}
|
||||||
|
:global(.dark) .toolbarButtons button:hover {
|
||||||
|
@apply text-cool-10 border-chalkboard-50 bg-cool-90;
|
||||||
|
}
|
||||||
|
:global(.dark .sketch) .toolbarButtons button:hover {
|
||||||
|
@apply text-fern-10 border-chalkboard-50 bg-fern-90;
|
||||||
|
}
|
||||||
|
:global(.dark) .toolbarButtons button:disabled {
|
||||||
|
@apply text-chalkboard-40 bg-chalkboard-80;
|
||||||
|
}
|
||||||
|
|
||||||
:global(.dark) .popoverToggle {
|
:global(.dark) .popoverToggle {
|
||||||
@apply hover:bg-cool-90;
|
@apply hover:bg-cool-90;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useStore, toolTips, Selections } from './useStore'
|
import { useStore, toolTips, ToolTip } from './useStore'
|
||||||
import { extrudeSketch, sketchOnExtrudedFace } from './lang/modifyAst'
|
import { extrudeSketch, sketchOnExtrudedFace } from './lang/modifyAst'
|
||||||
import { getNodePathFromSourceRange } from './lang/queryAst'
|
import { getNodePathFromSourceRange } from './lang/queryAst'
|
||||||
import { HorzVert } from './components/Toolbar/HorzVert'
|
import { HorzVert } from './components/Toolbar/HorzVert'
|
||||||
@ -17,6 +17,30 @@ import { Popover, Transition } from '@headlessui/react'
|
|||||||
import styles from './Toolbar.module.css'
|
import styles from './Toolbar.module.css'
|
||||||
import { v4 as uuidv4 } from 'uuid'
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
import { useAppMode } from 'hooks/useAppMode'
|
import { useAppMode } from 'hooks/useAppMode'
|
||||||
|
import { ActionIcon } from 'components/ActionIcon'
|
||||||
|
|
||||||
|
export const sketchButtonClassnames = {
|
||||||
|
background:
|
||||||
|
'bg-chalkboard-100 group-hover:bg-chalkboard-90 hover:bg-chalkboard-90 dark:bg-fern-20 dark:group-hover:bg-fern-10 dark:hover:bg-fern-10 group-disabled:bg-chalkboard-50 dark:group-disabled:bg-chalkboard-60 group-hover:group-disabled:bg-chalkboard-50 dark:group-hover:group-disabled:bg-chalkboard-50',
|
||||||
|
icon: 'text-fern-20 h-auto group-hover:text-fern-10 hover:text-fern-10 dark:text-chalkboard-100 dark:group-hover:text-chalkboard-100 dark:hover:text-chalkboard-100 group-disabled:bg-chalkboard-60 hover:group-disabled:text-inherit',
|
||||||
|
}
|
||||||
|
|
||||||
|
const sketchFnLabels: Record<ToolTip | 'sketch_line' | 'move', string> = {
|
||||||
|
sketch_line: 'Line',
|
||||||
|
line: 'Line',
|
||||||
|
move: 'Move',
|
||||||
|
angledLine: 'Angled Line',
|
||||||
|
angledLineThatIntersects: 'Angled Line That Intersects',
|
||||||
|
angledLineOfXLength: 'Angled Line Of X Length',
|
||||||
|
angledLineOfYLength: 'Angled Line Of Y Length',
|
||||||
|
angledLineToX: 'Angled Line To X',
|
||||||
|
angledLineToY: 'Angled Line To Y',
|
||||||
|
lineTo: 'Line to Point',
|
||||||
|
xLine: 'Horizontal Line',
|
||||||
|
yLine: 'Vertical Line',
|
||||||
|
xLineTo: 'Horizontal Line to Point',
|
||||||
|
yLineTo: 'Vertical Line to Point',
|
||||||
|
}
|
||||||
|
|
||||||
export const Toolbar = () => {
|
export const Toolbar = () => {
|
||||||
const {
|
const {
|
||||||
@ -44,9 +68,9 @@ export const Toolbar = () => {
|
|||||||
console.log('guiMode', guiMode)
|
console.log('guiMode', guiMode)
|
||||||
}, [guiMode])
|
}, [guiMode])
|
||||||
|
|
||||||
function ToolbarButtons() {
|
function ToolbarButtons({ className }: React.HTMLAttributes<HTMLElement>) {
|
||||||
return (
|
return (
|
||||||
<span className={styles.smallScrollbar}>
|
<span className={styles.toolbarButtons + ' ' + className}>
|
||||||
{guiMode.mode === 'default' && (
|
{guiMode.mode === 'default' && (
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -55,7 +79,9 @@ export const Toolbar = () => {
|
|||||||
sketchMode: 'selectFace',
|
sketchMode: 'selectFace',
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
|
className="group"
|
||||||
>
|
>
|
||||||
|
<ActionIcon icon="sketch" className="!p-0.5" size="md" />
|
||||||
Start Sketch
|
Start Sketch
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
@ -74,8 +100,10 @@ export const Toolbar = () => {
|
|||||||
)
|
)
|
||||||
updateAst(modifiedAst, true)
|
updateAst(modifiedAst, true)
|
||||||
}}
|
}}
|
||||||
|
className="group"
|
||||||
>
|
>
|
||||||
SketchOnFace
|
<ActionIcon icon="sketch" className="!p-0.5" size="md" />
|
||||||
|
Sketch on Face
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{guiMode.mode === 'canEditSketch' && (
|
{guiMode.mode === 'canEditSketch' && (
|
||||||
@ -98,7 +126,9 @@ export const Toolbar = () => {
|
|||||||
position: guiMode.position,
|
position: guiMode.position,
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
|
className="group"
|
||||||
>
|
>
|
||||||
|
<ActionIcon icon="sketch" className="!p-0.5" size="md" />
|
||||||
Edit Sketch
|
Edit Sketch
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
@ -117,8 +147,10 @@ export const Toolbar = () => {
|
|||||||
)
|
)
|
||||||
updateAst(modifiedAst, true, { focusPath: pathToExtrudeArg })
|
updateAst(modifiedAst, true, { focusPath: pathToExtrudeArg })
|
||||||
}}
|
}}
|
||||||
|
className="group"
|
||||||
>
|
>
|
||||||
ExtrudeSketch
|
<ActionIcon icon="extrude" className="!p-0.5" size="md" />
|
||||||
|
Extrude
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -134,8 +166,10 @@ export const Toolbar = () => {
|
|||||||
)
|
)
|
||||||
updateAst(modifiedAst, true, { focusPath: pathToExtrudeArg })
|
updateAst(modifiedAst, true, { focusPath: pathToExtrudeArg })
|
||||||
}}
|
}}
|
||||||
|
className="group"
|
||||||
>
|
>
|
||||||
ExtrudeSketch (w/o pipe)
|
<ActionIcon icon="extrude" className="!p-0.5" size="md" />
|
||||||
|
Extrude as new
|
||||||
</button>
|
</button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@ -157,7 +191,15 @@ export const Toolbar = () => {
|
|||||||
setGuiMode({ mode: 'default' })
|
setGuiMode({ mode: 'default' })
|
||||||
executeAst()
|
executeAst()
|
||||||
}}
|
}}
|
||||||
|
className="group"
|
||||||
>
|
>
|
||||||
|
<ActionIcon
|
||||||
|
icon="exit"
|
||||||
|
className="!p-0.5"
|
||||||
|
bgClassName={sketchButtonClassnames.background}
|
||||||
|
iconClassName={sketchButtonClassnames.icon}
|
||||||
|
size="md"
|
||||||
|
/>
|
||||||
Exit sketch
|
Exit sketch
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
@ -201,9 +243,21 @@ export const Toolbar = () => {
|
|||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
|
className={
|
||||||
|
'group ' +
|
||||||
|
(guiMode.sketchMode === sketchFnName
|
||||||
|
? '!text-fern-70 !bg-fern-10 !dark:text-fern-20 !border-fern-50'
|
||||||
|
: '')
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{sketchFnName}
|
<ActionIcon
|
||||||
{guiMode.sketchMode === sketchFnName && '✅'}
|
icon={sketchFnName.includes('line') ? 'line' : 'move'}
|
||||||
|
className="!p-0.5"
|
||||||
|
bgClassName={sketchButtonClassnames.background}
|
||||||
|
iconClassName={sketchButtonClassnames.icon}
|
||||||
|
size="md"
|
||||||
|
/>
|
||||||
|
{sketchFnLabels[sketchFnName]}
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
@ -234,7 +288,7 @@ export const Toolbar = () => {
|
|||||||
<span className={styles.toolbarCap + ' ' + styles.label}>
|
<span className={styles.toolbarCap + ' ' + styles.label}>
|
||||||
{guiMode.mode === 'sketch' ? '2D' : '3D'}
|
{guiMode.mode === 'sketch' ? '2D' : '3D'}
|
||||||
</span>
|
</span>
|
||||||
<menu className="flex flex-1 gap-2 py-0.5 overflow-hidden whitespace-nowrap">
|
<menu className="flex-1 gap-2 py-0.5 overflow-hidden whitespace-nowrap">
|
||||||
<ToolbarButtons />
|
<ToolbarButtons />
|
||||||
</menu>
|
</menu>
|
||||||
<Popover.Button
|
<Popover.Button
|
||||||
@ -275,7 +329,7 @@ export const Toolbar = () => {
|
|||||||
</Popover.Button>
|
</Popover.Button>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<ToolbarButtons />
|
<ToolbarButtons className="flex-wrap" />
|
||||||
</section>
|
</section>
|
||||||
</Popover.Panel>
|
</Popover.Panel>
|
||||||
</Transition>
|
</Transition>
|
||||||
|
@ -4,6 +4,7 @@ import {
|
|||||||
} from '@fortawesome/free-solid-svg-icons'
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
import { IconDefinition as BrandIconDefinition } from '@fortawesome/free-brands-svg-icons'
|
import { IconDefinition as BrandIconDefinition } from '@fortawesome/free-brands-svg-icons'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
|
import { CustomIcon, CustomIconName } from './CustomIcon'
|
||||||
|
|
||||||
const iconSizes = {
|
const iconSizes = {
|
||||||
sm: 12,
|
sm: 12,
|
||||||
@ -13,7 +14,7 @@ const iconSizes = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ActionIconProps extends React.PropsWithChildren {
|
export interface ActionIconProps extends React.PropsWithChildren {
|
||||||
icon?: SolidIconDefinition | BrandIconDefinition
|
icon?: SolidIconDefinition | BrandIconDefinition | CustomIconName
|
||||||
className?: string
|
className?: string
|
||||||
bgClassName?: string
|
bgClassName?: string
|
||||||
iconClassName?: string
|
iconClassName?: string
|
||||||
@ -28,25 +29,39 @@ export const ActionIcon = ({
|
|||||||
size = 'md',
|
size = 'md',
|
||||||
children,
|
children,
|
||||||
}: ActionIconProps) => {
|
}: ActionIconProps) => {
|
||||||
|
// By default, we reverse the icon color and background color in dark mode
|
||||||
|
const computedIconClassName =
|
||||||
|
iconClassName ||
|
||||||
|
`text-liquid-20 h-auto group-hover:text-liquid-10 hover:text-liquid-10 dark:text-chalkboard-100 dark:group-hover:text-chalkboard-100 dark:hover:text-chalkboard-100 group-disabled:bg-chalkboard-50 dark:group-disabled:bg-chalkboard-60 group-hover:group-disabled:bg-chalkboard-50 dark:group-hover:group-disabled:bg-chalkboard-50`
|
||||||
|
|
||||||
|
const computedBgClassName =
|
||||||
|
bgClassName ||
|
||||||
|
`bg-chalkboard-100 group-hover:bg-chalkboard-90 hover:bg-chalkboard-90 dark:bg-liquid-20 dark:group-hover:bg-liquid-10 dark:hover:bg-liquid-10 group-disabled:bg-chalkboard-80 dark:group-disabled:bg-chalkboard-80`
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
`p-${
|
`p-${
|
||||||
size === 'xl' ? '2' : '1'
|
size === 'xl' ? '2' : '1'
|
||||||
} w-fit inline-grid place-content-center ${className} ` +
|
} w-fit inline-grid place-content-center ${className} ` +
|
||||||
(bgClassName ||
|
computedBgClassName
|
||||||
'bg-chalkboard-100 group-hover:bg-chalkboard-90 hover:bg-chalkboard-90 dark:bg-liquid-20 dark:group-hover:bg-liquid-10 dark:hover:bg-liquid-10')
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{children || (
|
{children ? (
|
||||||
|
children
|
||||||
|
) : typeof icon === 'string' ? (
|
||||||
|
<CustomIcon
|
||||||
|
name={icon}
|
||||||
|
width={iconSizes[size]}
|
||||||
|
height={iconSizes[size]}
|
||||||
|
className={computedIconClassName}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={icon}
|
icon={icon}
|
||||||
width={iconSizes[size]}
|
width={iconSizes[size]}
|
||||||
height={iconSizes[size]}
|
height={iconSizes[size]}
|
||||||
className={
|
className={computedIconClassName}
|
||||||
iconClassName ||
|
|
||||||
'text-liquid-20 h-auto group-hover:text-liquid-10 hover:text-liquid-10 dark:text-liquid-100 dark:group-hover:text-liquid-100 dark:hover:text-liquid-100'
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -29,7 +29,7 @@ export const AppHeader = ({
|
|||||||
return (
|
return (
|
||||||
<header
|
<header
|
||||||
className={
|
className={
|
||||||
(showToolbar ? 'grid ' : 'flex justify-between ') +
|
(showToolbar ? 'w-full grid ' : 'flex justify-between ') +
|
||||||
styles.header +
|
styles.header +
|
||||||
' overlaid-panes sticky top-0 z-20 py-1 px-5 bg-chalkboard-10/70 dark:bg-chalkboard-100/50 border-b dark:border-b-2 border-chalkboard-30 dark:border-chalkboard-90 items-center ' +
|
' overlaid-panes sticky top-0 z-20 py-1 px-5 bg-chalkboard-10/70 dark:bg-chalkboard-100/50 border-b dark:border-b-2 border-chalkboard-30 dark:border-chalkboard-90 items-center ' +
|
||||||
className
|
className
|
||||||
@ -38,7 +38,7 @@ export const AppHeader = ({
|
|||||||
<ProjectSidebarMenu renderAsLink={!enableMenu} project={project} />
|
<ProjectSidebarMenu renderAsLink={!enableMenu} project={project} />
|
||||||
{/* Toolbar if the context deems it */}
|
{/* Toolbar if the context deems it */}
|
||||||
{showToolbar && (
|
{showToolbar && (
|
||||||
<div className="max-w-4xl">
|
<div className="max-w-lg md:max-w-xl lg:max-w-2xl xl:max-w-4xl 2xl:max-w-5xl">
|
||||||
<Toolbar />
|
<Toolbar />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
161
src/components/CustomIcon.tsx
Normal file
161
src/components/CustomIcon.tsx
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
export type CustomIconName =
|
||||||
|
| 'equal'
|
||||||
|
| 'exit'
|
||||||
|
| 'extrude'
|
||||||
|
| 'horizontal'
|
||||||
|
| 'line'
|
||||||
|
| 'move'
|
||||||
|
| 'parallel'
|
||||||
|
| 'sketch'
|
||||||
|
| 'vertical'
|
||||||
|
|
||||||
|
export const CustomIcon = ({
|
||||||
|
name,
|
||||||
|
...props
|
||||||
|
}: {
|
||||||
|
name: CustomIconName
|
||||||
|
} & React.SVGProps<SVGSVGElement>) => {
|
||||||
|
switch (name) {
|
||||||
|
case 'equal':
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
{...props}
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M5 8.78V7H14.52V8.78H5ZM5 13.02V11.24H14.52V13.02H5Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
case 'exit':
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
{...props}
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M17 10L3 10M3 10L6.5 6.5M3 10L6.5 13.5"
|
||||||
|
stroke="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
case 'extrude':
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
{...props}
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M10 3L10.3536 3.35355L12.3536 5.35355L11.6465 6.06066L10.5 4.91421V11.5854C11.0826 11.7913 11.5 12.3469 11.5 13C11.5 13.8284 10.8284 14.5 10 14.5C9.17157 14.5 8.5 13.8284 8.5 13C8.5 12.3469 8.91741 11.7913 9.5 11.5854V4.91421L8.35356 6.06066L7.64645 5.35355L9.64645 3.35355L10 3ZM1.95887 12.3282L8 8.63644V9.80838L2.91773 12.9142L10 17.2423L17.0823 12.9142L12 9.80838V8.63644L18.0411 12.3282L19 12.9142L19 14.9683H18V13.5253L10.5 18.1087V19.9683H9.5V18.1087L2 13.5253V14.9683H1L1 12.9142L1.95887 12.3282Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
case 'horizontal':
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
{...props}
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M4 9.5H16V11.5H4V9.5Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
case 'line':
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
{...props}
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M15.5 6C16.3284 6 17 5.32843 17 4.5C17 3.67157 16.3284 3 15.5 3C14.6716 3 14 3.67157 14 4.5C14 4.73107 14.0522 4.94993 14.1456 5.14543L5.14543 14.1456C4.94993 14.0522 4.73107 14 4.5 14C3.67157 14 3 14.6716 3 15.5C3 16.3284 3.67157 17 4.5 17C5.32843 17 6 16.3284 6 15.5C6 15.2679 5.94729 15.0482 5.8532 14.852L14.852 5.8532C15.0482 5.94729 15.2679 6 15.5 6Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
case 'move':
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
{...props}
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M10 2.29289L10.3536 2.64645L12.3536 4.64645L11.6465 5.35355L10.5 4.20711V8V9.50001H12L15.7929 9.50001L14.6465 8.35356L15.3536 7.64645L17.3536 9.64645L17.7071 10L17.3536 10.3536L15.3536 12.3536L14.6465 11.6465L15.7929 10.5H12H10.5V12V15.7929L11.6465 14.6464L12.3536 15.3536L10.3536 17.3536L10 17.7071L9.64645 17.3536L7.64645 15.3536L8.35356 14.6464L9.50001 15.7929V12V10.5H8.00001H4.20712L5.35357 11.6465L4.64646 12.3536L2.64646 10.3536L2.29291 10L2.64646 9.64645L4.64646 7.64645L5.35357 8.35356L4.20712 9.50001H8.00001H9.50001V8V4.20711L8.35356 5.35355L7.64645 4.64645L9.64645 2.64645L10 2.29289Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
case 'parallel':
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
{...props}
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M8 16V4H6V16H8ZM14 16V4H12V16H14Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
case 'sketch':
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
{...props}
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M14.8037 13.4035L15.5509 14.1635L16.3682 16.8386L13.5521 16.1346L12.8186 15.3885L14.8037 13.4035ZM14.1025 12.6903L12.1175 14.6754L3.48609 5.89624C2.94588 5.34678 2.94963 4.46456 3.49448 3.91971C4.04591 3.36828 4.94112 3.37208 5.48786 3.92817L14.1025 12.6903ZM6.20094 3.22709L16.4357 13.6371L17.5003 17.1216L17.8412 18.2376L16.7091 17.9546L13.0364 17.0364L2.77301 6.59732C1.84793 5.6564 1.85434 4.14564 2.78737 3.2126C3.73167 2.2683 5.26468 2.27481 6.20094 3.22709Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
case 'vertical':
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
{...props}
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M11 4V16H9V4H11Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -26,7 +26,7 @@ const ProjectSidebarMenu = ({
|
|||||||
className="h-9 w-auto"
|
className="h-9 w-auto"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
className="text-sm text-chalkboard-110 dark:text-chalkboard-20 min-w-max"
|
className="text-sm text-chalkboard-110 dark:text-chalkboard-20 min-w-max truncate"
|
||||||
data-testid="project-sidebar-link-name"
|
data-testid="project-sidebar-link-name"
|
||||||
>
|
>
|
||||||
{project?.name ? project.name : 'KittyCAD Modeling App'}
|
{project?.name ? project.name : 'KittyCAD Modeling App'}
|
||||||
@ -35,15 +35,15 @@ const ProjectSidebarMenu = ({
|
|||||||
) : (
|
) : (
|
||||||
<Popover className="relative">
|
<Popover className="relative">
|
||||||
<Popover.Button
|
<Popover.Button
|
||||||
className="border-0 p-0.5 pr-2 flex items-center gap-4 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-energy-50"
|
className="h-9 max-h-min min-w-max border-0 p-0.5 pr-2 flex items-center gap-4 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-energy-50"
|
||||||
data-testid="project-sidebar-toggle"
|
data-testid="project-sidebar-toggle"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src="/kitt-8bit-winking.svg"
|
src="/kitt-8bit-winking.svg"
|
||||||
alt="KittyCAD App"
|
alt="KittyCAD App"
|
||||||
className="h-9 w-auto"
|
className="h-full w-auto"
|
||||||
/>
|
/>
|
||||||
<span className="text-sm text-chalkboard-110 dark:text-chalkboard-20 min-w-max">
|
<span className="text-sm text-chalkboard-110 dark:text-chalkboard-20 whitespace-nowrap hidden 2xl:block">
|
||||||
{isTauri() && project?.name ? project.name : 'KittyCAD Modeling App'}
|
{isTauri() && project?.name ? project.name : 'KittyCAD Modeling App'}
|
||||||
</span>
|
</span>
|
||||||
</Popover.Button>
|
</Popover.Button>
|
||||||
|
@ -12,6 +12,8 @@ import {
|
|||||||
getTransformInfos,
|
getTransformInfos,
|
||||||
} from '../../lang/std/sketchcombos'
|
} from '../../lang/std/sketchcombos'
|
||||||
import { updateCursors } from '../../lang/util'
|
import { updateCursors } from '../../lang/util'
|
||||||
|
import { ActionIcon } from 'components/ActionIcon'
|
||||||
|
import { sketchButtonClassnames } from 'Toolbar'
|
||||||
|
|
||||||
export const EqualAngle = () => {
|
export const EqualAngle = () => {
|
||||||
const { guiMode, selectionRanges, ast, programMemory, updateAst, setCursor } =
|
const { guiMode, selectionRanges, ast, programMemory, updateAst, setCursor } =
|
||||||
@ -87,9 +89,17 @@ export const EqualAngle = () => {
|
|||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
disabled={!enableEqual}
|
disabled={!enableEqual}
|
||||||
title="yo dawg"
|
title="Parallel (or equal angle)"
|
||||||
|
className="group"
|
||||||
>
|
>
|
||||||
parallel
|
<ActionIcon
|
||||||
|
icon="parallel"
|
||||||
|
className="!p-0.5"
|
||||||
|
bgClassName={sketchButtonClassnames.background}
|
||||||
|
iconClassName={sketchButtonClassnames.icon}
|
||||||
|
size="md"
|
||||||
|
/>
|
||||||
|
Parallel
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@ import {
|
|||||||
getTransformInfos,
|
getTransformInfos,
|
||||||
} from '../../lang/std/sketchcombos'
|
} from '../../lang/std/sketchcombos'
|
||||||
import { updateCursors } from '../../lang/util'
|
import { updateCursors } from '../../lang/util'
|
||||||
|
import { ActionIcon } from 'components/ActionIcon'
|
||||||
|
import { sketchButtonClassnames } from 'Toolbar'
|
||||||
|
|
||||||
export const EqualLength = () => {
|
export const EqualLength = () => {
|
||||||
const { guiMode, selectionRanges, ast, programMemory, updateAst, setCursor } =
|
const { guiMode, selectionRanges, ast, programMemory, updateAst, setCursor } =
|
||||||
@ -87,8 +89,16 @@ export const EqualLength = () => {
|
|||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
disabled={!enableEqual}
|
disabled={!enableEqual}
|
||||||
title="yo dawg"
|
className="group"
|
||||||
|
title="Equal Length"
|
||||||
>
|
>
|
||||||
|
<ActionIcon
|
||||||
|
icon="equal"
|
||||||
|
className="!p-0.5"
|
||||||
|
bgClassName={sketchButtonClassnames.background}
|
||||||
|
iconClassName={sketchButtonClassnames.icon}
|
||||||
|
size="md"
|
||||||
|
/>
|
||||||
Equal Length
|
Equal Length
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
|
@ -11,6 +11,8 @@ import {
|
|||||||
transformAstSketchLines,
|
transformAstSketchLines,
|
||||||
} from '../../lang/std/sketchcombos'
|
} from '../../lang/std/sketchcombos'
|
||||||
import { updateCursors } from '../../lang/util'
|
import { updateCursors } from '../../lang/util'
|
||||||
|
import { ActionIcon } from 'components/ActionIcon'
|
||||||
|
import { sketchButtonClassnames } from 'Toolbar'
|
||||||
|
|
||||||
export const HorzVert = ({
|
export const HorzVert = ({
|
||||||
horOrVert,
|
horOrVert,
|
||||||
@ -66,9 +68,17 @@ export const HorzVert = ({
|
|||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
disabled={!enableHorz}
|
disabled={!enableHorz}
|
||||||
title="yo dawg"
|
className="group"
|
||||||
|
title={horOrVert === 'horizontal' ? 'Horizontal' : 'Vertical'}
|
||||||
>
|
>
|
||||||
{horOrVert === 'horizontal' ? 'Horz' : 'Vert'}
|
<ActionIcon
|
||||||
|
icon={horOrVert === 'horizontal' ? 'horizontal' : 'vertical'}
|
||||||
|
className="!p-0.5"
|
||||||
|
bgClassName={sketchButtonClassnames.background}
|
||||||
|
iconClassName={sketchButtonClassnames.icon}
|
||||||
|
size="md"
|
||||||
|
/>
|
||||||
|
{horOrVert === 'horizontal' ? 'Horizontal' : 'Vertical'}
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -188,8 +188,9 @@ export const Intersect = () => {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
disabled={!enable}
|
disabled={!enable}
|
||||||
|
title="Set Perpendicular Distance"
|
||||||
>
|
>
|
||||||
perpendicularDistance
|
Set Perpendicular Distance
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ export const RemoveConstrainingValues = () => {
|
|||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
disabled={!enableHorz}
|
disabled={!enableHorz}
|
||||||
title="yo dawg"
|
title="Remove Constraining Values"
|
||||||
>
|
>
|
||||||
Remove Constraining Values
|
Remove Constraining Values
|
||||||
</button>
|
</button>
|
||||||
|
@ -22,11 +22,16 @@ import { updateCursors } from '../../lang/util'
|
|||||||
|
|
||||||
const getModalInfo = create(SetAngleLengthModal as any)
|
const getModalInfo = create(SetAngleLengthModal as any)
|
||||||
|
|
||||||
export const SetAbsDistance = ({
|
type ButtonType = 'xAbs' | 'yAbs' | 'snapToYAxis' | 'snapToXAxis'
|
||||||
buttonType,
|
|
||||||
}: {
|
const buttonLabels: Record<ButtonType, string> = {
|
||||||
buttonType: 'xAbs' | 'yAbs' | 'snapToYAxis' | 'snapToXAxis'
|
xAbs: 'Set distance from X Axis',
|
||||||
}) => {
|
yAbs: 'Set distance from Y Axis',
|
||||||
|
snapToYAxis: 'Snap To Y Axis',
|
||||||
|
snapToXAxis: 'Snap To X Axis',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SetAbsDistance = ({ buttonType }: { buttonType: ButtonType }) => {
|
||||||
const { guiMode, selectionRanges, ast, programMemory, updateAst, setCursor } =
|
const { guiMode, selectionRanges, ast, programMemory, updateAst, setCursor } =
|
||||||
useStore((s) => ({
|
useStore((s) => ({
|
||||||
guiMode: s.guiMode,
|
guiMode: s.guiMode,
|
||||||
@ -132,8 +137,9 @@ export const SetAbsDistance = ({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
disabled={!enableAngLen}
|
disabled={!enableAngLen}
|
||||||
|
title={buttonLabels[buttonType]}
|
||||||
>
|
>
|
||||||
{buttonType}
|
{buttonLabels[buttonType]}
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -147,8 +147,9 @@ export const SetAngleBetween = () => {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
disabled={!enable}
|
disabled={!enable}
|
||||||
|
title="Set Angle Between"
|
||||||
>
|
>
|
||||||
angleBetween
|
Set Angle Between
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -21,17 +21,28 @@ import { GetInfoModal } from '../SetHorVertDistanceModal'
|
|||||||
import { createLiteral, createVariableDeclaration } from '../../lang/modifyAst'
|
import { createLiteral, createVariableDeclaration } from '../../lang/modifyAst'
|
||||||
import { removeDoubleNegatives } from '../AvailableVarsHelpers'
|
import { removeDoubleNegatives } from '../AvailableVarsHelpers'
|
||||||
import { updateCursors } from '../../lang/util'
|
import { updateCursors } from '../../lang/util'
|
||||||
|
import { ActionIcon } from 'components/ActionIcon'
|
||||||
|
import { sketchButtonClassnames } from 'Toolbar'
|
||||||
|
|
||||||
const getModalInfo = create(GetInfoModal as any)
|
const getModalInfo = create(GetInfoModal as any)
|
||||||
|
|
||||||
export const SetHorzVertDistance = ({
|
type ButtonType =
|
||||||
buttonType,
|
|
||||||
}: {
|
|
||||||
buttonType:
|
|
||||||
| 'setHorzDistance'
|
| 'setHorzDistance'
|
||||||
| 'setVertDistance'
|
| 'setVertDistance'
|
||||||
| 'alignEndsHorizontally'
|
| 'alignEndsHorizontally'
|
||||||
| 'alignEndsVertically'
|
| 'alignEndsVertically'
|
||||||
|
|
||||||
|
const buttonLabels: Record<ButtonType, string> = {
|
||||||
|
setHorzDistance: 'Set Horizontal Distance',
|
||||||
|
setVertDistance: 'Set Vertical Distance',
|
||||||
|
alignEndsHorizontally: 'Align Ends Horizontally',
|
||||||
|
alignEndsVertically: 'Align Ends Vertically',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SetHorzVertDistance = ({
|
||||||
|
buttonType,
|
||||||
|
}: {
|
||||||
|
buttonType: ButtonType
|
||||||
}) => {
|
}) => {
|
||||||
const { guiMode, selectionRanges, ast, programMemory, updateAst, setCursor } =
|
const { guiMode, selectionRanges, ast, programMemory, updateAst, setCursor } =
|
||||||
useStore((s) => ({
|
useStore((s) => ({
|
||||||
@ -169,8 +180,9 @@ export const SetHorzVertDistance = ({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
disabled={!enable}
|
disabled={!enable}
|
||||||
|
title={buttonLabels[buttonType]}
|
||||||
>
|
>
|
||||||
{buttonType}
|
{buttonLabels[buttonType]}
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -23,10 +23,17 @@ import { updateCursors } from '../../lang/util'
|
|||||||
|
|
||||||
const getModalInfo = create(SetAngleLengthModal as any)
|
const getModalInfo = create(SetAngleLengthModal as any)
|
||||||
|
|
||||||
|
type ButtonType = 'setAngle' | 'setLength'
|
||||||
|
|
||||||
|
const buttonLabels: Record<ButtonType, string> = {
|
||||||
|
setAngle: 'Set Angle',
|
||||||
|
setLength: 'Set Length',
|
||||||
|
}
|
||||||
|
|
||||||
export const SetAngleLength = ({
|
export const SetAngleLength = ({
|
||||||
angleOrLength,
|
angleOrLength,
|
||||||
}: {
|
}: {
|
||||||
angleOrLength: 'setAngle' | 'setLength'
|
angleOrLength: ButtonType
|
||||||
}) => {
|
}) => {
|
||||||
const { guiMode, selectionRanges, ast, programMemory, updateAst, setCursor } =
|
const { guiMode, selectionRanges, ast, programMemory, updateAst, setCursor } =
|
||||||
useStore((s) => ({
|
useStore((s) => ({
|
||||||
@ -144,8 +151,9 @@ export const SetAngleLength = ({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
disabled={!enableAngLen}
|
disabled={!enableAngLen}
|
||||||
|
title={buttonLabels[angleOrLength]}
|
||||||
>
|
>
|
||||||
{angleOrLength}
|
{buttonLabels[angleOrLength]}
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
|
|||||||
<Popover className="relative">
|
<Popover className="relative">
|
||||||
{user?.image && !imageLoadFailed ? (
|
{user?.image && !imageLoadFailed ? (
|
||||||
<Popover.Button
|
<Popover.Button
|
||||||
className="border-0 rounded-full w-fit p-0 focus:outline-none group"
|
className="border-0 rounded-full w-fit min-w-max p-0 focus:outline-none group"
|
||||||
data-testid="user-sidebar-toggle"
|
data-testid="user-sidebar-toggle"
|
||||||
>
|
>
|
||||||
<div className="rounded-full border border-chalkboard-70/50 hover:border-liquid-50 group-focus:border-liquid-50 overflow-hidden">
|
<div className="rounded-full border border-chalkboard-70/50 hover:border-liquid-50 group-focus:border-liquid-50 overflow-hidden">
|
||||||
|
Reference in New Issue
Block a user