-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #64 from complexdatacollective/feature/lucide-add-…
…node Feature: Use any lucide icon for the add node button
- Loading branch information
Showing
26 changed files
with
363 additions
and
244 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import '~/styles/themes/interview.css'; | ||
import { createUseDisableImportedStyles } from './useDisableImportedStyles'; | ||
|
||
const useDisableImportedStyles = createUseDisableImportedStyles(); | ||
|
||
export default function InterviewTheme() { | ||
useDisableImportedStyles(); | ||
return null; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { useEffect } from 'react'; | ||
|
||
// global list of all the StyleSheets that are touched in useDisableImportedStyles | ||
const switchableGlobalStyleSheets: StyleSheet[] = []; | ||
|
||
// just to clarify what createUseDisableImportedStyles() returns | ||
type useDisableImportedStyles = () => void; | ||
|
||
/** | ||
* Conditionally apply imported .css files | ||
* WARNING: This is pretty finicky. You must set this up exactly or there may be unintended consequences | ||
* | ||
* ## Conditions: | ||
* | ||
* 1. `createUseDisableImportedStyles` must called in global scope in the same tsx file as the imported css being targeted and the component to be lazy loaded | ||
* ```tsx | ||
* import React from 'react' | ||
* import { createUseDisableImportedStyles } from './useDisableImportedStyles' | ||
* import './global-styles.css' | ||
* const useDisableImportedStyles = createUseDisableImportedStyles() | ||
* export const CssComponent: React.FC<{}> = () => { | ||
* useDisableImportedStyles() | ||
* return null | ||
* } | ||
* export default CssComponent | ||
* ``` | ||
* | ||
* 2. A component using this hook *should* be lazy loaded: | ||
* ```tsx | ||
* LazyCssComponent = React.lazy(() => import('./cssComponent')) | ||
* ... | ||
* <React.Suspense fallback={<></>}> | ||
* {condition && <LazyCssComponent/>} | ||
* </React.Suspense> | ||
* ``` | ||
* - An exception to lazy loading might be using this in a single, normal, non-lazy component so styles are loaded on first render | ||
* - NOTE: the `InitialCssComponent` never needs to actually render, it just needs to be imported | ||
* - BUT: this will only work if there is **one single** .css file imported globally, otherwise, I don't know what would happen | ||
* ```tsx | ||
* import InitialCssComponent from './initialCssComponent' | ||
* LazyCssComponent = React.lazy(() => import('./cssComponent')) | ||
* ... | ||
* {false && <InitialCssComponent/>} | ||
* <React.Suspense fallback={<></>}> | ||
* {condition && <LazyCssComponent/>} | ||
* </React.Suspense> | ||
* ``` | ||
* | ||
* @param {boolean} immediatelyUnloadStyle | ||
* if true: immediately unloads the StyleSheet when the component is unmounted | ||
* if false: waits to unloads the StyleSheet until another instance of useDisableImportedStyles is called. This avoids a flash of unstyled content | ||
* | ||
*/ | ||
export const createUseDisableImportedStyles = ( | ||
immediatelyUnloadStyle = true, | ||
): useDisableImportedStyles => { | ||
let localStyleSheet: StyleSheet; | ||
return () => { | ||
useEffect(() => { | ||
// if there are no stylesheets, you did something wrong... | ||
if (document.styleSheets.length < 1) return; | ||
|
||
// set the localStyleSheet if this is the first time this instance of this useEffect is called | ||
if (localStyleSheet == null) { | ||
localStyleSheet = | ||
document.styleSheets[document.styleSheets.length - 1]!; | ||
switchableGlobalStyleSheets.push(localStyleSheet); | ||
} | ||
|
||
// if we are switching StyleSheets, disable all switchableGlobalStyleSheets | ||
if (!immediatelyUnloadStyle) { | ||
switchableGlobalStyleSheets.forEach( | ||
(styleSheet) => (styleSheet.disabled = true), | ||
); | ||
} | ||
|
||
// enable our StyleSheet! | ||
localStyleSheet.disabled = false; | ||
|
||
// if we are NOT switching StyleSheets, disable this StyleSheet when the component is unmounted | ||
if (immediatelyUnloadStyle) | ||
return () => { | ||
if (localStyleSheet != null) localStyleSheet.disabled = true; | ||
}; | ||
}); | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { type LucideProps, icons } from 'lucide-react'; | ||
|
||
type IconComponentName = keyof typeof icons; | ||
|
||
type IconProps = { | ||
name: string; // because this is coming from the CMS | ||
} & LucideProps; | ||
|
||
// 👮♀️ guard | ||
function isValidIconComponent( | ||
componentName: string, | ||
): componentName is IconComponentName { | ||
return componentName in icons; | ||
} | ||
|
||
// This is a workaround to issues with lucide-react/dynamicIconImports found at https://github.com/lucide-icons/lucide/issues/1576#issuecomment-2335019821 | ||
export default function DynamicLucideIcon({ name, ...props }: IconProps) { | ||
// we need to convert kebab-case to PascalCase because we formerly relied on | ||
// lucide-react/dynamicIconImports and the icon names are what are stored in the CMS. | ||
const kebabToPascal = (str: string) => | ||
str | ||
.split('-') | ||
.map((word) => word.charAt(0).toUpperCase() + word.slice(1)) | ||
.join(''); | ||
|
||
const componentName = kebabToPascal(name); | ||
|
||
// ensure what is in the CMS is a valid icon component | ||
if (!isValidIconComponent(componentName)) { | ||
return null; | ||
} | ||
|
||
// lucide-react/dynamicIconImports makes makes NextJS development server very slow | ||
// https://github.com/lucide-icons/lucide/issues/1576 | ||
const Icon = icons[componentName]; | ||
|
||
return <Icon {...props} />; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import React from 'react'; | ||
import { type Meta, type StoryFn } from '@storybook/react'; | ||
import ActionButton from '~/components/interview/ActionButton'; | ||
import { | ||
type NodeColor, | ||
NodeColors, | ||
type NodeIcon, | ||
NodeIcons, | ||
} from '~/schemas/protocol/codebook/entities'; | ||
|
||
export default { | ||
title: 'Interview/ActionButton', | ||
component: ActionButton, | ||
parameters: { | ||
forceTheme: 'interview', | ||
layout: 'centered', | ||
}, | ||
argTypes: { | ||
iconName: { | ||
control: { | ||
type: 'select', | ||
}, | ||
options: NodeIcons, | ||
}, | ||
color: { | ||
control: { | ||
type: 'select', | ||
}, | ||
options: NodeColors, | ||
}, | ||
onClick: { action: 'clicked' }, // Action logger for click events | ||
}, | ||
decorators: [ | ||
(Story) => ( | ||
<div className="bg-primary-background flex h-screen w-screen items-center justify-center"> | ||
<Story /> | ||
</div> | ||
), | ||
], | ||
} as Meta; | ||
|
||
const Template: StoryFn<{ | ||
iconName: NodeIcon; | ||
color: NodeColor; | ||
onClick: () => void; | ||
}> = (args) => <ActionButton {...args} />; | ||
|
||
export const Default = Template.bind({}); | ||
Default.args = { | ||
iconName: 'user-round', | ||
color: 'node-1', | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.