diff --git a/src/actions/clickOutside.js b/src/actions/clickOutside.js new file mode 100644 index 000000000..ba8c0d4de --- /dev/null +++ b/src/actions/clickOutside.js @@ -0,0 +1,15 @@ +export function clickOutside(node) { + const handleClick = event => { + if (node && !node.contains(event.target) && !event.defaultPrevented) { + node.dispatchEvent(new CustomEvent('outside', node)) + } + } + + document.addEventListener('click', handleClick, true) + + return { + destroy() { + document.removeEventListener('click', handleClick, true) + } + } +} diff --git a/src/actions/index.js b/src/actions/index.js new file mode 100644 index 000000000..d2b6fcf48 --- /dev/null +++ b/src/actions/index.js @@ -0,0 +1 @@ +export * from './clickOutside' diff --git a/src/app.css b/src/app.css index bd95b3fd5..d3d527a01 100644 --- a/src/app.css +++ b/src/app.css @@ -1,7 +1,49 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; +@import 'tailwindcss'; + +@plugin "tailwind-scrollbar-hide"; + +@custom-variant dark (&:where(.dark, .dark *)); + +@theme { + --color-primary-950: hsl(219, 23%, 5%); + --color-primary-900: hsl(219, 23%, 10%); + --color-primary-890: hsl(219, 23%, 11%); + --color-primary-880: hsl(219, 23%, 12%); + --color-primary-870: hsl(219, 23%, 13%); + --color-primary-860: hsl(219, 23%, 14%); + --color-primary-850: hsl(219, 23%, 15%); + --color-primary-840: hsl(219, 23%, 16%); + --color-primary-830: hsl(219, 23%, 17%); + --color-primary-820: hsl(219, 23%, 18%); + --color-primary-810: hsl(219, 23%, 19%); + --color-primary-800: hsl(219, 23%, 20%); + --color-primary-790: hsl(219, 23%, 21%); + --color-primary-780: hsl(219, 23%, 22%); + --color-primary-770: hsl(219, 23%, 23%); + --color-primary-760: hsl(219, 23%, 24%); + --color-primary-750: hsl(219, 23%, 25%); + --color-primary-740: hsl(219, 23%, 26%); + --color-primary-730: hsl(219, 23%, 27%); + --color-primary-720: hsl(219, 23%, 28%); + --color-primary-710: hsl(219, 23%, 29%); + --color-primary-700: hsl(219, 23%, 30%); + --color-primary-650: hsl(219, 23%, 35%); + --color-primary-600: hsl(219, 23%, 40%); + --color-primary-500: hsl(219, 23%, 50%); + --color-primary-400: hsl(219, 23%, 60%); + --color-primary-300: hsl(219, 23%, 70%); + --color-primary-200: hsl(219, 23%, 80%); + --color-primary-100: hsl(219, 23%, 90%); + --color-primary-50: hsl(219, 23%, 95%); +} html { overflow-y: scroll; } + +input[type='search']::-webkit-search-decoration, +input[type='search']::-webkit-search-cancel-button, +input[type='search']::-webkit-search-results-button, +input[type='search']::-webkit-search-results-decoration { + -webkit-appearance: none; +} diff --git a/src/commands/api/load.ts b/src/commands/api/load.ts new file mode 100644 index 000000000..7daa8c0b5 --- /dev/null +++ b/src/commands/api/load.ts @@ -0,0 +1,52 @@ +import { ApiClient, DataLoader, DataProcessor } from '../../core' +import { DataStorage } from '../../core/dataStorage' +import cliProgress from 'cli-progress' +import numeral from 'numeral' + +async function main() { + const progressBar = new cliProgress.MultiBar({ + stopOnComplete: true, + hideCursor: true, + forceRedraw: true, + barsize: 36, + format(options, params, payload) { + const filename = payload.filename.padEnd(18, ' ') + const barsize = options.barsize || 40 + const percent = (params.progress * 100).toFixed(2) + const speed = payload.speed ? numeral(payload.speed).format('0.0 b') + '/s' : 'N/A' + const total = numeral(params.total).format('0.0 b') + const completeSize = Math.round(params.progress * barsize) + const incompleteSize = barsize - completeSize + const bar = + options.barCompleteString && options.barIncompleteString + ? options.barCompleteString.substr(0, completeSize) + + options.barGlue + + options.barIncompleteString.substr(0, incompleteSize) + : '-'.repeat(barsize) + + return `${filename} [${bar}] ${percent}% | ETA: ${params.eta}s | ${total} | ${speed}` + } + }) + const storage = new DataStorage() + const processor = new DataProcessor() + const client = new ApiClient() + const dataLoader = new DataLoader({ storage, client, processor, progressBar }) + + const requests = [ + dataLoader.download('channels.json'), + dataLoader.download('feeds.json'), + dataLoader.download('categories.json'), + dataLoader.download('countries.json'), + dataLoader.download('regions.json'), + dataLoader.download('subdivisions.json'), + dataLoader.download('timezones.json'), + dataLoader.download('languages.json'), + dataLoader.download('streams.json'), + dataLoader.download('guides.json'), + dataLoader.download('blocklist.json') + ] + + await Promise.all(requests) +} + +main() diff --git a/src/components/ActionButton.svelte b/src/components/ActionButton.svelte deleted file mode 100644 index 9d0261e8d..000000000 --- a/src/components/ActionButton.svelte +++ /dev/null @@ -1,20 +0,0 @@ - - - diff --git a/src/components/Badge.svelte b/src/components/Badge.svelte new file mode 100644 index 000000000..fd968d450 --- /dev/null +++ b/src/components/Badge.svelte @@ -0,0 +1,5 @@ +
+ +
diff --git a/src/components/BlockedBadge.svelte b/src/components/BlockedBadge.svelte index 9348a4934..866df9804 100644 --- a/src/components/BlockedBadge.svelte +++ b/src/components/BlockedBadge.svelte @@ -1,49 +1,37 @@ - -
- Blocked -
+ +
+ Blocked +
+
diff --git a/src/components/BottomBar.svelte b/src/components/BottomBar.svelte index f079a7b92..5d951b926 100644 --- a/src/components/BottomBar.svelte +++ b/src/components/BottomBar.svelte @@ -1,30 +1,28 @@ -
-
-
- Selected {$selected.length.toLocaleString()} channel(s) -
-
- - - - { - downloadMode.set(false) - }} - /> +
+
+
+
+ {$selected.count()} selected +
+
+ + + + { + downloadMode.set(false) + }} + variant="light" + /> +
diff --git a/src/components/Button.svelte b/src/components/Button.svelte new file mode 100644 index 000000000..e892e7e9e --- /dev/null +++ b/src/components/Button.svelte @@ -0,0 +1,19 @@ + + + diff --git a/src/components/Card.svelte b/src/components/Card.svelte new file mode 100644 index 000000000..860c049b2 --- /dev/null +++ b/src/components/Card.svelte @@ -0,0 +1,16 @@ + + +
+
+ + +
+
+ +
+
diff --git a/src/components/ChannelEditButton.svelte b/src/components/ChannelEditButton.svelte new file mode 100644 index 000000000..3894ef470 --- /dev/null +++ b/src/components/ChannelEditButton.svelte @@ -0,0 +1,29 @@ + + + diff --git a/src/components/ChannelGrid.svelte b/src/components/ChannelGrid.svelte index 91d50d73c..cd9271de9 100644 --- a/src/components/ChannelGrid.svelte +++ b/src/components/ChannelGrid.svelte @@ -1,51 +1,36 @@ - -
-
-
-
-
-
-
-
- Name -
-
- ID -
-
- Actions -
-
-
-
- {#each channelsDisplay as channel, idx (channel)} - - {/each} -
+
+
+
+
+ {#each channelsDisplay.all() as channel, index (channel.id)} + + {/each}
- {#if channelsDisplay.length < channels.length} + {#if channelsDisplay.count() < channels.count()} Show More {/if}
diff --git a/src/components/ChannelItem.svelte b/src/components/ChannelItem.svelte index 3c6c888b1..2d424f106 100644 --- a/src/components/ChannelItem.svelte +++ b/src/components/ChannelItem.svelte @@ -1,45 +1,47 @@ - {#if $downloadMode}
- +
{/if}
-
+
- {#if channel.logo} + {#if channel.logoUrl} {displayName} {/if}
-
-
-
-
- - {displayName} - -
- {#if channel.is_closed} - - {/if} - {#if channel.is_blocked} - - {/if} -
-
- {#if channel.alt_names.length} -
- {channel.alt_names.join(', ')} -
- {/if} -
-
-
-
-
- {channel.id} +
+ + {channel.getDisplayName()} + + {#if channel.isClosed()} + + {/if} + {#if channel.isBlocked()} + + {/if}
+ {#if channel.altNames.notEmpty()} +
+ {channel.altNames.join(', ')} +
+ {/if}
-
+ +
- {#if guides.length} + {#if channel.hasFeeds()} - {/if}{#if streams.length} - {/if}
diff --git a/src/components/ChannelPopup.svelte b/src/components/ChannelPopup.svelte index 12d105a28..329c59fad 100644 --- a/src/components/ChannelPopup.svelte +++ b/src/components/ChannelPopup.svelte @@ -1,57 +1,72 @@ - -