@byomakase/omakase-player 0.0.2

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.
Files changed (86) hide show
  1. package/LICENSE +228 -0
  2. package/README.md +233 -0
  3. package/dist/api/api.d.ts +17 -0
  4. package/dist/api/audio-api.d.ts +24 -0
  5. package/dist/api/marker-lane-api.d.ts +33 -0
  6. package/dist/api/omakase-player-api.d.ts +38 -0
  7. package/dist/api/subtitles-api.d.ts +36 -0
  8. package/dist/api/timeline-api.d.ts +91 -0
  9. package/dist/api/video-api.d.ts +68 -0
  10. package/dist/audio/audio-controller.d.ts +32 -0
  11. package/dist/common/browser-provider.d.ts +34 -0
  12. package/dist/common/component.d.ts +56 -0
  13. package/dist/common/measurement.d.ts +41 -0
  14. package/dist/common/style-adapter.d.ts +27 -0
  15. package/dist/common/styles-provider.d.ts +33 -0
  16. package/dist/constants.d.ts +9 -0
  17. package/dist/dom/dom-controller.d.ts +53 -0
  18. package/dist/dom/fullscreen.d.ts +32 -0
  19. package/dist/events.d.ts +14 -0
  20. package/dist/http.d.ts +2 -0
  21. package/dist/images/help.svg +17 -0
  22. package/dist/images/loading.svg +29 -0
  23. package/dist/images/pause.svg +19 -0
  24. package/dist/images/play.svg +18 -0
  25. package/dist/images/replay.svg +23 -0
  26. package/dist/index.d.ts +3 -0
  27. package/dist/omakase-player.cjs.js +71 -0
  28. package/dist/omakase-player.cjs.js.map +1 -0
  29. package/dist/omakase-player.d.ts +51 -0
  30. package/dist/omakase-player.es.js +17439 -0
  31. package/dist/omakase-player.es.js.map +1 -0
  32. package/dist/omakase-player.umd.js +71 -0
  33. package/dist/omakase-player.umd.js.map +1 -0
  34. package/dist/style.css +1 -0
  35. package/dist/subtitles/subtitles-controller.d.ts +51 -0
  36. package/dist/timeline/audio-track/audio-track-lane-item.d.ts +38 -0
  37. package/dist/timeline/audio-track/audio-track-lane.d.ts +46 -0
  38. package/dist/timeline/audio-track/index.d.ts +1 -0
  39. package/dist/timeline/index.d.ts +5 -0
  40. package/dist/timeline/marker/index.d.ts +4 -0
  41. package/dist/timeline/marker/marker-handle.d.ts +55 -0
  42. package/dist/timeline/marker/marker-lane.d.ts +38 -0
  43. package/dist/timeline/marker/marker.d.ts +64 -0
  44. package/dist/timeline/marker/moment-marker.d.ts +31 -0
  45. package/dist/timeline/marker/period-marker.d.ts +43 -0
  46. package/dist/timeline/playhead-hover.d.ts +36 -0
  47. package/dist/timeline/playhead.d.ts +40 -0
  48. package/dist/timeline/scrollbar.d.ts +60 -0
  49. package/dist/timeline/scrubber-lane.d.ts +44 -0
  50. package/dist/timeline/subtitles/index.d.ts +1 -0
  51. package/dist/timeline/subtitles/subtitles-lane-item.d.ts +40 -0
  52. package/dist/timeline/subtitles/subtitles-lane.d.ts +38 -0
  53. package/dist/timeline/thumbnail/index.d.ts +1 -0
  54. package/dist/timeline/thumbnail/thumbnail-lane.d.ts +54 -0
  55. package/dist/timeline/thumbnail/thumbnail.d.ts +46 -0
  56. package/dist/timeline/timecode-display.d.ts +32 -0
  57. package/dist/timeline/timeline-lane.d.ts +70 -0
  58. package/dist/timeline/timeline.d.ts +222 -0
  59. package/dist/track/audio-vtt-file.d.ts +8 -0
  60. package/dist/track/subtitles-vtt-file.d.ts +8 -0
  61. package/dist/track/subtitles-vtt-track.d.ts +5 -0
  62. package/dist/track/thumbnail-vtt-file.d.ts +11 -0
  63. package/dist/track/track.d.ts +12 -0
  64. package/dist/track/vtt-file.d.ts +32 -0
  65. package/dist/types/common.d.ts +6 -0
  66. package/dist/types/events.d.ts +125 -0
  67. package/dist/types/index.d.ts +5 -0
  68. package/dist/types/model.d.ts +17 -0
  69. package/dist/types/track.d.ts +21 -0
  70. package/dist/types/types.d.ts +3 -0
  71. package/dist/types/vtt.d.ts +23 -0
  72. package/dist/util/animation-util.d.ts +11 -0
  73. package/dist/util/color-util.d.ts +3 -0
  74. package/dist/util/frame-util.d.ts +18 -0
  75. package/dist/util/image-util.d.ts +9 -0
  76. package/dist/util/observable-util.d.ts +2 -0
  77. package/dist/util/shape-util.d.ts +17 -0
  78. package/dist/util/time-util.d.ts +6 -0
  79. package/dist/util/window-util.d.ts +4 -0
  80. package/dist/validators.d.ts +6 -0
  81. package/dist/video/playback-state.d.ts +23 -0
  82. package/dist/video/video-controller.d.ts +139 -0
  83. package/dist/video/video-hls-controller.d.ts +15 -0
  84. package/dist/video/video.d.ts +19 -0
  85. package/package.json +56 -0
  86. package/style/omakase-player.scss +144 -0
@@ -0,0 +1,21 @@
1
+ export interface OmakaseTrackConfig {
2
+ id: string;
3
+ src: string;
4
+ default: boolean;
5
+ label: string;
6
+ language: string;
7
+ }
8
+ export interface OmakaseTextTrackCue {
9
+ id: string;
10
+ startTime: number;
11
+ endTime: number;
12
+ }
13
+ export interface OmakaseTextTrack<T extends OmakaseTextTrackCue> {
14
+ id: string;
15
+ src: string;
16
+ default: boolean;
17
+ label: string;
18
+ language: string;
19
+ hidden: boolean;
20
+ cues: T[];
21
+ }
@@ -0,0 +1,3 @@
1
+ export type CamelToSnakeCase<S extends string> = S extends `${infer T}${infer U}` ? `${T extends Capitalize<T> ? "_" : ""}${Lowercase<T>}${CamelToSnakeCase<U>}` : S;
2
+ export type PartialRecord<K extends keyof any, T> = Partial<Record<K, T>>;
3
+ export type WithOptionalPartial<T, K extends keyof T> = Omit<T, K> & PartialRecord<K, Partial<T[K]>>;
@@ -0,0 +1,23 @@
1
+ import { OmakaseTextTrackCue, OmakaseTrackConfig } from "./track";
2
+ export interface OmakaseVttFile<T extends OmakaseVttCue> {
3
+ getCues(): T[];
4
+ findCue(time: number): T;
5
+ findCues(startTime: number, endTime: number): T[];
6
+ }
7
+ export interface OmakaseVttCue extends OmakaseTextTrackCue {
8
+ text: string;
9
+ vttCue?: VTTCue;
10
+ }
11
+ export interface ThumbnailVttCue extends OmakaseVttCue {
12
+ url: string;
13
+ }
14
+ export interface SubtitlesVttCue extends OmakaseVttCue {
15
+ }
16
+ export interface AudioVttCue extends OmakaseVttCue {
17
+ minSample: number;
18
+ maxSample: number;
19
+ }
20
+ export interface SubtitlesVttTrackConfig extends OmakaseTrackConfig {
21
+ label: string;
22
+ language: string;
23
+ }
@@ -0,0 +1,11 @@
1
+ import Konva from "konva";
2
+ import { IFrame } from "konva/lib/types";
3
+ export interface AnimateConf {
4
+ layer: Konva.Layer;
5
+ duration: number;
6
+ from: number;
7
+ to: number;
8
+ onUpdateHandler: (frame: IFrame, value: number) => void;
9
+ onCompleteHandler?: (frame: IFrame, value: number) => void;
10
+ }
11
+ export declare function animate(conf: AnimateConf): void;
@@ -0,0 +1,3 @@
1
+ export declare class ColorUtil {
2
+ static randomHexColor(): string;
3
+ }
@@ -0,0 +1,18 @@
1
+ import Decimal from "decimal.js";
2
+ export declare class FrameUtil {
3
+ /***
4
+ * Returns frame number
5
+ *
6
+ * @param time in Seconds
7
+ * @param frameRateDecimal
8
+ */
9
+ static timeToFrame(time: number, frameRateDecimal: Decimal): number;
10
+ /***
11
+ * Returns time in seconds
12
+ *
13
+ * @param framesCount
14
+ * @param frameRateDecimal
15
+ * @param timeCorrection
16
+ */
17
+ static frameToTime(framesCount: number, frameRateDecimal: Decimal): number;
18
+ }
@@ -0,0 +1,9 @@
1
+ import Konva from "konva";
2
+ import { Observable } from "rxjs";
3
+ export declare class ImageUtil {
4
+ static createKonvaImage(url: string): Observable<Konva.Image>;
5
+ static createKonvaImageSizedByWidth(url: string, width: number): Observable<Konva.Image>;
6
+ static createKonvaImageSizedByHeight(url: string, height: number): Observable<Konva.Image>;
7
+ static calculateProportionalHeight(width: number, image: Konva.Image): number;
8
+ static calculateProportionalWidth(height: number, image: Konva.Image): number;
9
+ }
@@ -0,0 +1,2 @@
1
+ import { Subject } from "rxjs";
2
+ export declare function completeSubject(subject: Subject<void>): void;
@@ -0,0 +1,17 @@
1
+ import Konva from "konva";
2
+ export declare class ShapeUtil {
3
+ static createGoldenRatioWedge(config: {
4
+ x: number;
5
+ y: number;
6
+ height: number;
7
+ color: string;
8
+ }): Konva.Line;
9
+ static createTriangle(config: {
10
+ x: number;
11
+ y: number;
12
+ height: number;
13
+ color: string;
14
+ }): Konva.Line;
15
+ static createEventCatcher(config?: Konva.RectConfig): import("konva/lib/shapes/Rect").Rect;
16
+ static createDebugRect(): import("konva/lib/shapes/Rect").Rect;
17
+ }
@@ -0,0 +1,6 @@
1
+ import Decimal from "decimal.js";
2
+ export declare class TimeUtil {
3
+ static readonly VIDEO_ZERO_TIMESTAMP: string;
4
+ static formatVideoTimestamp(time: number, frameRateDecimal: Decimal): string;
5
+ private static padZero;
6
+ }
@@ -0,0 +1,4 @@
1
+ export declare class WindowUtil {
2
+ static resetCursorStyle(): void;
3
+ static cursor(cursor: 'default' | 'pointer' | 'grab' | 'grabbing' | 'ew-resize'): void;
4
+ }
@@ -0,0 +1,6 @@
1
+ export declare class Validators {
2
+ static id(): (value: string) => string;
3
+ static description(): (value: string) => string;
4
+ static boolean(): (value: boolean) => boolean;
5
+ static url(): (value: string) => string;
6
+ }
@@ -0,0 +1,23 @@
1
+ import { Subject } from "rxjs";
2
+ export interface PlaybackState {
3
+ playing: boolean;
4
+ paused: boolean;
5
+ waiting: boolean;
6
+ seeking: boolean;
7
+ buffering: boolean;
8
+ ended: boolean;
9
+ }
10
+ export declare class PlaybackStateMachine {
11
+ readonly onChange$: Subject<PlaybackState>;
12
+ private _state;
13
+ constructor();
14
+ private updateState;
15
+ private compare;
16
+ get state(): PlaybackState;
17
+ setPlaying(): void;
18
+ setPaused(): void;
19
+ setEnded(): void;
20
+ set waiting(value: boolean);
21
+ set seeking(value: boolean);
22
+ set buffering(value: boolean);
23
+ }
@@ -0,0 +1,139 @@
1
+ import Decimal from "decimal.js";
2
+ import { AudioEvent, VideoBufferingEvent, VideoEndedEvent, VideoLoadedEvent, VideoLoadingEvent, VideoPlayEvent, VideoSeekedEvent, VideoSeekingEvent, VideoTimeChangeEvent } from "../types/events";
3
+ import { BehaviorSubject, Observable, Subject } from "rxjs";
4
+ import { BrowserProvider } from "../common/browser-provider";
5
+ import { VideoApi } from "../api/video-api";
6
+ import { Video } from "./video";
7
+ import { DomController } from "../dom/dom-controller";
8
+ import { PlaybackState, PlaybackStateMachine } from "./playback-state";
9
+ import Hls from "hls.js";
10
+ import { HelpMenuGroup } from "../types";
11
+ export declare const HTMLVideoElementEventKeys: {
12
+ PAUSE: string;
13
+ WAITING: string;
14
+ PLAYING: string;
15
+ TIMEUPDATE: string;
16
+ SEEKING: string;
17
+ SEEKED: string;
18
+ LOADEDDATA: string;
19
+ LOADEDMETEDATA: string;
20
+ ENDED: string;
21
+ PROGRESS: string;
22
+ };
23
+ export interface BufferedTimespan {
24
+ start: number;
25
+ end: number;
26
+ }
27
+ export type HTMLVideoElementCrossorigin = 'anonymous' | 'use-credentials';
28
+ interface VideoFrameCallbackData {
29
+ now: DOMHighResTimeStamp;
30
+ metadata: VideoFrameCallbackMetadata;
31
+ }
32
+ export declare abstract class VideoController implements VideoApi {
33
+ protected browserProvider: BrowserProvider;
34
+ protected domController: DomController;
35
+ protected crossorigin: HTMLVideoElementCrossorigin;
36
+ protected videoElement: HTMLVideoElement;
37
+ protected helpMenuGroups: HelpMenuGroup[];
38
+ protected video: Video;
39
+ protected _isVideoLoaded: boolean;
40
+ protected playbackStateMachine: PlaybackStateMachine;
41
+ protected frameRateDecimal: Decimal;
42
+ protected userSetDuration: number;
43
+ protected frameDurationSpillOverCorrection: number;
44
+ protected syncStepCurrentTimeMediaTime: number;
45
+ protected syncLoopMaxIterations: number;
46
+ protected videoFrameCallbackHandle: number;
47
+ protected seekInProgress: boolean;
48
+ protected videoStalledCheckIntervalMs: number;
49
+ protected videoStalledCheckLastCurrentTime: number;
50
+ /***
51
+ * Stream of data provided by videoElement.requestVideoFrameCallback()
52
+ * @protected
53
+ */
54
+ protected readonly videoFrameCallback$: BehaviorSubject<VideoFrameCallbackData>;
55
+ protected videoEventBreaker$: Subject<void>;
56
+ /***
57
+ * Cancels previous unfinished seek operation if new seek is requested
58
+ * @protected
59
+ */
60
+ protected seekBreaker$: Subject<void>;
61
+ readonly onVideoLoaded$: Subject<VideoLoadedEvent>;
62
+ readonly onVideoLoading$: Subject<VideoLoadingEvent>;
63
+ readonly onPlay$: Subject<VideoPlayEvent>;
64
+ readonly onPause$: Subject<VideoPlayEvent>;
65
+ readonly onVideoTimeChange$: Subject<VideoTimeChangeEvent>;
66
+ readonly onSeeking$: Subject<VideoSeekingEvent>;
67
+ readonly onSeeked$: Subject<VideoSeekedEvent>;
68
+ readonly onBuffering$: Subject<VideoBufferingEvent>;
69
+ readonly onEnded$: Subject<VideoEndedEvent>;
70
+ readonly onAudioSwitched$: Subject<AudioEvent>;
71
+ readonly onPlaybackState$: Subject<PlaybackState>;
72
+ readonly onHelpMenuChange$: Subject<void>;
73
+ protected constructor(domController: DomController, crossorigin: HTMLVideoElementCrossorigin);
74
+ loadVideo(sourceUrl: string, frameRate: number, duration: number): Observable<Video>;
75
+ protected abstract videoLoad(sourceUrl: string, frameRate: number, duration: number): Observable<Video>;
76
+ protected initEventHandlers(): void;
77
+ getBufferedTimespans(): BufferedTimespan[];
78
+ protected startVideoFrameCallback(): void;
79
+ private detachVideoEventListeners;
80
+ private syncVideoFrames;
81
+ private seekTimeAndSync;
82
+ private _seekTimeFireAndForget;
83
+ private _seekTimeAndSyncNoEmitEvents;
84
+ /***
85
+ *
86
+ * @param timeOffset Time offset in seconds
87
+ */
88
+ private seekFromCurrentTimeAndSync;
89
+ private setCurrentTime;
90
+ getFrameRateDecimal(): Decimal;
91
+ private _seekToFrame;
92
+ /***
93
+ *
94
+ * @param framesCount Positive or negative number of frames. If positive - seek forward, if negative - seek backward.
95
+ */
96
+ private _seekFromCurrentFrame;
97
+ private videoTimeChangeHandlerExecutor;
98
+ getPlaybackState(): PlaybackState;
99
+ getVideo(): Video;
100
+ getHTMLVideoElement(): HTMLVideoElement;
101
+ calculateTimeToFrame(time: number): number;
102
+ calculateFrameToTime(framesCount: number): number;
103
+ play(): void;
104
+ pause(): void;
105
+ togglePlayPause(): void;
106
+ isPlaying(): boolean;
107
+ isPaused(): boolean;
108
+ isSeeking(): boolean;
109
+ getCurrentTime(): number;
110
+ getPlaybackRate(): number;
111
+ setPlaybackRate(playbackRate: number): void;
112
+ getVolume(): number;
113
+ setVolume(volume: number): void;
114
+ /***
115
+ * return Video duration in seconds
116
+ */
117
+ getDuration(): number;
118
+ getFrameRate(): number;
119
+ getTotalFrames(): number;
120
+ getCurrentFrame(): number;
121
+ seekToFrame(frame: number): Observable<boolean>;
122
+ seekFromCurrentFrame(framesCount: number): Observable<boolean>;
123
+ seekPreviousFrame(): Observable<boolean>;
124
+ seekNextFrame(): Observable<boolean>;
125
+ seekToTimestamp(currentTime: number): Observable<boolean>;
126
+ formatTimestamp(currentTime: number): string;
127
+ mute(): void;
128
+ unmute(): void;
129
+ isFullscreen(): boolean;
130
+ toggleFullscreen(): void;
131
+ getAudioTracks(): any[];
132
+ getCurrentAudioTrack(): any;
133
+ setAudioTrack(audioTrackId: number): void;
134
+ isVideoLoaded(): boolean;
135
+ getHls(): Hls;
136
+ addHelpMenuGroup(helpMenuGroup: HelpMenuGroup): void;
137
+ getHelpMenuGroups(): HelpMenuGroup[];
138
+ }
139
+ export {};
@@ -0,0 +1,15 @@
1
+ import { HTMLVideoElementCrossorigin, VideoController } from "./video-controller";
2
+ import Hls, { MediaPlaylist } from "hls.js";
3
+ import { Observable } from "rxjs";
4
+ import { Video } from "./video";
5
+ import { DomController } from "../dom/dom-controller";
6
+ export declare class VideoHlsController extends VideoController {
7
+ protected hls: Hls;
8
+ constructor(domController: DomController, crossorigin: HTMLVideoElementCrossorigin);
9
+ videoLoad(sourceUrl: string, frameRate: number, duration: number): Observable<Video>;
10
+ protected initEventHandlers(): void;
11
+ getAudioTracks(): MediaPlaylist[];
12
+ getCurrentAudioTrack(): any;
13
+ setAudioTrack(audioTrackId: number): any;
14
+ getHls(): Hls;
15
+ }
@@ -0,0 +1,19 @@
1
+ export declare class Video {
2
+ private readonly _element;
3
+ private readonly _sourceUrl;
4
+ private readonly _frameRate;
5
+ private readonly _duration;
6
+ private readonly _totalFrames;
7
+ /***
8
+ * Frame duration in seconds
9
+ * @private
10
+ */
11
+ private readonly _frameDuration;
12
+ constructor(element: HTMLVideoElement, sourceUrl: string, frameRate: number, duration: number);
13
+ get element(): HTMLVideoElement;
14
+ get sourceUrl(): string;
15
+ get frameRate(): number;
16
+ get duration(): number;
17
+ get totalFrames(): number;
18
+ get frameDuration(): number;
19
+ }
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@byomakase/omakase-player",
3
+ "version": "0.0.2",
4
+ "description": "## Omakase Player - Open source JavaScript framework for building frame accurate video experiences",
5
+ "author": "ByOmakase",
6
+ "homepage": "https://byomakase.org",
7
+ "copyright": "Copyright 2023 ByOmakase, LLC <https://byomakase.org/>",
8
+ "license": "Apache-2.0",
9
+ "keywords": [
10
+ "hls",
11
+ "frame",
12
+ "accurate",
13
+ "timeline",
14
+ "player",
15
+ "video",
16
+ "segmentation",
17
+ "markers"
18
+ ],
19
+ "main": "./dist/omakase-player.cjs.js",
20
+ "module": "./dist/omakase-player.es.js",
21
+ "style": "./dist/style.css",
22
+ "scripts": {
23
+ "dev": "vite",
24
+ "int": "tsc --noEmit && vite build --debug",
25
+ "prod": "tsc --noEmit && vite build --debug",
26
+ "check": "tsc --noEmit",
27
+ "dev:tsc": "rm -rf dist/lib && tsc --watch",
28
+ "build:tsc": "rm -rf dist/lib && tsc"
29
+ },
30
+ "dependencies": {
31
+ "axios": "1.3.3",
32
+ "decimal.js": "10.4.3",
33
+ "eventemitter3": "5.0.0",
34
+ "hls.js": "1.3.3",
35
+ "konva": "8.3.14",
36
+ "node-webvtt": "1.9.4",
37
+ "rxjs": "7.8.0",
38
+ "zod": "3.20.6"
39
+ },
40
+ "devDependencies": {
41
+ "sass": "^1.59.2",
42
+ "typescript": "^4.9.5",
43
+ "vite": "^4.1.3",
44
+ "vite-plugin-dts": "^2.0.0-beta.2"
45
+ },
46
+ "publishConfig": {
47
+ "registry": "https://registry.npmjs.org"
48
+ },
49
+ "repository": {
50
+ "type": "git",
51
+ "url": "https://github.com/byomakase/omakase-player.git"
52
+ },
53
+ "bugs": {
54
+ "url": "https://github.com/byomakase/omakase-player/issues"
55
+ }
56
+ }
@@ -0,0 +1,144 @@
1
+ .omakase-player {
2
+ display: block;
3
+
4
+ .d-none {
5
+ display: none;
6
+ }
7
+
8
+ .d-block {
9
+ display: block;
10
+ }
11
+
12
+ .float-start {
13
+ float: left !important;
14
+ }
15
+
16
+ .float-end {
17
+ float: right !important;
18
+ }
19
+
20
+ .omakase-player-wrapper {
21
+ display: block;
22
+ position: relative;
23
+ width: 700px;
24
+
25
+ .omakase-video {
26
+ display: block;
27
+ width: 100%;
28
+ opacity: 100%;
29
+ }
30
+
31
+ .omakase-video-controls {
32
+
33
+ .omakase-overlay-buttons {
34
+
35
+ .omakase-video-overlay-button {
36
+ background-repeat: no-repeat;
37
+ width: 128px;
38
+ height: 128px;
39
+ position: absolute;
40
+ left: 0;
41
+ right: 0;
42
+ top: 0;
43
+ bottom: 0;
44
+ margin: auto;
45
+ background-size: contain;
46
+ background-position: center;
47
+ }
48
+
49
+ .omakase-button-play {
50
+ background-image: url(/images/play.svg);
51
+ }
52
+
53
+ .omakase-button-pause {
54
+ background-image: url(/images/pause.svg);
55
+ }
56
+
57
+ .omakase-button-replay {
58
+ background-image: url(/images/replay.svg);
59
+ }
60
+
61
+ .omakase-button-loading {
62
+ background-image: url(/images/loading.svg);
63
+ animation: loading 3s linear infinite;
64
+ @keyframes loading {
65
+ 0% {
66
+ transform: rotate(0);
67
+ }
68
+ 100% {
69
+ transform: rotate(360deg);
70
+ }
71
+ }
72
+ }
73
+
74
+ }
75
+ }
76
+
77
+ .omakase-help {
78
+ font-family: Arial;
79
+ font-size: 13px;
80
+ position: absolute;
81
+ right: 20px;
82
+ top: 20px;
83
+
84
+ .omakase-help-dropdown {
85
+ position: absolute;
86
+ right: 0;
87
+ top: 0;
88
+
89
+ .omakase-help-button {
90
+ background-color: transparent;
91
+ background-image: url(/images/help.svg);
92
+ background-repeat: no-repeat;
93
+ background-size: contain;
94
+ background-position: center;
95
+ border: 0;
96
+ padding: 0;
97
+
98
+ width: 30px;
99
+ height: 30px;
100
+ margin: 0 0 5px;
101
+ }
102
+
103
+ .omakase-help-menu {
104
+ z-index: 100;
105
+ position: absolute;
106
+ right: 0;
107
+ width: 400px;
108
+
109
+ .omakase-help-group-title {
110
+ background: rgba(2, 171, 141, 1);
111
+ display: block;
112
+ padding: 5px 10px 5px 10px;
113
+ color: #ffffff;
114
+ font-weight: bold;
115
+ text-align: left;
116
+ }
117
+
118
+ .omakase-help-group {
119
+ overflow-y: scroll;
120
+ display: block;
121
+ height: 200px;
122
+ background: rgba(2, 171, 141, 0.2);
123
+
124
+ .omakase-help-item {
125
+ display: list-item;
126
+ padding: 5px 10px 5px 10px;
127
+ color: #ffffff;
128
+ //text-align: left;
129
+
130
+ span {
131
+ //text-align: left;
132
+ }
133
+
134
+ &:hover {
135
+ background-color: #a93232;
136
+ }
137
+ }
138
+ }
139
+ }
140
+ }
141
+ }
142
+
143
+ }
144
+ }