@playpilot/tpi 8.36.2 → 8.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playpilot/tpi",
3
- "version": "8.36.2",
3
+ "version": "8.37.0",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "vite dev",
@@ -408,6 +408,16 @@ export const translations = {
408
408
  [Language.Swedish]: 'Regissör',
409
409
  [Language.Danish]: 'Instruktør',
410
410
  },
411
+ 'Job: cinematographer': {
412
+ [Language.English]: 'Cinematographer',
413
+ [Language.Swedish]: 'Filmfotograf',
414
+ [Language.Danish]: 'Filmfotograf',
415
+ },
416
+ 'Job: editor': {
417
+ [Language.English]: 'Editor',
418
+ [Language.Swedish]: 'Redaktör',
419
+ [Language.Danish]: 'Redaktør',
420
+ },
411
421
 
412
422
  // Genres
413
423
  'All': {
package/src/lib/modal.ts CHANGED
@@ -20,6 +20,8 @@ type Modal = {
20
20
  type: ModalType
21
21
  data: TitleData | TitleData[] | ParticipantData | null
22
22
  scrollPosition?: number
23
+ initialIndex?: number
24
+ props?: Record<string, any>
23
25
  }
24
26
 
25
27
  const modals: Modal[] = []
@@ -97,6 +99,8 @@ export function goBackToPreviousModal(): void {
97
99
  const previousModal = modals.pop()
98
100
  if (!previousModal) return
99
101
 
102
+ console.log(previousModal)
103
+
100
104
  openModal({ ...previousModal })
101
105
  }
102
106
 
@@ -105,14 +109,14 @@ export function getAllModals(): Modal[] {
105
109
  }
106
110
 
107
111
  function saveCurrentModalScrollPosition(): void {
108
- // The scrollable element differs on mobile and desktop.
109
- // On desktop you scroll the entire parent but on mobile you scroll the dialog itself.
110
- const selector = `[data-playpilot-link-injections] ${window.innerWidth > mobileBreakpoint ? '.modal' : '.dialog'}`
111
- const element = document.querySelector(selector)
112
+ // Some modals have their own scroll target which can be set with the corresponding data attribute
113
+ const selector = window.innerWidth > mobileBreakpoint ? '.modal' : '.dialog'
114
+ const element = getPlayPilotWrapperElement().querySelector('[data-modal-scroll-target]') || getPlayPilotWrapperElement().querySelector(selector)
112
115
 
113
116
  if (!element?.scrollTop) return
114
117
 
115
118
  modals[modals.length - 1].scrollPosition = element.scrollTop
119
+ modals[modals.length - 1].props = { initialIndex: parseInt(getPlayPilotWrapperElement().querySelector<HTMLElement>('[data-active-index]')?.dataset.activeIndex || '0') }
116
120
  }
117
121
 
118
122
  export function openModalForInjectedLink(event: MouseEvent, injections: LinkInjection[]): void {
@@ -38,14 +38,13 @@
38
38
  data,
39
39
  props: {
40
40
  onclose: () => navigate('home'),
41
- pushState: false,
42
41
  },
43
42
  })
44
43
  }
45
44
  </script>
46
45
 
47
46
  {#await openModalViaRoute()}
48
- <Modal blur pushState={false}>
47
+ <Modal blur>
49
48
  {#snippet dialog()}
50
49
  <div class="loading">
51
50
  <div class="bar"></div>
@@ -55,7 +54,7 @@
55
54
  {/snippet}
56
55
  </Modal>
57
56
  {:catch}
58
- <Modal blur onclose={() => navigate('home')} pushState={false}>
57
+ <Modal blur onclose={() => navigate('home')}>
59
58
  <div class="error">
60
59
  {t('An Error Occurred')}
61
60
  </div>
@@ -10,6 +10,7 @@
10
10
  import { destroyAllModals, getPreviousModal, goBackToPreviousModal } from '$lib/modal'
11
11
  import { focustrap } from '$lib/actions/focustrap'
12
12
  import { getScrollRoot } from '$lib/scroll'
13
+ import { getPlayPilotWrapperElement } from '$lib/injection'
13
14
 
14
15
  interface Props {
15
16
  children?: Snippet
@@ -21,7 +22,6 @@
21
22
  blur?: boolean
22
23
  closeButtonStyle?: 'shadow' | 'flat'
23
24
  initialScrollPosition?: number
24
- pushState?: boolean
25
25
  onscroll?: () => void
26
26
  onclose?: () => void
27
27
  }
@@ -36,7 +36,6 @@
36
36
  blur = false,
37
37
  closeButtonStyle = 'shadow',
38
38
  initialScrollPosition = 0,
39
- pushState = true,
40
39
  onscroll = () => null,
41
40
  onclose = () => null,
42
41
  }: Props = $props()
@@ -64,11 +63,7 @@
64
63
 
65
64
  hasPreviousModal = !!getPreviousModal()
66
65
 
67
- // Add modal state to the browser history. This allows us to close to modal when using the back button.
68
- // Only do this for the very first modal opened in the stack. The back button always fully closes all modals.
69
- if (pushState && !hasPreviousModal) window.history.pushState({ modal: true }, '', historyHash)
70
-
71
- requestAnimationFrame(setInitialScrollPosition)
66
+ requestAnimationFrame(() => requestAnimationFrame(setInitialScrollPosition))
72
67
 
73
68
  return () => {
74
69
  if (!document.querySelector('.modal')) scrollElement.classList.remove('playpilot-modal-open')
@@ -81,7 +76,8 @@
81
76
  })
82
77
 
83
78
  function setInitialScrollPosition(): void {
84
- const scrollableElement = window.innerWidth > mobileBreakpoint ? modalElement : dialogElement
79
+ /** @see utils/modal.ts > saveCurrentModalScrollPosition */
80
+ const scrollableElement = getPlayPilotWrapperElement().querySelector('[data-modal-scroll-target]') || (window.innerWidth > mobileBreakpoint ? modalElement : dialogElement)
85
81
  scrollableElement?.scrollTo(0, initialScrollPosition)
86
82
  }
87
83
 
@@ -106,7 +102,6 @@
106
102
 
107
103
  <svelte:window
108
104
  onkeydown={({ key }) => { if (key === 'Escape') close() }}
109
- onhashchange={close}
110
105
  bind:innerWidth={windowWidth} />
111
106
 
112
107
  {#snippet closeButton()}
@@ -166,7 +161,7 @@
166
161
  transition:scaleOrFly|global>
167
162
  {#if hasPreviousModal}
168
163
  <div class="close back {closeButtonStyle}">
169
- <RoundButton onclick={() => goBackToPreviousModal()} aria-label="Back">
164
+ <RoundButton onclick={goBackToPreviousModal} aria-label="Back">
170
165
  <IconArrow direction="left" />
171
166
  </RoundButton>
172
167
  </div>
@@ -20,7 +20,6 @@
20
20
 
21
21
  const { items, initialIndex = 0, onchange = () => null, onclose = () => null, each, ...restProps }: Props = $props()
22
22
 
23
-
24
23
  let slider: TinySlider
25
24
  let initialized = $state(false)
26
25
  let transitionDuration = $state(prefersReducedMotion.current ? 0 : 300)
@@ -74,11 +73,13 @@
74
73
  <TinySlider threshold={40} moveThreshold={40} transitionDuration={initialized ? transitionDuration : 0} bind:this={slider}>
75
74
  {#snippet children({ currentIndex })}
76
75
  {#each items as item, index}
76
+ {@const active = currentIndex === index}
77
+
77
78
  <!-- svelte-ignore a11y_click_events_have_key_events -->
78
79
  <!-- svelte-ignore a11y_no_static_element_interactions -->
79
- <div class="item" class:active={index === currentIndex} onclick={() => setSliderIndex(index)}>
80
- {#if Math.abs(index - currentIndex) === 1 || currentIndex === index}
81
- <div class="content" transition:fade={{ duration: initialized ? transitionDuration : 0 }}>
80
+ <div class="item" class:active onclick={() => setSliderIndex(index)} data-active-index={active ? index : null}>
81
+ {#if Math.abs(index - currentIndex) === 1 || active}
82
+ <div class="content" data-modal-scroll-target={active ? '' : null} transition:fade={{ duration: initialized ? transitionDuration : 0 }}>
82
83
  {@render each(item, currentIndex)}
83
84
  </div>
84
85
  {/if}
@@ -77,7 +77,12 @@
77
77
  {#if participants?.length}
78
78
  <Rail {heading}>
79
79
  {#each orderParticipantsByPageTextOccurrence(participants).slice(0, 15) as participant}
80
- <button class="participant" data-testid="participant" onclick={event => onclick(event, participant)}>
80
+ <button
81
+ class="participant"
82
+ data-testid="participant"
83
+ onclick={event => onclick(event, participant)}
84
+ onmouseenter={() => fetchParticipantBySid(participant.sid)}
85
+ ontouchstart={() => fetchParticipantBySid(participant.sid)}>
81
86
  <ParticipantImage {participant} />
82
87
 
83
88
  <div class="name">{participant.name}</div>
@@ -1,3 +1,4 @@
1
+ import fs from 'fs'
1
2
  import path from 'path'
2
3
  import * as dotenv from 'dotenv'
3
4
  import { defineConfig } from 'vitest/config'
@@ -8,11 +9,13 @@ dotenv.config({ path: '.env' })
8
9
 
9
10
  export default defineConfig(({ mode }) => {
10
11
  const isEditiorial = mode === 'editorial'
12
+ const fileName = isEditiorial ? 'editorial.mount.js' : 'mount.js'
11
13
 
12
14
  return {
13
15
  plugins: [
14
16
  svelte(),
15
17
  injectEnvVariables,
18
+ wrapJsToBeSelfContained(fileName),
16
19
  ],
17
20
 
18
21
  build: {
@@ -21,7 +24,7 @@ export default defineConfig(({ mode }) => {
21
24
  input: './src/mount.ts',
22
25
  output: {
23
26
  name: 'PlayPilotMount',
24
- entryFileNames: isEditiorial ? 'editorial.mount.js' : 'mount.js',
27
+ entryFileNames: fileName,
25
28
  assetFileNames: (assetInfo) => assetInfo.name,
26
29
  },
27
30
  },
@@ -56,3 +59,15 @@ const injectEnvVariables = {
56
59
  }
57
60
  },
58
61
  }
62
+
63
+ const wrapJsToBeSelfContained = (fileName) => ({
64
+ name: 'wrap-to-be-self-contained',
65
+ writeBundle() {
66
+ const distPath = path.resolve(__dirname, './dist')
67
+ const targetPath = path.join(distPath, fileName)
68
+ const originalContent = fs.readFileSync(targetPath, 'utf8')
69
+ const wrappedContent = `(() => {\n${originalContent}\n})();\n`
70
+
71
+ fs.writeFileSync(targetPath, wrappedContent)
72
+ },
73
+ })