Skip to content

Commit

Permalink
feat(modals): add modal component (#268)
Browse files Browse the repository at this point in the history
* feat: add modal component

* feat: add modal component

* fix: proxies page arrow button problem

* fix: button radius problem

* feat: add modal component

* feat: add modal component

---------

Signed-off-by: Alpha <61853980+AlphaGHX@users.noreply.github.com>
  • Loading branch information
AlphaGHX committed Sep 23, 2023
1 parent 04c8d25 commit eca9a16
Show file tree
Hide file tree
Showing 14 changed files with 161 additions and 175 deletions.
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

0 comments on commit eca9a16

Please sign in to comment.