Creates /channel page

This commit is contained in:
Arhey 2023-02-17 15:01:46 +03:00
parent 677365c6da
commit 33d6a13667
6 changed files with 456 additions and 347 deletions

View file

@ -10,7 +10,14 @@
const guides = channel._guides const guides = channel._guides
const streams = channel._streams const streams = channel._streams
const currLocation = window.location.href
const { open } = getContext('simple-modal') const { open } = getContext('simple-modal')
const onOpened = () => {
window.history.pushState({}, `${channel.name} • iptv-org`, `/channel?id=${channel.id}`)
}
const onClosed = () => {
window.history.pushState({}, `iptv-org`, currLocation)
}
const showGuides = () => const showGuides = () =>
open( open(
GuidesPopup, GuidesPopup,
@ -27,7 +34,8 @@
open( open(
ChannelPopup, ChannelPopup,
{ channel }, { channel },
{ transitionBgProps: { duration: 0 }, transitionWindowProps: { duration: 0 } } { transitionBgProps: { duration: 0 }, transitionWindowProps: { duration: 0 } },
{ onOpened, onClosed }
) )
} }
@ -67,9 +75,7 @@
<div class="text-left"> <div class="text-left">
<a <a
on:click|preventDefault="{showChannelData}" on:click|preventDefault="{showChannelData}"
href="/" href="/channel?id={channel.id}"
rel="nofollow"
role="button"
tabindex="0" tabindex="0"
class="font-normal text-gray-600 dark:text-white hover:underline hover:text-blue-500" class="font-normal text-gray-600 dark:text-white hover:underline hover:text-blue-500"
> >

View file

@ -1,6 +1,7 @@
<script> <script>
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { search, query, hasQuery, channels, setSearchParam } from '../store.js' import { goto } from '$app/navigation'
import { search, query, hasQuery, channels, setSearchParam } from '~/store'
export let data export let data
export let close export let close
@ -88,26 +89,25 @@
if ($query !== q) { if ($query !== q) {
query.set(q) query.set(q)
hasQuery.set(true) hasQuery.set(true)
search(q) setTimeout(() => {
setSearchParam('q', q) goto('/')
}, 0)
} }
close() close()
} }
</script> </script>
<div class="pb-8 px-8 pt-6 dark:text-white">
<div class="flex p-4 w-full">
<table class="table-fixed w-full"> <table class="table-fixed w-full">
<tbody> <tbody>
{#each fieldset as field} {#each fieldset as field}
<tr> <tr>
<td class="align-top w-[11rem]"> <td class="align-top w-[11rem]">
<div class="flex px-4 py-1 text-sm text-gray-400 whitespace-nowrap dark:text-gray-400"> <div class="flex pr-4 py-1 text-sm text-gray-400 whitespace-nowrap dark:text-gray-400">
{field.name} {field.name}
</div> </div>
</td> </td>
<td class="align-top"> <td class="align-top">
<div class="flex px-4 py-1 text-sm text-gray-700 dark:text-gray-100 flex-wrap"> <div class="flex py-1 text-sm text-gray-700 dark:text-gray-100 flex-wrap">
{#if field.type === 'image'} {#if field.type === 'image'}
<img <img
src="{field.value}" src="{field.value}"
@ -127,10 +127,7 @@
>,&nbsp; >,&nbsp;
</span> </span>
{/if} {/if}
<button <button on:click="{() => searchBy(value.query)}" class="underline hover:text-blue-500">
on:click="{() => searchBy(value.query)}"
class="underline hover:text-blue-500"
>
{value.label} {value.label}
</button> </button>
{/each} {:else if field.type === 'external_link'} {/each} {:else if field.type === 'external_link'}
@ -164,5 +161,3 @@
{/each} {/each}
</tbody> </tbody>
</table> </table>
</div>
</div>

View file

@ -1,9 +1,9 @@
<script> <script>
import { query, search, setSearchParam } from '../store.js' import { query, search, setSearchParam } from '~/store'
import { goto } from '$app/navigation'
function onSubmit() { function onSubmit() {
setSearchParam('q', $query) goto('/')
search($query)
} }
</script> </script>

View file

@ -1,12 +1,7 @@
<script> <script>
import '~/app.css' import '~/app.css'
import NavBar from '~/components/NavBar.svelte'
import Modal from 'svelte-simple-modal'
let scrollTop = 0
</script> </script>
<svelte:window bind:scrollY="{scrollTop}" />
<svelte:head> <svelte:head>
<script> <script>
if (document) { if (document) {
@ -22,20 +17,4 @@
</script> </script>
</svelte:head> </svelte:head>
<header <slot />
class:absolute="{scrollTop <= 150}"
class:fixed="{scrollTop > 150}"
class="z-40 w-full min-w-[360px]"
style="top: {scrollTop > 150 && scrollTop <= 210 ? scrollTop-210: 0}px"
>
<NavBar withSearch="{scrollTop > 150}" />
</header>
<main class="bg-slate-50 dark:bg-[#1d232e] min-h-screen pt-10 min-w-[360px]">
<Modal
unstyled="{true}"
classBg="fixed top-0 left-0 z-40 w-screen h-screen flex flex-col bg-black/[.7] overflow-y-scroll"
closeButton="{false}"
><slot
/></Modal>
</main>

View file

@ -1,7 +1,11 @@
<script> <script>
import NavBar from '~/components/NavBar.svelte'
import Modal from 'svelte-simple-modal'
import { page } from '$app/stores'
import InfiniteLoading from 'svelte-infinite-loading' import InfiniteLoading from 'svelte-infinite-loading'
import { import {
fetchChannels, fetchChannels,
channels,
hasQuery, hasQuery,
countries, countries,
filteredChannels, filteredChannels,
@ -14,6 +18,7 @@
import CountryItem from '~/components/CountryItem.svelte' import CountryItem from '~/components/CountryItem.svelte'
import SearchField from '~/components/SearchField.svelte' import SearchField from '~/components/SearchField.svelte'
import _ from 'lodash' import _ from 'lodash'
import { afterNavigate } from '$app/navigation'
let _countries = [] let _countries = []
const initLimit = 10 const initLimit = 10
@ -52,7 +57,9 @@
hasQuery.set(true) hasQuery.set(true)
} }
if (!$channels.length) {
await fetchChannels() await fetchChannels()
}
_countries = Object.values($countries) _countries = Object.values($countries)
isLoading = false isLoading = false
@ -73,15 +80,41 @@
} }
} }
}) })
afterNavigate(() => {
setSearchParam('q', $query)
search($query)
})
let scrollTop = 0
</script> </script>
<svelte:window bind:scrollY="{scrollTop}" />
<svelte:head> <svelte:head>
<title>iptv-org</title> <title>iptv-org</title>
<meta name="description" content="Collection of resources dedicated to IPTV" /> <meta name="description" content="Collection of resources dedicated to IPTV" />
</svelte:head> </svelte:head>
<header
class:absolute="{scrollTop <= 150}"
class:fixed="{scrollTop > 150}"
class="z-40 w-full min-w-[360px]"
style="top: {scrollTop > 150 && scrollTop <= 210 ? scrollTop-210: 0}px"
>
<NavBar withSearch="{scrollTop > 150}" />
</header>
<main class="bg-slate-50 dark:bg-[#1d232e] min-h-screen pt-10 min-w-[360px]">
<Modal
unstyled="{true}"
classBg="fixed top-0 left-0 z-40 w-screen h-screen flex flex-col bg-black/[.7] overflow-y-scroll"
closeButton="{false}"
>
<section class="container max-w-5xl mx-auto px-2 py-20"> <section class="container max-w-5xl mx-auto px-2 py-20">
<SearchField bind:isLoading="{isLoading}" bind:found="{$filteredChannels.length}"></SearchField> <SearchField
bind:isLoading="{isLoading}"
bind:found="{$filteredChannels.length}"
></SearchField>
{#if isLoading} {#if isLoading}
<div <div
class="flex items-center justify-center w-full pt-1 pb-6 tracking-tight text-sm text-gray-500 dark:text-gray-400 font-mono" class="flex items-center justify-center w-full pt-1 pb-6 tracking-tight text-sm text-gray-500 dark:text-gray-400 font-mono"
@ -104,3 +137,5 @@
</InfiniteLoading> </InfiniteLoading>
{/if} {/if}
</section> </section>
</Modal>
</main>

View file

@ -0,0 +1,94 @@
<script>
import GuideItem from '~/components/GuideItem.svelte'
import StreamItem from '~/components/StreamItem.svelte'
import HTMLPreview from '~/components/HTMLPreview.svelte'
import NavBar from '~/components/NavBar.svelte'
import { onMount } from 'svelte'
import { fetchChannels, channels } from '~/store'
import { page } from '$app/stores'
let channel
let isLoading = true
let streams = []
let guides = []
onMount(async () => {
const id = $page.url.searchParams.get('id')
if (id && !$channels.length) {
await fetchChannels()
}
channel = $channels.find(c => c.id === id)
if (channel) {
streams = channel._streams
guides = channel._guides
}
isLoading = false
})
</script>
<svelte:head>
<title>{channel && channel.name ? `${channel.name} iptv-org` : 'iptv-org'}</title>
</svelte:head>
<header class="fixed z-40 w-full min-w-[360px] top-0">
<NavBar withSearch />
</header>
<main class="bg-slate-50 dark:bg-[#1d232e] min-h-screen min-w-[360px] pt-16">
<section class="container max-w-[820px] mx-auto px-2 pt-6 pb-20 flex-col space-y-4">
{#if isLoading}
<div
class="flex items-center justify-center w-full pt-1 pb-6 tracking-tight text-sm text-gray-500 dark:text-gray-400 font-mono"
>
loading...
</div>
{/if} {#if channel}
<div class="border rounded-md border-gray-200 dark:border-gray-700 dark:bg-gray-800 bg-white">
<div
class="flex justify-between items-center py-4 pl-5 pr-4 rounded-t border-b dark:border-gray-700"
>
<div class="w-1/3 overflow-hidden">
<h1 class="text-l font-medium text-gray-900 dark:text-white">{channel.name}</h1>
</div>
</div>
<div class="overflow-y-scroll overflow-x-hidden w-full p-10">
<HTMLPreview data="{channel}" />
</div>
</div>
{/if} {#if streams.length}
<div class="border rounded-md border-gray-200 dark:border-gray-700 dark:bg-gray-800 bg-white">
<div
class="flex justify-between items-center py-4 pl-5 pr-4 rounded-t border-b dark:border-gray-700"
>
<div class="w-1/3 overflow-hidden">
<h3 class="text-l font-medium text-gray-900 dark:text-white">Streams</h3>
</div>
</div>
<div class="overflow-y-scroll overflow-x-hidden w-full p-6">
<div class="space-y-2">
{#each streams as stream}
<StreamItem stream="{stream}" />
{/each}
</div>
</div>
</div>
{/if} {#if guides.length}
<div class="border rounded-md border-gray-200 dark:border-gray-700 dark:bg-gray-800 bg-white">
<div
class="flex justify-between items-center py-4 pl-5 pr-4 rounded-t border-b dark:border-gray-700"
>
<div class="w-1/3 overflow-hidden">
<h3 class="text-l font-medium text-gray-900 dark:text-white">Guides</h3>
</div>
</div>
<div class="overflow-y-scroll overflow-x-hidden w-full p-6">
<div class="space-y-2">
{#each guides as guide}
<GuideItem guide="{guide}" />
{/each}
</div>
</div>
</div>
{/if}
</section>
</main>