Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(modals): add modal component #268

Merged
merged 7 commits into from
Sep 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,12 @@ export const Button: ParentComponent<
<div class="loading loading-spinner" />
</Show>

<span class="truncate" classList={{ 'flex-1': !local.icon }}>
<span
class="truncate rounded-none"
classList={{
'flex-1': !local.icon,
}}
>
{props.icon || props.children}
</span>
</button>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Collapse.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const Collapse: ParentComponent<Props> = (props) => {
<div
class={twMerge(
getCollapseClassName(),
'collapse collapse-arrow select-none overflow-visible border-secondary bg-base-200 drop-shadow-md',
'collapse collapse-arrow select-none overflow-visible border-secondary bg-base-200 shadow-md',
)}
>
<div
Expand Down
62 changes: 22 additions & 40 deletions src/components/ConnectionsSettingsModal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createForm } from '@felte/solid'
import { validator } from '@felte/validator-zod'
import { IconX } from '@tabler/icons-solidjs'
import { IconNetwork, IconX } from '@tabler/icons-solidjs'
import type {
DragEventHandler,
Draggable,
Expand All @@ -18,12 +18,11 @@ import {
import { uniq } from 'lodash'
import { Component, For, Index, Show, createSignal } from 'solid-js'
import { z } from 'zod'
import { Button, ConfigTitle } from '~/components'
import { Button, ConfigTitle, Modal } from '~/components'
import {
CONNECTIONS_TABLE_ACCESSOR_KEY,
CONNECTIONS_TABLE_INITIAL_COLUMN_ORDER,
CONNECTIONS_TABLE_INITIAL_COLUMN_VISIBILITY,
MODAL,
TAILWINDCSS_SIZE,
} from '~/constants'
import { useI18n } from '~/i18n'
Expand Down Expand Up @@ -107,13 +106,14 @@ const TagClientSourceIPWithNameForm: Component = () => {
}

export const ConnectionsSettingsModal = (props: {
ref?: (el: HTMLDialogElement) => void
order: ConnectionsTableColumnOrder
visible: ConnectionsTableColumnVisibility
onOrderChange: (value: ConnectionsTableColumnOrder) => void
onVisibleChange: (value: ConnectionsTableColumnVisibility) => void
}) => {
const modalID = MODAL.CONNECTIONS_SETTINGS
const [t] = useI18n()

const [activeKey, setActiveKey] =
createSignal<CONNECTIONS_TABLE_ACCESSOR_KEY | null>(null)

Expand Down Expand Up @@ -179,25 +179,23 @@ export const ConnectionsSettingsModal = (props: {
}

return (
<dialog id={modalID} class="modal modal-bottom sm:modal-middle">
<div
class="modal-box flex flex-col gap-4"
onContextMenu={(e) => e.preventDefault()}
>
<div class="sticky top-0 z-50 flex items-center justify-end">
<Button
class="btn-circle btn-sm"
onClick={() => {
const modal = document.querySelector(
`#${modalID}`,
) as HTMLDialogElement | null

modal?.close()
}}
icon={<IconX size={20} />}
/>
</div>

<Modal
ref={(el) => props.ref?.(el)}
icon={<IconNetwork size={24} />}
title={t('connectionsSettings')}
action={
<Button
class="btn-neutral btn-sm"
onClick={() => {
props.onOrderChange(CONNECTIONS_TABLE_INITIAL_COLUMN_ORDER)
props.onVisibleChange(CONNECTIONS_TABLE_INITIAL_COLUMN_VISIBILITY)
}}
>
{t('reset')}
</Button>
}
>
<div class="flex flex-col gap-4">
<div>
<ConfigTitle withDivider>{t('tableSize')}</ConfigTitle>

Expand Down Expand Up @@ -267,23 +265,7 @@ export const ConnectionsSettingsModal = (props: {
</DragOverlay>
</DragDropProvider>
</div>

<div class="modal-action">
<Button
class="btn-neutral btn-sm ml-auto mt-4 block"
onClick={() => {
props.onOrderChange(CONNECTIONS_TABLE_INITIAL_COLUMN_ORDER)
props.onVisibleChange(CONNECTIONS_TABLE_INITIAL_COLUMN_VISIBILITY)
}}
>
{t('reset')}
</Button>
</div>
</div>

<form method="dialog" class="modal-backdrop">
<button />
</form>
</dialog>
</Modal>
)
}
64 changes: 24 additions & 40 deletions src/components/ConnectionsTableDetailsModal.tsx
Original file line number Diff line number Diff line change
@@ -1,50 +1,34 @@
import { IconX } from '@tabler/icons-solidjs'
import { IconNetwork } from '@tabler/icons-solidjs'
import { Component, Show } from 'solid-js'
import { MODAL } from '~/constants'
import { Modal } from '~/components'
import { useI18n } from '~/i18n'
import { allConnections } from '~/signals'
import { Button } from './Button'

export const ConnectionsTableDetailsModal: Component<{
ref?: (el: HTMLDialogElement) => void
selectedConnectionID?: string
}> = (props) => {
const modalID = MODAL.CONNECTIONS_TABLE_DETAILS
const [t] = useI18n()

return (
<dialog id={modalID} class="modal modal-bottom sm:modal-middle">
<div class="modal-box">
<div class="sticky top-0 z-50 flex items-center justify-end">
<Button
class="btn-circle btn-sm"
onClick={() => {
const modal = document.querySelector(
`#${modalID}`,
) as HTMLDialogElement | null

modal?.close()
}}
>
<IconX size={20} />
</Button>
</div>

<Show when={props.selectedConnectionID}>
<pre>
<code>
{JSON.stringify(
allConnections().find(
({ id }) => id === props.selectedConnectionID,
),
null,
2,
)}
</code>
</pre>
</Show>
</div>

<form method="dialog" class="modal-backdrop">
<button />
</form>
</dialog>
<Modal
ref={(el) => props.ref?.(el)}
icon={<IconNetwork size={24} />}
title={t('connectionsDetails')}
>
<Show when={props.selectedConnectionID}>
<pre>
<code>
{JSON.stringify(
allConnections().find(
({ id }) => id === props.selectedConnectionID,
),
null,
2,
)}
</code>
</pre>
</Show>
</Modal>
)
}
40 changes: 13 additions & 27 deletions src/components/LogsSettingsModal.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { IconX } from '@tabler/icons-solidjs'
import { For } from 'solid-js'
import { Button, ConfigTitle } from '~/components'
import { IconFileStack } from '@tabler/icons-solidjs'
import { Component, For } from 'solid-js'
import { ConfigTitle, Modal } from '~/components'
import {
LOGS_TABLE_MAX_ROWS_LIST,
LOG_LEVEL,
MODAL,
TAILWINDCSS_SIZE,
} from '~/constants'
import { useI18n } from '~/i18n'
Expand All @@ -17,27 +16,18 @@ import {
setLogsTableSize,
} from '~/signals'

export const LogsSettingsModal = () => {
const modalID = MODAL.LOGS_SETTINGS
export const LogsSettingsModal: Component<{
ref?: (el: HTMLDialogElement) => void
}> = (props) => {
const [t] = useI18n()

return (
<dialog id={modalID} class="modal modal-bottom sm:modal-middle">
<div class="modal-box flex flex-col gap-4">
<div class="sticky top-0 z-50 flex items-center justify-end">
<Button
class="btn-circle btn-sm"
onClick={() => {
const modal = document.querySelector(
`#${modalID}`,
) as HTMLDialogElement | null

modal?.close()
}}
icon={<IconX size={20} />}
/>
</div>

<Modal
ref={(el) => props.ref?.(el)}
icon={<IconFileStack size={24} />}
title={t('logsSettings')}
>
<div class="flex flex-col gap-4">
<div>
<ConfigTitle withDivider>{t('tableSize')}</ConfigTitle>

Expand Down Expand Up @@ -90,10 +80,6 @@ export const LogsSettingsModal = () => {
</select>
</div>
</div>

<form method="dialog" class="modal-backdrop">
<button />
</form>
</dialog>
</Modal>
)
}
53 changes: 53 additions & 0 deletions src/components/Modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { IconX } from '@tabler/icons-solidjs'
import { JSX, ParentComponent, Show, children } from 'solid-js'
import { twMerge } from 'tailwind-merge'
import { Button } from '~/components'

type Props = {
ref?: (el: HTMLDialogElement) => void
icon?: JSX.Element
title?: JSX.Element
action?: JSX.Element
}

const actionClass =
'sticky bottom-0 z-50 flex items-center justify-end bg-base-100 bg-opacity-80 p-6 backdrop-blur'

export const Modal: ParentComponent<Props> = (props) => {
let dialogRef: HTMLDialogElement | undefined

return (
<dialog
ref={(el) => (dialogRef = el) && props.ref?.(el)}
class="modal modal-bottom sm:modal-middle"
>
<div class="modal-box p-0" onContextMenu={(e) => e.preventDefault()}>
<div class={twMerge(actionClass, 'top-0 justify-between')}>
<div class="flex items-center gap-4 text-xl font-bold">
{props.icon}
<span>{props.title}</span>
</div>
<Button
class="btn-circle btn-sm"
onClick={() => {
dialogRef?.close()
}}
icon={<IconX size={20} />}
/>
</div>

<div class="p-6 pt-3">{children(() => props.children)()}</div>

<Show when={props.action}>
<div class={actionClass}>
<div class="flex justify-end gap-2">{props.action}</div>
</div>
</Show>
</div>

<form method="dialog" class="modal-backdrop">
<button />
</form>
</dialog>
)
}
41 changes: 14 additions & 27 deletions src/components/ProxiesSettingsModal.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { IconX } from '@tabler/icons-solidjs'
import { For } from 'solid-js'
import { Button, ConfigTitle } from '~/components'
import { MODAL, PROXIES_ORDERING_TYPE, PROXIES_PREVIEW_TYPE } from '~/constants'
import { IconGlobe } from '@tabler/icons-solidjs'
import { Component, For } from 'solid-js'
import { ConfigTitle, Modal } from '~/components'
import { PROXIES_ORDERING_TYPE, PROXIES_PREVIEW_TYPE } from '~/constants'
import { useI18n } from '~/i18n'
import {
autoCloseConns,
Expand All @@ -18,27 +18,18 @@ import {
urlForLatencyTest,
} from '~/signals'

export const ProxiesSettingsModal = () => {
const modalID = MODAL.PROXIES_SETTINGS
export const ProxiesSettingsModal: Component<{
ref?: (el: HTMLDialogElement) => void
}> = (props) => {
const [t] = useI18n()

return (
<dialog id={modalID} class="modal modal-bottom sm:modal-middle">
<div class="modal-box flex flex-col gap-4">
<div class="sticky top-0 z-50 flex items-center justify-end">
<Button
class="btn-circle btn-sm"
onClick={() => {
const modal = document.querySelector(
`#${modalID}`,
) as HTMLDialogElement | null

modal?.close()
}}
icon={<IconX size={20} />}
/>
</div>

<Modal
ref={(el) => props.ref?.(el)}
icon={<IconGlobe size={24} />}
title={t('proxiesSettings')}
>
<div class="flex flex-col gap-4">
<div>
<ConfigTitle withDivider>{t('autoCloseConns')}</ConfigTitle>

Expand Down Expand Up @@ -126,10 +117,6 @@ export const ProxiesSettingsModal = () => {
</select>
</div>
</div>

<form method="dialog" class="modal-backdrop">
<button />
</form>
</dialog>
</Modal>
)
}
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export * from './Header'
export * from './Latency'
export * from './LogoText'
export * from './LogsSettingsModal'
export * from './Modal'
export * from './ProxiesSettingsModal'
export * from './ProxyCardGroups'
export * from './ProxyNodeCard'
Expand Down
Loading