First UI Pass (#15)
* Added scratchpad dir * Installed Alpine * [WIP] began integrating Tailwind and accompanying theme * [WIP] Set up basic views for sources * Adds new UI to media profiles page * Removes unneeded view
This commit is contained in:
@@ -40,3 +40,4 @@ npm-debug.log
|
|||||||
.env
|
.env
|
||||||
.DS_Store
|
.DS_Store
|
||||||
scratchpad.md
|
scratchpad.md
|
||||||
|
/scratchpad/
|
||||||
|
|||||||
@@ -2,4 +2,30 @@
|
|||||||
@import 'tailwindcss/components';
|
@import 'tailwindcss/components';
|
||||||
@import 'tailwindcss/utilities';
|
@import 'tailwindcss/utilities';
|
||||||
|
|
||||||
|
@import './satoshi';
|
||||||
|
|
||||||
/* This file is for your main application CSS */
|
/* This file is for your main application CSS */
|
||||||
|
[x-cloak] {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
body {
|
||||||
|
@apply relative z-1 bg-whiten font-satoshi text-base font-normal text-body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer components {
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer utilities {
|
||||||
|
/* Chrome, Safari and Opera */
|
||||||
|
.no-scrollbar::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-scrollbar {
|
||||||
|
-ms-overflow-style: none; /* IE and Edge */
|
||||||
|
scrollbar-width: none; /* Firefox */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
*
|
||||||
|
* Font Family: Satoshi
|
||||||
|
* Designed by: Deni Anggara
|
||||||
|
* URL: https://www.fontshare.com/fonts/satoshi
|
||||||
|
* © 2023 Indian Type Foundry
|
||||||
|
*
|
||||||
|
* Font Styles:
|
||||||
|
* Satoshi Light
|
||||||
|
* Satoshi Light Italic
|
||||||
|
* Satoshi Regular
|
||||||
|
* Satoshi Italic
|
||||||
|
* Satoshi Medium
|
||||||
|
* Satoshi Medium Italic
|
||||||
|
* Satoshi Bold
|
||||||
|
* Satoshi Bold Italic
|
||||||
|
* Satoshi Black
|
||||||
|
* Satoshi Black Italic
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Satoshi';
|
||||||
|
src: url('/fonts/satoshi/Satoshi-Light.woff2'), url('/fonts/satoshi/Satoshi-Light.woff'),
|
||||||
|
url('/fonts/satoshi/Satoshi-Light.ttf');
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Satoshi';
|
||||||
|
src: url('/fonts/satoshi/Satoshi-LightItalic.woff2'),
|
||||||
|
url('/fonts/satoshi/Satoshi-LightItalic.woff'), url('/fonts/satoshi/Satoshi-LightItalic.ttf');
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Satoshi';
|
||||||
|
src: url('/fonts/satoshi/Satoshi-Regular.woff2'), url('/fonts/satoshi/Satoshi-Regular.woff'),
|
||||||
|
url('/fonts/satoshi/Satoshi-Regular.ttf');
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Satoshi';
|
||||||
|
src: url('/fonts/satoshi/Satoshi-Italic.woff2'), url('/fonts/satoshi/Satoshi-Italic.woff'),
|
||||||
|
url('/fonts/satoshi/Satoshi-Italic.ttf');
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Satoshi';
|
||||||
|
src: url('/fonts/satoshi/Satoshi-Medium.woff2'), url('/fonts/satoshi/Satoshi-Medium.woff'),
|
||||||
|
url('/fonts/satoshi/Satoshi-Medium.ttf');
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Satoshi';
|
||||||
|
src: url('/fonts/satoshi/Satoshi-MediumItalic.woff2'),
|
||||||
|
url('/fonts/satoshi/Satoshi-MediumItalic.woff'), url('/fonts/satoshi/Satoshi-MediumItalic.ttf');
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Satoshi';
|
||||||
|
src: url('/fonts/satoshi/Satoshi-Bold.woff2'), url('/fonts/satoshi/Satoshi-Bold.woff'),
|
||||||
|
url('/fonts/satoshi/Satoshi-Bold.ttf');
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Satoshi';
|
||||||
|
src: url('/fonts/satoshi/Satoshi-BoldItalic.woff2'), url('/fonts/satoshi/Satoshi-BoldItalic.woff'),
|
||||||
|
url('/fonts/satoshi/Satoshi-BoldItalic.ttf');
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Satoshi';
|
||||||
|
src: url('/fonts/satoshi/Satoshi-BlackItalic.woff2'),
|
||||||
|
url('/fonts/satoshi/Satoshi-BlackItalic.woff'), url('/fonts/satoshi/Satoshi-BlackItalic.ttf');
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: swap;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
+12
-1
@@ -21,10 +21,21 @@ import 'phoenix_html'
|
|||||||
import { Socket } from 'phoenix'
|
import { Socket } from 'phoenix'
|
||||||
import { LiveSocket } from 'phoenix_live_view'
|
import { LiveSocket } from 'phoenix_live_view'
|
||||||
import topbar from '../vendor/topbar'
|
import topbar from '../vendor/topbar'
|
||||||
|
import Alpine from 'alpinejs'
|
||||||
|
|
||||||
|
window.Alpine = Alpine
|
||||||
|
Alpine.start()
|
||||||
|
|
||||||
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute('content')
|
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute('content')
|
||||||
let liveSocket = new LiveSocket('/live', Socket, {
|
let liveSocket = new LiveSocket('/live', Socket, {
|
||||||
params: { _csrf_token: csrfToken }
|
params: { _csrf_token: csrfToken },
|
||||||
|
dom: {
|
||||||
|
onBeforeElUpdated(from, to) {
|
||||||
|
if (from._x_dataStack) {
|
||||||
|
window.Alpine.clone(from, to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Show progress bar on live navigation and form submits
|
// Show progress bar on live navigation and form submits
|
||||||
|
|||||||
+4
-1
@@ -1,3 +1,6 @@
|
|||||||
{
|
{
|
||||||
"description": "Use this one for actual JS deps used in-app"
|
"description": "Use this one for actual JS deps used in-app",
|
||||||
|
"dependencies": {
|
||||||
|
"alpinejs": "^3.13.5"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+274
-1
@@ -2,15 +2,288 @@
|
|||||||
// https://tailwindcss.com/docs/configuration
|
// https://tailwindcss.com/docs/configuration
|
||||||
|
|
||||||
const plugin = require('tailwindcss/plugin')
|
const plugin = require('tailwindcss/plugin')
|
||||||
|
const defaultTheme = require('tailwindcss/defaultTheme')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
content: ['./js/**/*.js', '../lib/pinchflat_web.ex', '../lib/pinchflat_web/**/*.*ex'],
|
content: ['./js/**/*.js', '../lib/pinchflat_web.ex', '../lib/pinchflat_web/**/*.*ex'],
|
||||||
|
darkMode: 'class',
|
||||||
theme: {
|
theme: {
|
||||||
|
fontFamily: {
|
||||||
|
satoshi: ['Satoshi', 'sans-serif']
|
||||||
|
},
|
||||||
|
screens: {
|
||||||
|
'2xsm': '375px',
|
||||||
|
xsm: '425px',
|
||||||
|
'3xl': '2000px',
|
||||||
|
...defaultTheme.screens
|
||||||
|
},
|
||||||
extend: {
|
extend: {
|
||||||
colors: {
|
colors: {
|
||||||
brand: '#FD4F00'
|
current: 'currentColor',
|
||||||
|
transparent: 'transparent',
|
||||||
|
white: '#FFFFFF',
|
||||||
|
black: '#1C2434',
|
||||||
|
'black-2': '#010101',
|
||||||
|
body: '#64748B',
|
||||||
|
bodydark: '#AEB7C0',
|
||||||
|
bodydark1: '#DEE4EE',
|
||||||
|
bodydark2: '#8A99AF',
|
||||||
|
primary: '#3C50E0',
|
||||||
|
secondary: '#80CAEE',
|
||||||
|
stroke: '#E2E8F0',
|
||||||
|
gray: '#EFF4FB',
|
||||||
|
graydark: '#333A48',
|
||||||
|
'gray-2': '#F7F9FC',
|
||||||
|
'gray-3': '#FAFAFA',
|
||||||
|
whiten: '#F1F5F9',
|
||||||
|
whiter: '#F5F7FD',
|
||||||
|
boxdark: '#24303F',
|
||||||
|
'boxdark-2': '#1A222C',
|
||||||
|
strokedark: '#2E3A47',
|
||||||
|
'form-strokedark': '#3d4d60',
|
||||||
|
'form-input': '#1d2a39',
|
||||||
|
'meta-1': '#DC3545',
|
||||||
|
'meta-2': '#EFF2F7',
|
||||||
|
'meta-3': '#10B981',
|
||||||
|
'meta-4': '#313D4A',
|
||||||
|
'meta-5': '#259AE6',
|
||||||
|
'meta-6': '#FFBA00',
|
||||||
|
'meta-7': '#FF6766',
|
||||||
|
'meta-8': '#F0950C',
|
||||||
|
'meta-9': '#E5E7EB',
|
||||||
|
success: '#219653',
|
||||||
|
danger: '#D34053',
|
||||||
|
warning: '#FFA70B'
|
||||||
|
},
|
||||||
|
fontSize: {
|
||||||
|
'title-xxl': ['44px', '55px'],
|
||||||
|
'title-xl': ['36px', '45px'],
|
||||||
|
'title-xl2': ['33px', '45px'],
|
||||||
|
'title-lg': ['28px', '35px'],
|
||||||
|
'title-md': ['24px', '30px'],
|
||||||
|
'title-md2': ['26px', '30px'],
|
||||||
|
'title-sm': ['20px', '26px'],
|
||||||
|
'title-xsm': ['18px', '24px']
|
||||||
|
},
|
||||||
|
spacing: {
|
||||||
|
4.5: '1.125rem',
|
||||||
|
5.5: '1.375rem',
|
||||||
|
6.5: '1.625rem',
|
||||||
|
7.5: '1.875rem',
|
||||||
|
8.5: '2.125rem',
|
||||||
|
9.5: '2.375rem',
|
||||||
|
10.5: '2.625rem',
|
||||||
|
11: '2.75rem',
|
||||||
|
11.5: '2.875rem',
|
||||||
|
12.5: '3.125rem',
|
||||||
|
13: '3.25rem',
|
||||||
|
13.5: '3.375rem',
|
||||||
|
14: '3.5rem',
|
||||||
|
14.5: '3.625rem',
|
||||||
|
15: '3.75rem',
|
||||||
|
15.5: '3.875rem',
|
||||||
|
16: '4rem',
|
||||||
|
16.5: '4.125rem',
|
||||||
|
17: '4.25rem',
|
||||||
|
17.5: '4.375rem',
|
||||||
|
18: '4.5rem',
|
||||||
|
18.5: '4.625rem',
|
||||||
|
19: '4.75rem',
|
||||||
|
19.5: '4.875rem',
|
||||||
|
21: '5.25rem',
|
||||||
|
21.5: '5.375rem',
|
||||||
|
22: '5.5rem',
|
||||||
|
22.5: '5.625rem',
|
||||||
|
24.5: '6.125rem',
|
||||||
|
25: '6.25rem',
|
||||||
|
25.5: '6.375rem',
|
||||||
|
26: '6.5rem',
|
||||||
|
27: '6.75rem',
|
||||||
|
27.5: '6.875rem',
|
||||||
|
29: '7.25rem',
|
||||||
|
29.5: '7.375rem',
|
||||||
|
30: '7.5rem',
|
||||||
|
31: '7.75rem',
|
||||||
|
32.5: '8.125rem',
|
||||||
|
34: '8.5rem',
|
||||||
|
34.5: '8.625rem',
|
||||||
|
35: '8.75rem',
|
||||||
|
36.5: '9.125rem',
|
||||||
|
37.5: '9.375rem',
|
||||||
|
39: '9.75rem',
|
||||||
|
39.5: '9.875rem',
|
||||||
|
40: '10rem',
|
||||||
|
42.5: '10.625rem',
|
||||||
|
44: '11rem',
|
||||||
|
45: '11.25rem',
|
||||||
|
46: '11.5rem',
|
||||||
|
47.5: '11.875rem',
|
||||||
|
49: '12.25rem',
|
||||||
|
50: '12.5rem',
|
||||||
|
52: '13rem',
|
||||||
|
52.5: '13.125rem',
|
||||||
|
54: '13.5rem',
|
||||||
|
54.5: '13.625rem',
|
||||||
|
55: '13.75rem',
|
||||||
|
55.5: '13.875rem',
|
||||||
|
59: '14.75rem',
|
||||||
|
60: '15rem',
|
||||||
|
62.5: '15.625rem',
|
||||||
|
65: '16.25rem',
|
||||||
|
67: '16.75rem',
|
||||||
|
67.5: '16.875rem',
|
||||||
|
70: '17.5rem',
|
||||||
|
72.5: '18.125rem',
|
||||||
|
73: '18.25rem',
|
||||||
|
75: '18.75rem',
|
||||||
|
90: '22.5rem',
|
||||||
|
94: '23.5rem',
|
||||||
|
95: '23.75rem',
|
||||||
|
100: '25rem',
|
||||||
|
115: '28.75rem',
|
||||||
|
125: '31.25rem',
|
||||||
|
132.5: '33.125rem',
|
||||||
|
150: '37.5rem',
|
||||||
|
171.5: '42.875rem',
|
||||||
|
180: '45rem',
|
||||||
|
187.5: '46.875rem',
|
||||||
|
203: '50.75rem',
|
||||||
|
230: '57.5rem',
|
||||||
|
242.5: '60.625rem'
|
||||||
|
},
|
||||||
|
maxWidth: {
|
||||||
|
2.5: '0.625rem',
|
||||||
|
3: '0.75rem',
|
||||||
|
4: '1rem',
|
||||||
|
11: '2.75rem',
|
||||||
|
13: '3.25rem',
|
||||||
|
14: '3.5rem',
|
||||||
|
15: '3.75rem',
|
||||||
|
22.5: '5.625rem',
|
||||||
|
25: '6.25rem',
|
||||||
|
30: '7.5rem',
|
||||||
|
34: '8.5rem',
|
||||||
|
35: '8.75rem',
|
||||||
|
40: '10rem',
|
||||||
|
42.5: '10.625rem',
|
||||||
|
44: '11rem',
|
||||||
|
45: '11.25rem',
|
||||||
|
60: '15rem',
|
||||||
|
70: '17.5rem',
|
||||||
|
90: '22.5rem',
|
||||||
|
94: '23.5rem',
|
||||||
|
125: '31.25rem',
|
||||||
|
132.5: '33.125rem',
|
||||||
|
142.5: '35.625rem',
|
||||||
|
150: '37.5rem',
|
||||||
|
180: '45rem',
|
||||||
|
203: '50.75rem',
|
||||||
|
230: '57.5rem',
|
||||||
|
242.5: '60.625rem',
|
||||||
|
270: '67.5rem',
|
||||||
|
280: '70rem',
|
||||||
|
292.5: '73.125rem'
|
||||||
|
},
|
||||||
|
maxHeight: {
|
||||||
|
35: '8.75rem',
|
||||||
|
70: '17.5rem',
|
||||||
|
90: '22.5rem',
|
||||||
|
550: '34.375rem',
|
||||||
|
300: '18.75rem'
|
||||||
|
},
|
||||||
|
minWidth: {
|
||||||
|
22.5: '5.625rem',
|
||||||
|
42.5: '10.625rem',
|
||||||
|
47.5: '11.875rem',
|
||||||
|
75: '18.75rem'
|
||||||
|
},
|
||||||
|
zIndex: {
|
||||||
|
999999: '999999',
|
||||||
|
99999: '99999',
|
||||||
|
9999: '9999',
|
||||||
|
999: '999',
|
||||||
|
99: '99',
|
||||||
|
9: '9',
|
||||||
|
1: '1'
|
||||||
|
},
|
||||||
|
opacity: {
|
||||||
|
65: '.65'
|
||||||
|
},
|
||||||
|
transitionProperty: { width: 'width', stroke: 'stroke' },
|
||||||
|
borderWidth: {
|
||||||
|
6: '6px'
|
||||||
|
},
|
||||||
|
boxShadow: {
|
||||||
|
default: '0px 8px 13px -3px rgba(0, 0, 0, 0.07)',
|
||||||
|
card: '0px 1px 3px rgba(0, 0, 0, 0.12)',
|
||||||
|
'card-2': '0px 1px 2px rgba(0, 0, 0, 0.05)',
|
||||||
|
switcher:
|
||||||
|
'0px 2px 4px rgba(0, 0, 0, 0.2), inset 0px 2px 2px #FFFFFF, inset 0px -1px 1px rgba(0, 0, 0, 0.1)',
|
||||||
|
'switch-1': '0px 0px 5px rgba(0, 0, 0, 0.15)',
|
||||||
|
1: '0px 1px 3px rgba(0, 0, 0, 0.08)',
|
||||||
|
2: '0px 1px 4px rgba(0, 0, 0, 0.12)',
|
||||||
|
3: '0px 1px 5px rgba(0, 0, 0, 0.14)',
|
||||||
|
4: '0px 4px 10px rgba(0, 0, 0, 0.12)',
|
||||||
|
5: '0px 1px 1px rgba(0, 0, 0, 0.15)',
|
||||||
|
6: '0px 3px 15px rgba(0, 0, 0, 0.1)',
|
||||||
|
7: '-5px 0 0 #313D4A, 5px 0 0 #313D4A',
|
||||||
|
8: '1px 0 0 #313D4A, -1px 0 0 #313D4A, 0 1px 0 #313D4A, 0 -1px 0 #313D4A, 0 3px 13px rgb(0 0 0 / 8%)'
|
||||||
|
},
|
||||||
|
dropShadow: {
|
||||||
|
1: '0px 1px 0px #E2E8F0',
|
||||||
|
2: '0px 1px 4px rgba(0, 0, 0, 0.12)'
|
||||||
|
},
|
||||||
|
keyframes: {
|
||||||
|
linspin: {
|
||||||
|
'100%': { transform: 'rotate(360deg)' }
|
||||||
|
},
|
||||||
|
easespin: {
|
||||||
|
'12.5%': { transform: 'rotate(135deg)' },
|
||||||
|
'25%': { transform: 'rotate(270deg)' },
|
||||||
|
'37.5%': { transform: 'rotate(405deg)' },
|
||||||
|
'50%': { transform: 'rotate(540deg)' },
|
||||||
|
'62.5%': { transform: 'rotate(675deg)' },
|
||||||
|
'75%': { transform: 'rotate(810deg)' },
|
||||||
|
'87.5%': { transform: 'rotate(945deg)' },
|
||||||
|
'100%': { transform: 'rotate(1080deg)' }
|
||||||
|
},
|
||||||
|
'left-spin': {
|
||||||
|
'0%': { transform: 'rotate(130deg)' },
|
||||||
|
'50%': { transform: 'rotate(-5deg)' },
|
||||||
|
'100%': { transform: 'rotate(130deg)' }
|
||||||
|
},
|
||||||
|
'right-spin': {
|
||||||
|
'0%': { transform: 'rotate(-130deg)' },
|
||||||
|
'50%': { transform: 'rotate(5deg)' },
|
||||||
|
'100%': { transform: 'rotate(-130deg)' }
|
||||||
|
},
|
||||||
|
rotating: {
|
||||||
|
'0%, 100%': { transform: 'rotate(360deg)' },
|
||||||
|
'50%': { transform: 'rotate(0deg)' }
|
||||||
|
},
|
||||||
|
topbottom: {
|
||||||
|
'0%, 100%': { transform: 'translate3d(0, -100%, 0)' },
|
||||||
|
'50%': { transform: 'translate3d(0, 0, 0)' }
|
||||||
|
},
|
||||||
|
bottomtop: {
|
||||||
|
'0%, 100%': { transform: 'translate3d(0, 0, 0)' },
|
||||||
|
'50%': { transform: 'translate3d(0, -100%, 0)' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
animation: {
|
||||||
|
linspin: 'linspin 1568.2353ms linear infinite',
|
||||||
|
easespin: 'easespin 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both',
|
||||||
|
'left-spin': 'left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both',
|
||||||
|
'right-spin': 'right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both',
|
||||||
|
'ping-once': 'ping 5s cubic-bezier(0, 0, 0.2, 1)',
|
||||||
|
rotating: 'rotating 30s linear infinite',
|
||||||
|
topbottom: 'topbottom 60s infinite alternate linear',
|
||||||
|
bottomtop: 'bottomtop 60s infinite alternate linear',
|
||||||
|
'spin-1.5': 'spin 1.5s linear infinite',
|
||||||
|
'spin-2': 'spin 2s linear infinite',
|
||||||
|
'spin-3': 'spin 3s linear infinite'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,3 +2,21 @@
|
|||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
"@vue/reactivity@~3.1.1":
|
||||||
|
version "3.1.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.1.5.tgz#dbec4d9557f7c8f25c2635db1e23a78a729eb991"
|
||||||
|
integrity sha512-1tdfLmNjWG6t/CsPldh+foumYFo3cpyCHgBYQ34ylaMsJ+SNHQ1kApMIa8jN+i593zQuaw3AdWH0nJTARzCFhg==
|
||||||
|
dependencies:
|
||||||
|
"@vue/shared" "3.1.5"
|
||||||
|
|
||||||
|
"@vue/shared@3.1.5":
|
||||||
|
version "3.1.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.1.5.tgz#74ee3aad995d0a3996a6bb9533d4d280514ede03"
|
||||||
|
integrity sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA==
|
||||||
|
|
||||||
|
alpinejs@^3.13.5:
|
||||||
|
version "3.13.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/alpinejs/-/alpinejs-3.13.5.tgz#c06f067e847a295085b4c6f76c42a6a35499d953"
|
||||||
|
integrity sha512-1d2XeNGN+Zn7j4mUAKXtAgdc4/rLeadyTMWeJGXF5DzwawPBxwTiBhFFm6w/Ei8eJxUZeyNWWSD9zknfdz1kEw==
|
||||||
|
dependencies:
|
||||||
|
"@vue/reactivity" "~3.1.1"
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ defmodule Pinchflat.Profiles.MediaProfile do
|
|||||||
|
|
||||||
schema "media_profiles" do
|
schema "media_profiles" do
|
||||||
field :name, :string
|
field :name, :string
|
||||||
field :output_path_template, :string
|
|
||||||
|
field :output_path_template, :string, default: "/{{ uploader }}/{{ title }}.{{ ext }}"
|
||||||
|
|
||||||
field :download_subs, :boolean, default: true
|
field :download_subs, :boolean, default: true
|
||||||
field :download_auto_subs, :boolean, default: true
|
field :download_auto_subs, :boolean, default: true
|
||||||
|
|||||||
@@ -84,8 +84,10 @@ defmodule PinchflatWeb do
|
|||||||
# HTML escaping functionality
|
# HTML escaping functionality
|
||||||
import Phoenix.HTML
|
import Phoenix.HTML
|
||||||
# Core UI components and translation
|
# Core UI components and translation
|
||||||
import PinchflatWeb.CoreComponents
|
|
||||||
import PinchflatWeb.Gettext
|
import PinchflatWeb.Gettext
|
||||||
|
import PinchflatWeb.CoreComponents
|
||||||
|
import PinchflatWeb.CustomComponents.TableComponents
|
||||||
|
import PinchflatWeb.CustomComponents.ButtonComponents
|
||||||
|
|
||||||
# Shortcut for generating JS commands
|
# Shortcut for generating JS commands
|
||||||
alias Phoenix.LiveView.JS
|
alias Phoenix.LiveView.JS
|
||||||
|
|||||||
@@ -201,46 +201,14 @@ defmodule PinchflatWeb.CoreComponents do
|
|||||||
def simple_form(assigns) do
|
def simple_form(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<.form :let={f} for={@for} as={@as} {@rest}>
|
<.form :let={f} for={@for} as={@as} {@rest}>
|
||||||
<div class="mt-10 space-y-8 bg-white">
|
|
||||||
<%= render_slot(@inner_block, f) %>
|
<%= render_slot(@inner_block, f) %>
|
||||||
<div :for={action <- @actions} class="mt-2 flex items-center justify-between gap-6">
|
<div :for={action <- @actions} class="mt-2 flex items-center justify-between gap-6">
|
||||||
<%= render_slot(action, f) %>
|
<%= render_slot(action, f) %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</.form>
|
</.form>
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
|
||||||
Renders a button.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
<.button>Send!</.button>
|
|
||||||
<.button phx-click="go" class="ml-2">Send!</.button>
|
|
||||||
"""
|
|
||||||
attr :type, :string, default: nil
|
|
||||||
attr :class, :string, default: nil
|
|
||||||
attr :rest, :global, include: ~w(disabled form name value)
|
|
||||||
|
|
||||||
slot :inner_block, required: true
|
|
||||||
|
|
||||||
def button(assigns) do
|
|
||||||
~H"""
|
|
||||||
<button
|
|
||||||
type={@type}
|
|
||||||
class={[
|
|
||||||
"phx-submit-loading:opacity-75 rounded-lg bg-zinc-900 hover:bg-zinc-700 py-2 px-3",
|
|
||||||
"text-sm font-semibold leading-6 text-white active:text-white/80",
|
|
||||||
@class
|
|
||||||
]}
|
|
||||||
{@rest}
|
|
||||||
>
|
|
||||||
<%= render_slot(@inner_block) %>
|
|
||||||
</button>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Renders an input with label and error messages.
|
Renders an input with label and error messages.
|
||||||
|
|
||||||
@@ -270,11 +238,12 @@ defmodule PinchflatWeb.CoreComponents do
|
|||||||
attr :name, :any
|
attr :name, :any
|
||||||
attr :label, :string, default: nil
|
attr :label, :string, default: nil
|
||||||
attr :value, :any
|
attr :value, :any
|
||||||
|
attr :help, :string, default: nil
|
||||||
|
|
||||||
attr :type, :string,
|
attr :type, :string,
|
||||||
default: "text",
|
default: "text",
|
||||||
values: ~w(checkbox color date datetime-local email file hidden month number password
|
values: ~w(checkbox color date datetime-local email file hidden month number password
|
||||||
range radio search select tel text textarea time url week)
|
toggle range radio search select tel text textarea time url week)
|
||||||
|
|
||||||
attr :field, Phoenix.HTML.FormField,
|
attr :field, Phoenix.HTML.FormField,
|
||||||
doc: "a form field struct retrieved from the form, for example: @form[:email]"
|
doc: "a form field struct retrieved from the form, for example: @form[:email]"
|
||||||
@@ -308,7 +277,7 @@ defmodule PinchflatWeb.CoreComponents do
|
|||||||
|
|
||||||
~H"""
|
~H"""
|
||||||
<div phx-feedback-for={@name}>
|
<div phx-feedback-for={@name}>
|
||||||
<label class="flex items-center gap-4 text-sm leading-6 text-zinc-600">
|
<label class="flex items-center gap-4 text-sm leading-6">
|
||||||
<input type="hidden" name={@name} value="false" />
|
<input type="hidden" name={@name} value="false" />
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -316,16 +285,54 @@ defmodule PinchflatWeb.CoreComponents do
|
|||||||
name={@name}
|
name={@name}
|
||||||
value="true"
|
value="true"
|
||||||
checked={@checked}
|
checked={@checked}
|
||||||
class="rounded border-zinc-300 text-zinc-900 focus:ring-0"
|
class="rounded focus:ring-0"
|
||||||
{@rest}
|
{@rest}
|
||||||
/>
|
/>
|
||||||
<%= @label %>
|
<%= @label %>
|
||||||
</label>
|
</label>
|
||||||
|
<.help :if={@help}><%= @help %></.help>
|
||||||
<.error :for={msg <- @errors}><%= msg %></.error>
|
<.error :for={msg <- @errors}><%= msg %></.error>
|
||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def input(%{type: "toggle"} = assigns) do
|
||||||
|
assigns =
|
||||||
|
assign_new(assigns, :checked, fn ->
|
||||||
|
Phoenix.HTML.Form.normalize_value("checkbox", assigns[:value])
|
||||||
|
end)
|
||||||
|
|
||||||
|
~H"""
|
||||||
|
<div x-data={"{ enabled: #{@checked}}"}>
|
||||||
|
<.label for={@id}><%= @label %></.label>
|
||||||
|
<div class="relative">
|
||||||
|
<input type="hidden" name={@name} value="false" />
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
id={@id}
|
||||||
|
name={@name}
|
||||||
|
value="true"
|
||||||
|
x-bind:checked="enabled"
|
||||||
|
class="sr-only"
|
||||||
|
@change="enabled = !enabled"
|
||||||
|
{@rest}
|
||||||
|
/>
|
||||||
|
<div class="inline-block cursor-pointer" @click="enabled = !enabled">
|
||||||
|
<div x-bind:class="enabled && '!bg-primary'" class="block h-8 w-14 rounded-full bg-black">
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
x-bind:class="enabled && '!right-1 !translate-x-full'"
|
||||||
|
class="absolute left-1 top-1 flex h-6 w-6 items-center justify-center rounded-full bg-white transition"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<.help :if={@help}><%= @help %></.help>
|
||||||
|
<.error :for={msg <- @errors}><%= msg %></.error>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
def input(%{type: "select"} = assigns) do
|
def input(%{type: "select"} = assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<div phx-feedback-for={@name}>
|
<div phx-feedback-for={@name}>
|
||||||
@@ -333,13 +340,17 @@ defmodule PinchflatWeb.CoreComponents do
|
|||||||
<select
|
<select
|
||||||
id={@id}
|
id={@id}
|
||||||
name={@name}
|
name={@name}
|
||||||
class="mt-2 block w-full rounded-md border border-gray-300 bg-white shadow-sm focus:border-zinc-400 focus:ring-0 sm:text-sm"
|
class={[
|
||||||
|
"relative z-20 w-full appearance-none rounded border border-stroke bg-transparent py-3 pl-5 pr-12 outline-none transition",
|
||||||
|
"focus:border-primary active:border-primary dark:border-form-strokedark dark:bg-form-input text-black dark:text-white"
|
||||||
|
]}
|
||||||
multiple={@multiple}
|
multiple={@multiple}
|
||||||
{@rest}
|
{@rest}
|
||||||
>
|
>
|
||||||
<option :if={@prompt} value=""><%= @prompt %></option>
|
<option :if={@prompt} value=""><%= @prompt %></option>
|
||||||
<%= Phoenix.HTML.Form.options_for_select(@options, @value) %>
|
<%= Phoenix.HTML.Form.options_for_select(@options, @value) %>
|
||||||
</select>
|
</select>
|
||||||
|
<.help :if={@help}><%= @help %></.help>
|
||||||
<.error :for={msg <- @errors}><%= msg %></.error>
|
<.error :for={msg <- @errors}><%= msg %></.error>
|
||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
@@ -360,6 +371,7 @@ defmodule PinchflatWeb.CoreComponents do
|
|||||||
]}
|
]}
|
||||||
{@rest}
|
{@rest}
|
||||||
><%= Phoenix.HTML.Form.normalize_value("textarea", @value) %></textarea>
|
><%= Phoenix.HTML.Form.normalize_value("textarea", @value) %></textarea>
|
||||||
|
<.help :if={@help}><%= @help %></.help>
|
||||||
<.error :for={msg <- @errors}><%= msg %></.error>
|
<.error :for={msg <- @errors}><%= msg %></.error>
|
||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
@@ -376,18 +388,32 @@ defmodule PinchflatWeb.CoreComponents do
|
|||||||
id={@id}
|
id={@id}
|
||||||
value={Phoenix.HTML.Form.normalize_value(@type, @value)}
|
value={Phoenix.HTML.Form.normalize_value(@type, @value)}
|
||||||
class={[
|
class={[
|
||||||
"mt-2 block w-full rounded-lg text-zinc-900 focus:ring-0 sm:text-sm sm:leading-6",
|
"w-full rounded-lg border-[1.5px] border-stroke bg-transparent px-5 py-3 font-normal text-black",
|
||||||
"phx-no-feedback:border-zinc-300 phx-no-feedback:focus:border-zinc-400",
|
"outline-none transition focus:border-primary active:border-primary disabled:cursor-default disabled:bg-whiter",
|
||||||
@errors == [] && "border-zinc-300 focus:border-zinc-400",
|
"dark:border-form-strokedark dark:bg-form-input dark:text-white dark:focus:border-primary",
|
||||||
@errors != [] && "border-rose-400 focus:border-rose-400"
|
@errors != [] && "border-rose-400 focus:border-rose-400"
|
||||||
]}
|
]}
|
||||||
{@rest}
|
{@rest}
|
||||||
/>
|
/>
|
||||||
|
<.help :if={@help}><%= @help %></.help>
|
||||||
<.error :for={msg <- @errors}><%= msg %></.error>
|
<.error :for={msg <- @errors}><%= msg %></.error>
|
||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Renders help text.
|
||||||
|
"""
|
||||||
|
slot :inner_block, required: true
|
||||||
|
|
||||||
|
def help(assigns) do
|
||||||
|
~H"""
|
||||||
|
<p class="mt-1 text-sm leading-5">
|
||||||
|
<%= render_slot(@inner_block) %>
|
||||||
|
</p>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Renders a label.
|
Renders a label.
|
||||||
"""
|
"""
|
||||||
@@ -396,7 +422,7 @@ defmodule PinchflatWeb.CoreComponents do
|
|||||||
|
|
||||||
def label(assigns) do
|
def label(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<label for={@for} class="block text-sm font-semibold leading-6 text-zinc-800">
|
<label for={@for} class="mt-5 mb-2 block text-md font-medium text-black dark:text-white">
|
||||||
<%= render_slot(@inner_block) %>
|
<%= render_slot(@inner_block) %>
|
||||||
</label>
|
</label>
|
||||||
"""
|
"""
|
||||||
@@ -409,7 +435,7 @@ defmodule PinchflatWeb.CoreComponents do
|
|||||||
|
|
||||||
def error(assigns) do
|
def error(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<p class="mt-3 flex gap-3 text-sm leading-6 text-rose-600 phx-no-feedback:hidden">
|
<p class="mt-1 mb-5 flex gap-3 text-md leading-6 text-rose-600 phx-no-feedback:hidden">
|
||||||
<.icon name="hero-exclamation-circle-mini" class="mt-0.5 h-5 w-5 flex-none" />
|
<.icon name="hero-exclamation-circle-mini" class="mt-0.5 h-5 w-5 flex-none" />
|
||||||
<%= render_slot(@inner_block) %>
|
<%= render_slot(@inner_block) %>
|
||||||
</p>
|
</p>
|
||||||
@@ -425,7 +451,7 @@ defmodule PinchflatWeb.CoreComponents do
|
|||||||
slot :subtitle
|
slot :subtitle
|
||||||
slot :actions
|
slot :actions
|
||||||
|
|
||||||
def header(assigns) do
|
def old_header(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<header class={[@actions != [] && "flex items-center justify-between gap-6", @class]}>
|
<header class={[@actions != [] && "flex items-center justify-between gap-6", @class]}>
|
||||||
<div>
|
<div>
|
||||||
@@ -446,10 +472,10 @@ defmodule PinchflatWeb.CoreComponents do
|
|||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
<.table id="users" rows={@users}>
|
<.old_table id="users" rows={@users}>
|
||||||
<:col :let={user} label="id"><%= user.id %></:col>
|
<:col :let={user} label="id"><%= user.id %></:col>
|
||||||
<:col :let={user} label="username"><%= user.username %></:col>
|
<:col :let={user} label="username"><%= user.username %></:col>
|
||||||
</.table>
|
</.old_table>
|
||||||
"""
|
"""
|
||||||
attr :id, :string, required: true
|
attr :id, :string, required: true
|
||||||
attr :rows, :list, required: true
|
attr :rows, :list, required: true
|
||||||
@@ -466,14 +492,13 @@ defmodule PinchflatWeb.CoreComponents do
|
|||||||
|
|
||||||
slot :action, doc: "the slot for showing user actions in the last table column"
|
slot :action, doc: "the slot for showing user actions in the last table column"
|
||||||
|
|
||||||
def table(assigns) do
|
def old_table(assigns) do
|
||||||
assigns =
|
assigns =
|
||||||
with %{rows: %Phoenix.LiveView.LiveStream{}} <- assigns do
|
with %{rows: %Phoenix.LiveView.LiveStream{}} <- assigns do
|
||||||
assign(assigns, row_id: assigns.row_id || fn {id, _item} -> id end)
|
assign(assigns, row_id: assigns.row_id || fn {id, _item} -> id end)
|
||||||
end
|
end
|
||||||
|
|
||||||
~H"""
|
~H"""
|
||||||
<div class="overflow-y-auto px-4 sm:overflow-visible sm:px-0">
|
|
||||||
<table class="w-[40rem] mt-11 sm:w-full">
|
<table class="w-[40rem] mt-11 sm:w-full">
|
||||||
<thead class="text-sm text-left leading-6 text-zinc-500">
|
<thead class="text-sm text-left leading-6 text-zinc-500">
|
||||||
<tr>
|
<tr>
|
||||||
@@ -515,7 +540,6 @@ defmodule PinchflatWeb.CoreComponents do
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -536,10 +560,10 @@ defmodule PinchflatWeb.CoreComponents do
|
|||||||
def list(assigns) do
|
def list(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<div class="mt-2 mb-14">
|
<div class="mt-2 mb-14">
|
||||||
<dl class="-my-4 divide-y divide-zinc-100">
|
<dl class="-my-4 divide-y dark:divide-strokedark">
|
||||||
<div :for={item <- @item} class="flex gap-4 py-4 text-sm leading-6 sm:gap-8">
|
<div :for={item <- @item} class="flex gap-4 py-4 text-sm leading-6 sm:gap-8">
|
||||||
<dt class="w-1/4 flex-none text-zinc-500"><%= item.title %></dt>
|
<dt class="w-1/4 flex-none dark:text-white"><%= item.title %></dt>
|
||||||
<dd class="text-zinc-700"><%= render_slot(item) %></dd>
|
<dd class="dark:text-white"><%= render_slot(item) %></dd>
|
||||||
</div>
|
</div>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
defmodule PinchflatWeb.CustomComponents.ButtonComponents do
|
||||||
|
@moduledoc false
|
||||||
|
use Phoenix.Component
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Render a button
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
<.button color="bg-primary" rounding="rounded-sm">
|
||||||
|
<span>Click me</span>
|
||||||
|
</.button>
|
||||||
|
"""
|
||||||
|
attr :color, :string, default: "bg-primary"
|
||||||
|
attr :rounding, :string, default: "rounded-sm"
|
||||||
|
attr :class, :string, default: ""
|
||||||
|
|
||||||
|
slot :inner_block, required: true
|
||||||
|
|
||||||
|
def button(assigns) do
|
||||||
|
~H"""
|
||||||
|
<button class={[
|
||||||
|
"text-center font-medium text-white",
|
||||||
|
"#{@rounding} inline-flex items-center justify-center px-10 py-4",
|
||||||
|
"#{@color}",
|
||||||
|
"hover:bg-opacity-90 lg:px-8 xl:px-10",
|
||||||
|
@class
|
||||||
|
]}>
|
||||||
|
<%= render_slot(@inner_block) %>
|
||||||
|
</button>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
defmodule PinchflatWeb.CustomComponents.TableComponents do
|
||||||
|
@moduledoc false
|
||||||
|
use Phoenix.Component
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Renders a table component with the given rows and columns.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
<.table rows={@users}>
|
||||||
|
<:col :let={user} label="Name"><%= user.name %></:col>
|
||||||
|
</.table>
|
||||||
|
"""
|
||||||
|
attr :rows, :list, required: true
|
||||||
|
attr :table_class, :string, default: ""
|
||||||
|
|
||||||
|
attr :row_item, :any,
|
||||||
|
default: &Function.identity/1,
|
||||||
|
doc: "the function for mapping each row before calling the :col and :action slots"
|
||||||
|
|
||||||
|
slot :col, required: true do
|
||||||
|
attr :label, :string
|
||||||
|
attr :class, :string
|
||||||
|
end
|
||||||
|
|
||||||
|
def table(assigns) do
|
||||||
|
~H"""
|
||||||
|
<table class={["w-full table-auto", @table_class]}>
|
||||||
|
<thead>
|
||||||
|
<tr class="bg-gray-2 text-left dark:bg-meta-4">
|
||||||
|
<th :for={col <- @col} class="px-4 py-4 font-medium text-black dark:text-white xl:pl-11">
|
||||||
|
<%= col[:label] %>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr :for={{row, i} <- Enum.with_index(@rows)}>
|
||||||
|
<td
|
||||||
|
:for={col <- @col}
|
||||||
|
class={[
|
||||||
|
"px-4 py-5 pl-9 dark:border-strokedark xl:pl-11",
|
||||||
|
i + 1 > length(@rows) && "border-b border-[#eee] dark:border-π",
|
||||||
|
col[:class]
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<%= render_slot(col, @row_item.(row)) %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -2,4 +2,28 @@ defmodule PinchflatWeb.Layouts do
|
|||||||
use PinchflatWeb, :html
|
use PinchflatWeb, :html
|
||||||
|
|
||||||
embed_templates "layouts/*"
|
embed_templates "layouts/*"
|
||||||
|
embed_templates "layouts/partials/*"
|
||||||
|
|
||||||
|
attr :icon, :string, required: true
|
||||||
|
attr :text, :string, required: true
|
||||||
|
attr :navigate, :any, required: true
|
||||||
|
|
||||||
|
def sidebar_item(assigns) do
|
||||||
|
# I'm testing out grouping classes here. Tentative order: font, layout, color, animation, state-modifiers
|
||||||
|
~H"""
|
||||||
|
<li>
|
||||||
|
<.link
|
||||||
|
navigate={@navigate}
|
||||||
|
class={[
|
||||||
|
"font-medium text-bodydark1",
|
||||||
|
"group relative flex items-center gap-2.5 rounded-sm px-4 py-2 duration-300 ease-in-out",
|
||||||
|
"duration-300 ease-in-out",
|
||||||
|
"hover:bg-graydark dark:hover:bg-meta-4"
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<.icon name={@icon} /> <%= @text %>
|
||||||
|
</.link>
|
||||||
|
</li>
|
||||||
|
"""
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,32 +1,13 @@
|
|||||||
<header class="px-4 sm:px-6 lg:px-8">
|
<div class="flex h-screen overflow-hidden">
|
||||||
<div class="flex items-center justify-between border-b border-zinc-100 py-3 text-sm">
|
<.sidebar />
|
||||||
<div class="flex items-center gap-4">
|
|
||||||
<a href="/">
|
<div class="relative flex flex-1 flex-col overflow-y-auto overflow-x-hidden">
|
||||||
<img src={~p"/images/logo.svg"} width="36" />
|
<.header />
|
||||||
</a>
|
<main>
|
||||||
<p class="bg-brand/5 text-brand rounded-full px-2 font-medium leading-6">
|
<div class="mx-auto max-w-screen-2xl p-4 md:p-6 2xl:p-10">
|
||||||
v<%= Application.spec(:phoenix, :vsn) %>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center gap-4 font-semibold leading-6 text-zinc-900">
|
|
||||||
<a href="https://twitter.com/elixirphoenix" class="hover:text-zinc-700">
|
|
||||||
@elixirphoenix
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/phoenixframework/phoenix" class="hover:text-zinc-700">
|
|
||||||
GitHub
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
href="https://hexdocs.pm/phoenix/overview.html"
|
|
||||||
class="rounded-lg bg-zinc-100 px-2 py-1 hover:bg-zinc-200/80"
|
|
||||||
>
|
|
||||||
Get Started <span aria-hidden="true">→</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<main class="px-4 py-20 sm:px-6 lg:px-8">
|
|
||||||
<div class="mx-auto max-w-2xl">
|
|
||||||
<.flash_group flash={@flash} />
|
<.flash_group flash={@flash} />
|
||||||
<%= @inner_content %>
|
<%= @inner_content %>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<header class="sticky top-0 z-999 flex w-full bg-white drop-shadow-1 dark:bg-boxdark dark:drop-shadow-none">
|
||||||
|
<div class="flex flex-grow items-center justify-end px-4 py-4 shadow-2 md:px-6 2xl:px-11">
|
||||||
|
<div class="flex items-center gap-2 sm:gap-4 lg:hidden">
|
||||||
|
<button
|
||||||
|
class="z-99999 block rounded-sm border border-stroke bg-white p-1.5 shadow-sm dark:border-strokedark dark:bg-boxdark lg:hidden"
|
||||||
|
@click.stop="sidebarToggle = !sidebarToggle"
|
||||||
|
>
|
||||||
|
<.icon name="hero-bars-3" />
|
||||||
|
</button>
|
||||||
|
<a class="block flex-shrink-0 lg:hidden" href="#">
|
||||||
|
<h2 class="text-title-md2 font-bold text-white">Pinchflat</h2>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="hidden sm:block bg-meta-4 rounded-md">
|
||||||
|
<%!-- Aspirational (for now) --%>
|
||||||
|
<div class="relative">
|
||||||
|
<span class="absolute left-2 top-1/2 -translate-y-1/2 flex">
|
||||||
|
<.icon name="hero-magnifying-glass" />
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Type to search..."
|
||||||
|
class="w-full bg-transparent pl-9 pr-4 border-0 focus:ring-0 focus:outline-none xl:w-125"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<aside
|
||||||
|
x-bind:class="sidebarToggle ? 'translate-x-0' : '-translate-x-full'"
|
||||||
|
class="absolute left-0 top-0 z-9999 flex h-screen w-72.5 flex-col overflow-y-hidden bg-black duration-300 ease-linear dark:bg-boxdark lg:static lg:translate-x-0"
|
||||||
|
@click.outside="sidebarToggle = false"
|
||||||
|
>
|
||||||
|
<div class="flex items-center justify-between gap-2 px-6 py-5.5 lg:py-6.5">
|
||||||
|
<h2 class="text-title-md2 font-bold text-white">Pinchflat</h2>
|
||||||
|
|
||||||
|
<button class="block lg:hidden" @click.stop="sidebarToggle = !sidebarToggle">
|
||||||
|
<.icon name="hero-arrow-left" class="fill-current" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="no-scrollbar flex flex-col overflow-y-auto duration-300 ease-linear">
|
||||||
|
<nav class="mt-5 px-4 py-4 lg:mt-9 lg:px-6">
|
||||||
|
<div>
|
||||||
|
<h3 class="mb-4 ml-4 text-sm font-medium text-bodydark2">MENU</h3>
|
||||||
|
<ul class="mb-6 flex flex-col gap-1.5">
|
||||||
|
<.sidebar_item icon="hero-tv" text="Sources" navigate={~p"/sources"} />
|
||||||
|
|
||||||
|
<.sidebar_item
|
||||||
|
icon="hero-adjustments-vertical"
|
||||||
|
text="Media Profiles"
|
||||||
|
navigate={~p"/media_profiles"}
|
||||||
|
/>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en" class="[scrollbar-gutter:stable]">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
<script defer phx-track-static type="text/javascript" src={~p"/assets/app.js"}>
|
<script defer phx-track-static type="text/javascript" src={~p"/assets/app.js"}>
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-white antialiased">
|
<body x-data="{ 'sidebarToggle': false }" class="dark text-bodydark bg-boxdark-2">
|
||||||
<%= @inner_content %>
|
<%= @inner_content %>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
<.header>
|
<div class="mb-6 flex gap-3 flex-row items-center">
|
||||||
Edit Media profile <%= @media_profile.id %>
|
<.link navigate={~p"/media_profiles"}>
|
||||||
<:subtitle>Use this form to manage media_profile records in your database.</:subtitle>
|
<.icon name="hero-arrow-left" class="w-10 h-10 hover:dark:text-white" />
|
||||||
</.header>
|
</.link>
|
||||||
|
<h2 class="text-title-md2 font-bold text-black dark:text-white ml-4">Edit Media Profile</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
<.media_profile_form changeset={@changeset} action={~p"/media_profiles/#{@media_profile}"} />
|
<div class="rounded-sm border border-stroke bg-white px-5 pb-2.5 pt-6 shadow-default dark:border-strokedark dark:bg-boxdark sm:px-7.5 xl:pb-1">
|
||||||
|
<div class="max-w-full overflow-x-auto">
|
||||||
<.back navigate={~p"/media_profiles"}>Back to media_profiles</.back>
|
<div class="flex flex-col gap-10">
|
||||||
|
<.media_profile_form changeset={@changeset} action={~p"/media_profiles/#{@media_profile}"} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -1,30 +1,39 @@
|
|||||||
<.header>
|
<div class="mb-6 flex gap-3 flex-row items-center justify-between">
|
||||||
Listing Media profiles
|
<h2 class="text-title-md2 font-bold text-black dark:text-white">All Media Profiles</h2>
|
||||||
<:actions>
|
<nav>
|
||||||
<.link href={~p"/media_profiles/new"}>
|
<.link navigate={~p"/media_profiles/new"}>
|
||||||
<.button>New Media profile</.button>
|
<.button color="bg-primary" rounding="rounded-full">
|
||||||
|
<span class="font-bold mx-2">+</span> New Media Profile
|
||||||
|
</.button>
|
||||||
</.link>
|
</.link>
|
||||||
</:actions>
|
</nav>
|
||||||
</.header>
|
</div>
|
||||||
|
|
||||||
<.table
|
<div class="rounded-sm border border-stroke bg-white shadow-default dark:border-strokedark dark:bg-boxdark">
|
||||||
id="media_profiles"
|
<div class="max-w-full overflow-x-auto">
|
||||||
rows={@media_profiles}
|
<div class="flex flex-col gap-10">
|
||||||
row_click={&JS.navigate(~p"/media_profiles/#{&1}")}
|
<.table rows={@media_profiles} table_class="text-black dark:text-white">
|
||||||
>
|
<:col :let={media_profile} label="Name">
|
||||||
<:col :let={media_profile} label="Name"><%= media_profile.name %></:col>
|
<%= media_profile.name %>
|
||||||
<:col :let={media_profile} label="Output path template">
|
|
||||||
<%= media_profile.output_path_template %>
|
|
||||||
</:col>
|
</:col>
|
||||||
<:action :let={media_profile}>
|
<:col :let={media_profile} label="Output Template">
|
||||||
<div class="sr-only">
|
<code class="text-sm"><%= media_profile.output_path_template %></code>
|
||||||
<.link navigate={~p"/media_profiles/#{media_profile}"}>Show</.link>
|
</:col>
|
||||||
</div>
|
<:col :let={media_profile} label="" class="flex place-content-evenly">
|
||||||
<.link navigate={~p"/media_profiles/#{media_profile}/edit"}>Edit</.link>
|
<.link
|
||||||
</:action>
|
navigate={~p"/media_profiles/#{media_profile.id}"}
|
||||||
<:action :let={media_profile}>
|
class="hover:text-secondary duration-200 ease-in-out mx-0.5"
|
||||||
<.link href={~p"/media_profiles/#{media_profile}"} method="delete" data-confirm="Are you sure?">
|
>
|
||||||
Delete
|
<.icon name="hero-eye" />
|
||||||
</.link>
|
</.link>
|
||||||
</:action>
|
<.link
|
||||||
</.table>
|
navigate={~p"/media_profiles/#{media_profile.id}/edit"}
|
||||||
|
class="hover:text-secondary duration-200 ease-in-out mx-0.5"
|
||||||
|
>
|
||||||
|
<.icon name="hero-pencil-square" />
|
||||||
|
</.link>
|
||||||
|
</:col>
|
||||||
|
</.table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
+48
-15
@@ -2,29 +2,62 @@
|
|||||||
<.error :if={@changeset.action}>
|
<.error :if={@changeset.action}>
|
||||||
Oops, something went wrong! Please check the errors below.
|
Oops, something went wrong! Please check the errors below.
|
||||||
</.error>
|
</.error>
|
||||||
<.input field={f[:name]} type="text" label="Name" />
|
<h3 class="my-4 text-2xl text-black dark:text-white">
|
||||||
<.input field={f[:output_path_template]} type="text" label="Output path template" />
|
General Options
|
||||||
|
</h3>
|
||||||
|
<.input field={f[:name]} type="text" label="Name" placeholder="New Profile" help="(required)" />
|
||||||
|
<.input
|
||||||
|
field={f[:output_path_template]}
|
||||||
|
type="text"
|
||||||
|
label="Output path template"
|
||||||
|
help="TODO: provide docs (required)"
|
||||||
|
/>
|
||||||
|
|
||||||
<h3>Subtitle Options</h3>
|
<h3 class="mb-4 mt-8 text-2xl text-black dark:text-white">
|
||||||
<.input field={f[:download_subs]} type="checkbox" label="Download Subs" />
|
Subtitle Options
|
||||||
<.input field={f[:download_auto_subs]} type="checkbox" label="Download Autogenerated Subs" />
|
</h3>
|
||||||
<.input field={f[:embed_subs]} type="checkbox" label="Embed Subs" />
|
<.input field={f[:download_subs]} type="toggle" label="Download Subtitles" />
|
||||||
<.input field={f[:sub_langs]} type="text" label="Sub Langs" />
|
<.input
|
||||||
|
field={f[:download_auto_subs]}
|
||||||
|
type="toggle"
|
||||||
|
label="Download Autogenerated Subtitles"
|
||||||
|
help="Prefers normal subs but will download autogenerated if needed"
|
||||||
|
/>
|
||||||
|
<.input
|
||||||
|
field={f[:embed_subs]}
|
||||||
|
type="toggle"
|
||||||
|
label="Embed Subtitles"
|
||||||
|
help="Embeds subtitles in the video file itself, if supported"
|
||||||
|
/>
|
||||||
|
<.input
|
||||||
|
field={f[:sub_langs]}
|
||||||
|
type="text"
|
||||||
|
label="Subtitle Languages"
|
||||||
|
help="Use commas for multiple languages (eg: en,de)"
|
||||||
|
/>
|
||||||
|
|
||||||
<h3>Thumbnail Options</h3>
|
<h3 class="mb-4 mt-8 text-2xl text-black dark:text-white">
|
||||||
<.input field={f[:download_thumbnail]} type="checkbox" label="Download Thumbnail" />
|
Thumbnail Options
|
||||||
<.input field={f[:embed_thumbnail]} type="checkbox" label="Embed Thumbnail" />
|
</h3>
|
||||||
|
<.input field={f[:download_thumbnail]} type="toggle" label="Download Thumbnail" />
|
||||||
|
<.input field={f[:embed_thumbnail]} type="toggle" label="Embed Thumbnail" />
|
||||||
|
|
||||||
<h3>Metadata Options</h3>
|
<h3 class="mb-4 mt-8 text-2xl text-black dark:text-white">
|
||||||
<.input field={f[:download_metadata]} type="checkbox" label="Download Metadata" />
|
Metadata Options
|
||||||
<.input field={f[:embed_metadata]} type="checkbox" label="Embed Metadata" />
|
</h3>
|
||||||
|
<.input field={f[:download_metadata]} type="toggle" label="Download Metadata" />
|
||||||
|
<.input field={f[:embed_metadata]} type="toggle" label="Embed Metadata" />
|
||||||
|
|
||||||
|
<h3 class="mb-4 mt-8 text-2xl text-black dark:text-white">
|
||||||
|
Release Format Options
|
||||||
|
</h3>
|
||||||
|
|
||||||
<h3>Release Format Options</h3>
|
|
||||||
<.input
|
<.input
|
||||||
field={f[:shorts_behaviour]}
|
field={f[:shorts_behaviour]}
|
||||||
options={friendly_format_type_options()}
|
options={friendly_format_type_options()}
|
||||||
type="select"
|
type="select"
|
||||||
label="Include Shorts?"
|
label="Include Shorts?"
|
||||||
|
help="Experimental"
|
||||||
/>
|
/>
|
||||||
<.input
|
<.input
|
||||||
field={f[:livestream_behaviour]}
|
field={f[:livestream_behaviour]}
|
||||||
@@ -34,6 +67,6 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<:actions>
|
<:actions>
|
||||||
<.button>Save Media profile</.button>
|
<.button class="mt-15 mb-5 sm:mb-7.5">Save Media profile</.button>
|
||||||
</:actions>
|
</:actions>
|
||||||
</.simple_form>
|
</.simple_form>
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
<.header>
|
<div class="mb-6 flex gap-3 flex-row items-center">
|
||||||
New Media profile
|
<.link navigate={~p"/media_profiles"}>
|
||||||
<:subtitle>Use this form to manage media_profile records in your database.</:subtitle>
|
<.icon name="hero-arrow-left" class="w-10 h-10 hover:dark:text-white" />
|
||||||
</.header>
|
</.link>
|
||||||
|
<h2 class="text-title-md2 font-bold text-black dark:text-white ml-4">New Media Profile</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
<.media_profile_form changeset={@changeset} action={~p"/media_profiles"} />
|
<div class="rounded-sm border border-stroke bg-white px-5 pb-2.5 pt-6 shadow-default dark:border-strokedark dark:bg-boxdark sm:px-7.5 xl:pb-1">
|
||||||
|
<div class="max-w-full overflow-x-auto">
|
||||||
<.back navigate={~p"/media_profiles"}>Back to media_profiles</.back>
|
<div class="flex flex-col gap-10">
|
||||||
|
<.media_profile_form changeset={@changeset} action={~p"/media_profiles"} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -1,13 +1,26 @@
|
|||||||
<.header>
|
<div class="mb-6 flex gap-3 flex-row items-center justify-between">
|
||||||
Media profile <%= @media_profile.id %>
|
<div class="flex gap-3 items-center">
|
||||||
<:subtitle>This is a media_profile record from your database.</:subtitle>
|
<.link navigate={~p"/media_profiles"}>
|
||||||
<:actions>
|
<.icon name="hero-arrow-left" class="w-10 h-10 hover:dark:text-white" />
|
||||||
<.link href={~p"/media_profiles/#{@media_profile}/edit"}>
|
|
||||||
<.button>Edit media_profile</.button>
|
|
||||||
</.link>
|
</.link>
|
||||||
</:actions>
|
<h2 class="text-title-md2 font-bold text-black dark:text-white ml-4">
|
||||||
</.header>
|
Media Profile #<%= @media_profile.id %>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
<.list_items_from_map map={Map.from_struct(@media_profile)} />
|
<nav>
|
||||||
|
<.link navigate={~p"/media_profiles/#{@media_profile}/edit"}>
|
||||||
<.back navigate={~p"/media_profiles"}>Back to media_profiles</.back>
|
<.button color="bg-primary" rounding="rounded-full">
|
||||||
|
<.icon name="hero-pencil-square" class="mr-2" /> Edit Media Profile
|
||||||
|
</.button>
|
||||||
|
</.link>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
<div class="rounded-sm border border-stroke bg-white px-5 pb-2.5 pt-6 shadow-default dark:border-strokedark dark:bg-boxdark sm:px-7.5 xl:pb-1">
|
||||||
|
<div class="max-w-full overflow-x-auto">
|
||||||
|
<div class="flex flex-col gap-10 dark:text-white">
|
||||||
|
<h3 class="font-bold text-xl">Attributes</h3>
|
||||||
|
<.list_items_from_map map={Map.from_struct(@media_profile)} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ defmodule PinchflatWeb.MediaSources.SourceController do
|
|||||||
alias Pinchflat.MediaSource.Source
|
alias Pinchflat.MediaSource.Source
|
||||||
|
|
||||||
def index(conn, _params) do
|
def index(conn, _params) do
|
||||||
sources = MediaSource.list_sources()
|
sources = Repo.preload(MediaSource.list_sources(), :media_profile)
|
||||||
|
|
||||||
render(conn, :index, sources: sources)
|
render(conn, :index, sources: sources)
|
||||||
end
|
end
|
||||||
@@ -23,7 +23,7 @@ defmodule PinchflatWeb.MediaSources.SourceController do
|
|||||||
{:ok, source} ->
|
{:ok, source} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Source created successfully.")
|
|> put_flash(:info, "Source created successfully.")
|
||||||
|> redirect(to: ~p"/media_sources/sources/#{source}")
|
|> redirect(to: ~p"/sources/#{source}")
|
||||||
|
|
||||||
{:error, %Ecto.Changeset{} = changeset} ->
|
{:error, %Ecto.Changeset{} = changeset} ->
|
||||||
render(conn, :new, changeset: changeset, media_profiles: media_profiles())
|
render(conn, :new, changeset: changeset, media_profiles: media_profiles())
|
||||||
@@ -53,7 +53,7 @@ defmodule PinchflatWeb.MediaSources.SourceController do
|
|||||||
{:ok, source} ->
|
{:ok, source} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Source updated successfully.")
|
|> put_flash(:info, "Source updated successfully.")
|
||||||
|> redirect(to: ~p"/media_sources/sources/#{source}")
|
|> redirect(to: ~p"/sources/#{source}")
|
||||||
|
|
||||||
{:error, %Ecto.Changeset{} = changeset} ->
|
{:error, %Ecto.Changeset{} = changeset} ->
|
||||||
render(conn, :edit,
|
render(conn, :edit,
|
||||||
@@ -70,7 +70,7 @@ defmodule PinchflatWeb.MediaSources.SourceController do
|
|||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Source deleted successfully.")
|
|> put_flash(:info, "Source deleted successfully.")
|
||||||
|> redirect(to: ~p"/media_sources/sources")
|
|> redirect(to: ~p"/sources")
|
||||||
end
|
end
|
||||||
|
|
||||||
defp media_profiles do
|
defp media_profiles do
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
<.header>
|
<div class="mb-6 flex gap-3 flex-row items-center">
|
||||||
Edit Source <%= @source.id %>
|
<.link navigate={~p"/sources"}>
|
||||||
<:subtitle>Use this form to manage source records in your database.</:subtitle>
|
<.icon name="hero-arrow-left" class="w-10 h-10 hover:dark:text-white" />
|
||||||
</.header>
|
</.link>
|
||||||
|
<h2 class="text-title-md2 font-bold text-black dark:text-white ml-4">Edit Source</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
<.source_form
|
<div class="rounded-sm border border-stroke bg-white px-5 pb-2.5 pt-6 shadow-default dark:border-strokedark dark:bg-boxdark sm:px-7.5 xl:pb-1">
|
||||||
|
<div class="max-w-full overflow-x-auto">
|
||||||
|
<div class="flex flex-col gap-10">
|
||||||
|
<.source_form
|
||||||
changeset={@changeset}
|
changeset={@changeset}
|
||||||
media_profiles={@media_profiles}
|
media_profiles={@media_profiles}
|
||||||
action={~p"/media_sources/sources/#{@source}"}
|
action={~p"/sources/#{@source}"}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
<.back navigate={~p"/media_sources/sources"}>Back to sources</.back>
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -1,24 +1,48 @@
|
|||||||
<.header>
|
<div class="mb-6 flex gap-3 flex-row items-center justify-between">
|
||||||
Listing Sources
|
<h2 class="text-title-md2 font-bold text-black dark:text-white">All Sources</h2>
|
||||||
<:actions>
|
<nav>
|
||||||
<.link href={~p"/media_sources/sources/new"}>
|
<.link navigate={~p"/sources/new"}>
|
||||||
<.button>New Source</.button>
|
<.button color="bg-primary" rounding="rounded-full">
|
||||||
|
<span class="font-bold mx-2">+</span> New Source
|
||||||
|
</.button>
|
||||||
</.link>
|
</.link>
|
||||||
</:actions>
|
</nav>
|
||||||
</.header>
|
</div>
|
||||||
|
|
||||||
<.table id="sources" rows={@sources} row_click={&JS.navigate(~p"/media_sources/sources/#{&1}")}>
|
<div class="rounded-sm border border-stroke bg-white shadow-default dark:border-strokedark dark:bg-boxdark">
|
||||||
<:col :let={source} label="Collection Name"><%= source.collection_name %></:col>
|
<div class="max-w-full overflow-x-auto">
|
||||||
<:col :let={source} label="Collection ID"><%= source.collection_id %></:col>
|
<div class="flex flex-col gap-10">
|
||||||
<:action :let={source}>
|
<.table rows={@sources} table_class="text-black dark:text-white">
|
||||||
<div class="sr-only">
|
<:col :let={source} label="Name">
|
||||||
<.link navigate={~p"/media_sources/sources/#{source}"}>Show</.link>
|
<%= source.friendly_name || source.collection_name %>
|
||||||
</div>
|
</:col>
|
||||||
<.link navigate={~p"/media_sources/sources/#{source}/edit"}>Edit</.link>
|
<:col :let={source} label="Type"><%= source.collection_type %></:col>
|
||||||
</:action>
|
<:col :let={source} label="Should Download?">
|
||||||
<:action :let={source}>
|
<.icon name={if source.download_media, do: "hero-check", else: "hero-x-mark"} />
|
||||||
<.link href={~p"/media_sources/sources/#{source}"} method="delete" data-confirm="Are you sure?">
|
</:col>
|
||||||
Delete
|
<:col :let={source} label="Media Profile">
|
||||||
|
<.link
|
||||||
|
navigate={~p"/media_profiles/#{source.media_profile_id}"}
|
||||||
|
class="hover:text-secondary duration-200 ease-in-out"
|
||||||
|
>
|
||||||
|
<%= source.media_profile.name %>
|
||||||
</.link>
|
</.link>
|
||||||
</:action>
|
</:col>
|
||||||
</.table>
|
<:col :let={source} label="" class="flex place-content-evenly">
|
||||||
|
<.link
|
||||||
|
navigate={~p"/sources/#{source.id}"}
|
||||||
|
class="hover:text-secondary duration-200 ease-in-out mx-0.5"
|
||||||
|
>
|
||||||
|
<.icon name="hero-eye" />
|
||||||
|
</.link>
|
||||||
|
<.link
|
||||||
|
navigate={~p"/sources/#{source.id}/edit"}
|
||||||
|
class="hover:text-secondary duration-200 ease-in-out mx-0.5"
|
||||||
|
>
|
||||||
|
<.icon name="hero-pencil-square" />
|
||||||
|
</.link>
|
||||||
|
</:col>
|
||||||
|
</.table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
<.header>
|
<div class="mb-6 flex gap-3 flex-row items-center">
|
||||||
New Source
|
<.link navigate={~p"/sources"}>
|
||||||
<:subtitle>Use this form to manage source records in your database.</:subtitle>
|
<.icon name="hero-arrow-left" class="w-10 h-10 hover:dark:text-white" />
|
||||||
</.header>
|
</.link>
|
||||||
|
<h2 class="text-title-md2 font-bold text-black dark:text-white ml-4">New Source</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
<.source_form
|
<div class="rounded-sm border border-stroke bg-white px-5 pb-2.5 pt-6 shadow-default dark:border-strokedark dark:bg-boxdark sm:px-7.5 xl:pb-1">
|
||||||
changeset={@changeset}
|
<div class="max-w-full overflow-x-auto">
|
||||||
media_profiles={@media_profiles}
|
<div class="flex flex-col gap-10">
|
||||||
action={~p"/media_sources/sources"}
|
<.source_form changeset={@changeset} media_profiles={@media_profiles} action={~p"/sources"} />
|
||||||
/>
|
</div>
|
||||||
|
</div>
|
||||||
<.back navigate={~p"/media_sources/sources"}>Back to sources</.back>
|
</div>
|
||||||
|
|||||||
@@ -1,23 +1,38 @@
|
|||||||
<.header>
|
<div class="mb-6 flex gap-3 flex-row items-center justify-between">
|
||||||
Source <%= @source.id %>
|
<div class="flex gap-3 items-center">
|
||||||
<:subtitle>This is a source record from your database.</:subtitle>
|
<.link navigate={~p"/sources"}>
|
||||||
<:actions>
|
<.icon name="hero-arrow-left" class="w-10 h-10 hover:dark:text-white" />
|
||||||
<.link href={~p"/media_sources/sources/#{@source}/edit"}>
|
|
||||||
<.button>Edit source</.button>
|
|
||||||
</.link>
|
</.link>
|
||||||
</:actions>
|
<h2 class="text-title-md2 font-bold text-black dark:text-white ml-4">
|
||||||
</.header>
|
Source #<%= @source.id %>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h3 class="mt-14">Relationships</h3>
|
<nav>
|
||||||
<.list>
|
<.link navigate={~p"/sources/#{@source}/edit"}>
|
||||||
|
<.button color="bg-primary" rounding="rounded-full">
|
||||||
|
<.icon name="hero-pencil-square" class="mr-2" /> Edit Source
|
||||||
|
</.button>
|
||||||
|
</.link>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
<div class="rounded-sm border border-stroke bg-white px-5 pb-2.5 pt-6 shadow-default dark:border-strokedark dark:bg-boxdark sm:px-7.5 xl:pb-1">
|
||||||
|
<div class="max-w-full overflow-x-auto">
|
||||||
|
<div class="flex flex-col gap-10 dark:text-white">
|
||||||
|
<h3 class="mt-14 font-bold text-xl">Relationships</h3>
|
||||||
|
<.list>
|
||||||
<:item title="media_profile">
|
<:item title="media_profile">
|
||||||
<.link href={~p"/media_profiles/#{@source.media_profile}"}>
|
<.link
|
||||||
|
navigate={~p"/media_profiles/#{@source.media_profile_id}"}
|
||||||
|
class="hover:text-secondary duration-200 ease-in-out"
|
||||||
|
>
|
||||||
<%= @source.media_profile.name %>
|
<%= @source.media_profile.name %>
|
||||||
</.link>
|
</.link>
|
||||||
</:item>
|
</:item>
|
||||||
</.list>
|
</.list>
|
||||||
|
|
||||||
<h3>Attributes</h3>
|
<h3 class="font-bold text-xl">Attributes</h3>
|
||||||
<.list_items_from_map map={Map.from_struct(@source)} />
|
<.list_items_from_map map={Map.from_struct(@source)} />
|
||||||
|
</div>
|
||||||
<.back navigate={~p"/media_sources/sources"}>Back to sources</.back>
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -3,6 +3,13 @@
|
|||||||
Oops, something went wrong! Please check the errors below.
|
Oops, something went wrong! Please check the errors below.
|
||||||
</.error>
|
</.error>
|
||||||
|
|
||||||
|
<.input
|
||||||
|
field={f[:original_url]}
|
||||||
|
type="text"
|
||||||
|
label="Source URL"
|
||||||
|
help="URL of a channel or playlist (required)"
|
||||||
|
/>
|
||||||
|
|
||||||
<.input field={f[:friendly_name]} type="text" label="Friendly Name" />
|
<.input field={f[:friendly_name]} type="text" label="Friendly Name" />
|
||||||
|
|
||||||
<.input
|
<.input
|
||||||
@@ -16,21 +23,25 @@
|
|||||||
field={f[:collection_type]}
|
field={f[:collection_type]}
|
||||||
options={friendly_collection_types()}
|
options={friendly_collection_types()}
|
||||||
type="select"
|
type="select"
|
||||||
label="Collection Type"
|
label="Source Type"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<.input field={f[:original_url]} type="text" label="Source URL" />
|
|
||||||
|
|
||||||
<.input
|
<.input
|
||||||
field={f[:index_frequency_minutes]}
|
field={f[:index_frequency_minutes]}
|
||||||
options={friendly_index_frequencies()}
|
options={friendly_index_frequencies()}
|
||||||
type="select"
|
type="select"
|
||||||
label="Index Frequency"
|
label="Index Frequency"
|
||||||
|
help="Roughly how often to check for media to download"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<.input field={f[:download_media]} type="checkbox" label="Download Media?" />
|
<.input
|
||||||
|
field={f[:download_media]}
|
||||||
|
type="toggle"
|
||||||
|
label="Download Media?"
|
||||||
|
help="Unchecking still indexes media but it won't be downloaded"
|
||||||
|
/>
|
||||||
|
|
||||||
<:actions>
|
<:actions>
|
||||||
<.button>Save Source</.button>
|
<.button class="mt-15 mb-5 sm:mb-7.5">Save Source</.button>
|
||||||
</:actions>
|
</:actions>
|
||||||
</.simple_form>
|
</.simple_form>
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ defmodule PinchflatWeb.PageController do
|
|||||||
def home(conn, _params) do
|
def home(conn, _params) do
|
||||||
# The home page is often custom made,
|
# The home page is often custom made,
|
||||||
# so skip the default app layout.
|
# so skip the default app layout.
|
||||||
render(conn, :home, layout: false)
|
render(conn, :home)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -20,10 +20,7 @@ defmodule PinchflatWeb.Router do
|
|||||||
get "/", PageController, :home
|
get "/", PageController, :home
|
||||||
|
|
||||||
resources "/media_profiles", MediaProfiles.MediaProfileController
|
resources "/media_profiles", MediaProfiles.MediaProfileController
|
||||||
|
resources "/sources", MediaSources.SourceController
|
||||||
scope "/media_sources", MediaSources do
|
|
||||||
resources "/sources", SourceController
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Other scopes may use custom stacks.
|
# Other scopes may use custom stacks.
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -13,14 +13,14 @@ defmodule PinchflatWeb.MediaProfileControllerTest do
|
|||||||
describe "index" do
|
describe "index" do
|
||||||
test "lists all media_profiles", %{conn: conn} do
|
test "lists all media_profiles", %{conn: conn} do
|
||||||
conn = get(conn, ~p"/media_profiles")
|
conn = get(conn, ~p"/media_profiles")
|
||||||
assert html_response(conn, 200) =~ "Listing Media profiles"
|
assert html_response(conn, 200) =~ "All Media Profiles"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "new media_profile" do
|
describe "new media_profile" do
|
||||||
test "renders form", %{conn: conn} do
|
test "renders form", %{conn: conn} do
|
||||||
conn = get(conn, ~p"/media_profiles/new")
|
conn = get(conn, ~p"/media_profiles/new")
|
||||||
assert html_response(conn, 200) =~ "New Media profile"
|
assert html_response(conn, 200) =~ "New Media Profile"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -32,12 +32,12 @@ defmodule PinchflatWeb.MediaProfileControllerTest do
|
|||||||
assert redirected_to(conn) == ~p"/media_profiles/#{id}"
|
assert redirected_to(conn) == ~p"/media_profiles/#{id}"
|
||||||
|
|
||||||
conn = get(conn, ~p"/media_profiles/#{id}")
|
conn = get(conn, ~p"/media_profiles/#{id}")
|
||||||
assert html_response(conn, 200) =~ "Media profile #{id}"
|
assert html_response(conn, 200) =~ "Media Profile ##{id}"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "renders errors when data is invalid", %{conn: conn} do
|
test "renders errors when data is invalid", %{conn: conn} do
|
||||||
conn = post(conn, ~p"/media_profiles", media_profile: @invalid_attrs)
|
conn = post(conn, ~p"/media_profiles", media_profile: @invalid_attrs)
|
||||||
assert html_response(conn, 200) =~ "New Media profile"
|
assert html_response(conn, 200) =~ "New Media Profile"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ defmodule PinchflatWeb.MediaProfileControllerTest do
|
|||||||
media_profile: media_profile
|
media_profile: media_profile
|
||||||
} do
|
} do
|
||||||
conn = get(conn, ~p"/media_profiles/#{media_profile}/edit")
|
conn = get(conn, ~p"/media_profiles/#{media_profile}/edit")
|
||||||
assert html_response(conn, 200) =~ "Edit Media profile"
|
assert html_response(conn, 200) =~ "Edit Media Profile"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ defmodule PinchflatWeb.MediaProfileControllerTest do
|
|||||||
|
|
||||||
test "renders errors when data is invalid", %{conn: conn, media_profile: media_profile} do
|
test "renders errors when data is invalid", %{conn: conn, media_profile: media_profile} do
|
||||||
conn = put(conn, ~p"/media_profiles/#{media_profile}", media_profile: @invalid_attrs)
|
conn = put(conn, ~p"/media_profiles/#{media_profile}", media_profile: @invalid_attrs)
|
||||||
assert html_response(conn, 200) =~ "Edit Media profile"
|
assert html_response(conn, 200) =~ "Edit Media Profile"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -28,14 +28,14 @@ defmodule PinchflatWeb.SourceControllerTest do
|
|||||||
|
|
||||||
describe "index" do
|
describe "index" do
|
||||||
test "lists all sources", %{conn: conn} do
|
test "lists all sources", %{conn: conn} do
|
||||||
conn = get(conn, ~p"/media_sources/sources")
|
conn = get(conn, ~p"/sources")
|
||||||
assert html_response(conn, 200) =~ "Listing Sources"
|
assert html_response(conn, 200) =~ "All Sources"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "new source" do
|
describe "new source" do
|
||||||
test "renders form", %{conn: conn} do
|
test "renders form", %{conn: conn} do
|
||||||
conn = get(conn, ~p"/media_sources/sources/new")
|
conn = get(conn, ~p"/sources/new")
|
||||||
assert html_response(conn, 200) =~ "New Source"
|
assert html_response(conn, 200) =~ "New Source"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -43,17 +43,17 @@ defmodule PinchflatWeb.SourceControllerTest do
|
|||||||
describe "create source" do
|
describe "create source" do
|
||||||
test "redirects to show when data is valid", %{conn: conn, create_attrs: create_attrs} do
|
test "redirects to show when data is valid", %{conn: conn, create_attrs: create_attrs} do
|
||||||
expect(YtDlpRunnerMock, :run, 1, &runner_function_mock/3)
|
expect(YtDlpRunnerMock, :run, 1, &runner_function_mock/3)
|
||||||
conn = post(conn, ~p"/media_sources/sources", source: create_attrs)
|
conn = post(conn, ~p"/sources", source: create_attrs)
|
||||||
|
|
||||||
assert %{id: id} = redirected_params(conn)
|
assert %{id: id} = redirected_params(conn)
|
||||||
assert redirected_to(conn) == ~p"/media_sources/sources/#{id}"
|
assert redirected_to(conn) == ~p"/sources/#{id}"
|
||||||
|
|
||||||
conn = get(conn, ~p"/media_sources/sources/#{id}")
|
conn = get(conn, ~p"/sources/#{id}")
|
||||||
assert html_response(conn, 200) =~ "Source #{id}"
|
assert html_response(conn, 200) =~ "Source ##{id}"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "renders errors when data is invalid", %{conn: conn, invalid_attrs: invalid_attrs} do
|
test "renders errors when data is invalid", %{conn: conn, invalid_attrs: invalid_attrs} do
|
||||||
conn = post(conn, ~p"/media_sources/sources", source: invalid_attrs)
|
conn = post(conn, ~p"/sources", source: invalid_attrs)
|
||||||
assert html_response(conn, 200) =~ "New Source"
|
assert html_response(conn, 200) =~ "New Source"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -62,7 +62,7 @@ defmodule PinchflatWeb.SourceControllerTest do
|
|||||||
setup [:create_source]
|
setup [:create_source]
|
||||||
|
|
||||||
test "renders form for editing chosen source", %{conn: conn, source: source} do
|
test "renders form for editing chosen source", %{conn: conn, source: source} do
|
||||||
conn = get(conn, ~p"/media_sources/sources/#{source}/edit")
|
conn = get(conn, ~p"/sources/#{source}/edit")
|
||||||
assert html_response(conn, 200) =~ "Edit Source"
|
assert html_response(conn, 200) =~ "Edit Source"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -73,10 +73,10 @@ defmodule PinchflatWeb.SourceControllerTest do
|
|||||||
test "redirects when data is valid", %{conn: conn, source: source, update_attrs: update_attrs} do
|
test "redirects when data is valid", %{conn: conn, source: source, update_attrs: update_attrs} do
|
||||||
expect(YtDlpRunnerMock, :run, 1, &runner_function_mock/3)
|
expect(YtDlpRunnerMock, :run, 1, &runner_function_mock/3)
|
||||||
|
|
||||||
conn = put(conn, ~p"/media_sources/sources/#{source}", source: update_attrs)
|
conn = put(conn, ~p"/sources/#{source}", source: update_attrs)
|
||||||
assert redirected_to(conn) == ~p"/media_sources/sources/#{source}"
|
assert redirected_to(conn) == ~p"/sources/#{source}"
|
||||||
|
|
||||||
conn = get(conn, ~p"/media_sources/sources/#{source}")
|
conn = get(conn, ~p"/sources/#{source}")
|
||||||
assert html_response(conn, 200) =~ "https://www.youtube.com/source/321xyz"
|
assert html_response(conn, 200) =~ "https://www.youtube.com/source/321xyz"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ defmodule PinchflatWeb.SourceControllerTest do
|
|||||||
source: source,
|
source: source,
|
||||||
invalid_attrs: invalid_attrs
|
invalid_attrs: invalid_attrs
|
||||||
} do
|
} do
|
||||||
conn = put(conn, ~p"/media_sources/sources/#{source}", source: invalid_attrs)
|
conn = put(conn, ~p"/sources/#{source}", source: invalid_attrs)
|
||||||
assert html_response(conn, 200) =~ "Edit Source"
|
assert html_response(conn, 200) =~ "Edit Source"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -94,11 +94,11 @@ defmodule PinchflatWeb.SourceControllerTest do
|
|||||||
setup [:create_source]
|
setup [:create_source]
|
||||||
|
|
||||||
test "deletes chosen source", %{conn: conn, source: source} do
|
test "deletes chosen source", %{conn: conn, source: source} do
|
||||||
conn = delete(conn, ~p"/media_sources/sources/#{source}")
|
conn = delete(conn, ~p"/sources/#{source}")
|
||||||
assert redirected_to(conn) == ~p"/media_sources/sources"
|
assert redirected_to(conn) == ~p"/sources"
|
||||||
|
|
||||||
assert_error_sent 404, fn ->
|
assert_error_sent 404, fn ->
|
||||||
get(conn, ~p"/media_sources/sources/#{source}")
|
get(conn, ~p"/sources/#{source}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user