mirror of
https://github.com/kieraneglin/pinchflat.git
synced 2026-01-23 02:24:24 +00:00
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:
parent
9e4fbfa35d
commit
e1565ad22f
76 changed files with 1029 additions and 297 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -40,3 +40,4 @@ npm-debug.log
|
|||
.env
|
||||
.DS_Store
|
||||
scratchpad.md
|
||||
/scratchpad/
|
||||
|
|
|
|||
|
|
@ -2,4 +2,30 @@
|
|||
@import 'tailwindcss/components';
|
||||
@import 'tailwindcss/utilities';
|
||||
|
||||
@import './satoshi';
|
||||
|
||||
/* 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 */
|
||||
}
|
||||
}
|
||||
|
|
|
|||
102
assets/css/satoshi.css
Normal file
102
assets/css/satoshi.css
Normal file
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -21,10 +21,21 @@ import 'phoenix_html'
|
|||
import { Socket } from 'phoenix'
|
||||
import { LiveSocket } from 'phoenix_live_view'
|
||||
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 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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,15 +2,288 @@
|
|||
// https://tailwindcss.com/docs/configuration
|
||||
|
||||
const plugin = require('tailwindcss/plugin')
|
||||
const defaultTheme = require('tailwindcss/defaultTheme')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
module.exports = {
|
||||
content: ['./js/**/*.js', '../lib/pinchflat_web.ex', '../lib/pinchflat_web/**/*.*ex'],
|
||||
darkMode: 'class',
|
||||
theme: {
|
||||
fontFamily: {
|
||||
satoshi: ['Satoshi', 'sans-serif']
|
||||
},
|
||||
screens: {
|
||||
'2xsm': '375px',
|
||||
xsm: '425px',
|
||||
'3xl': '2000px',
|
||||
...defaultTheme.screens
|
||||
},
|
||||
extend: {
|
||||
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
|
||||
|
||||
|
||||
"@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
|
||||
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_auto_subs, :boolean, default: true
|
||||
|
|
|
|||
|
|
@ -84,8 +84,10 @@ defmodule PinchflatWeb do
|
|||
# HTML escaping functionality
|
||||
import Phoenix.HTML
|
||||
# Core UI components and translation
|
||||
import PinchflatWeb.CoreComponents
|
||||
import PinchflatWeb.Gettext
|
||||
import PinchflatWeb.CoreComponents
|
||||
import PinchflatWeb.CustomComponents.TableComponents
|
||||
import PinchflatWeb.CustomComponents.ButtonComponents
|
||||
|
||||
# Shortcut for generating JS commands
|
||||
alias Phoenix.LiveView.JS
|
||||
|
|
|
|||
|
|
@ -201,46 +201,14 @@ defmodule PinchflatWeb.CoreComponents do
|
|||
def simple_form(assigns) do
|
||||
~H"""
|
||||
<.form :let={f} for={@for} as={@as} {@rest}>
|
||||
<div class="mt-10 space-y-8 bg-white">
|
||||
<%= render_slot(@inner_block, f) %>
|
||||
<div :for={action <- @actions} class="mt-2 flex items-center justify-between gap-6">
|
||||
<%= render_slot(action, f) %>
|
||||
</div>
|
||||
<%= render_slot(@inner_block, f) %>
|
||||
<div :for={action <- @actions} class="mt-2 flex items-center justify-between gap-6">
|
||||
<%= render_slot(action, f) %>
|
||||
</div>
|
||||
</.form>
|
||||
"""
|
||||
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 """
|
||||
Renders an input with label and error messages.
|
||||
|
||||
|
|
@ -270,11 +238,12 @@ defmodule PinchflatWeb.CoreComponents do
|
|||
attr :name, :any
|
||||
attr :label, :string, default: nil
|
||||
attr :value, :any
|
||||
attr :help, :string, default: nil
|
||||
|
||||
attr :type, :string,
|
||||
default: "text",
|
||||
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,
|
||||
doc: "a form field struct retrieved from the form, for example: @form[:email]"
|
||||
|
|
@ -308,7 +277,7 @@ defmodule PinchflatWeb.CoreComponents do
|
|||
|
||||
~H"""
|
||||
<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="checkbox"
|
||||
|
|
@ -316,16 +285,54 @@ defmodule PinchflatWeb.CoreComponents do
|
|||
name={@name}
|
||||
value="true"
|
||||
checked={@checked}
|
||||
class="rounded border-zinc-300 text-zinc-900 focus:ring-0"
|
||||
class="rounded focus:ring-0"
|
||||
{@rest}
|
||||
/>
|
||||
<%= @label %>
|
||||
</label>
|
||||
<.help :if={@help}><%= @help %></.help>
|
||||
<.error :for={msg <- @errors}><%= msg %></.error>
|
||||
</div>
|
||||
"""
|
||||
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
|
||||
~H"""
|
||||
<div phx-feedback-for={@name}>
|
||||
|
|
@ -333,13 +340,17 @@ defmodule PinchflatWeb.CoreComponents do
|
|||
<select
|
||||
id={@id}
|
||||
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}
|
||||
{@rest}
|
||||
>
|
||||
<option :if={@prompt} value=""><%= @prompt %></option>
|
||||
<%= Phoenix.HTML.Form.options_for_select(@options, @value) %>
|
||||
</select>
|
||||
<.help :if={@help}><%= @help %></.help>
|
||||
<.error :for={msg <- @errors}><%= msg %></.error>
|
||||
</div>
|
||||
"""
|
||||
|
|
@ -360,6 +371,7 @@ defmodule PinchflatWeb.CoreComponents do
|
|||
]}
|
||||
{@rest}
|
||||
><%= Phoenix.HTML.Form.normalize_value("textarea", @value) %></textarea>
|
||||
<.help :if={@help}><%= @help %></.help>
|
||||
<.error :for={msg <- @errors}><%= msg %></.error>
|
||||
</div>
|
||||
"""
|
||||
|
|
@ -376,18 +388,32 @@ defmodule PinchflatWeb.CoreComponents do
|
|||
id={@id}
|
||||
value={Phoenix.HTML.Form.normalize_value(@type, @value)}
|
||||
class={[
|
||||
"mt-2 block w-full rounded-lg text-zinc-900 focus:ring-0 sm:text-sm sm:leading-6",
|
||||
"phx-no-feedback:border-zinc-300 phx-no-feedback:focus:border-zinc-400",
|
||||
@errors == [] && "border-zinc-300 focus:border-zinc-400",
|
||||
"w-full rounded-lg border-[1.5px] border-stroke bg-transparent px-5 py-3 font-normal text-black",
|
||||
"outline-none transition focus:border-primary active:border-primary disabled:cursor-default disabled:bg-whiter",
|
||||
"dark:border-form-strokedark dark:bg-form-input dark:text-white dark:focus:border-primary",
|
||||
@errors != [] && "border-rose-400 focus:border-rose-400"
|
||||
]}
|
||||
{@rest}
|
||||
/>
|
||||
<.help :if={@help}><%= @help %></.help>
|
||||
<.error :for={msg <- @errors}><%= msg %></.error>
|
||||
</div>
|
||||
"""
|
||||
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 """
|
||||
Renders a label.
|
||||
"""
|
||||
|
|
@ -396,7 +422,7 @@ defmodule PinchflatWeb.CoreComponents do
|
|||
|
||||
def label(assigns) do
|
||||
~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) %>
|
||||
</label>
|
||||
"""
|
||||
|
|
@ -409,7 +435,7 @@ defmodule PinchflatWeb.CoreComponents do
|
|||
|
||||
def error(assigns) do
|
||||
~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" />
|
||||
<%= render_slot(@inner_block) %>
|
||||
</p>
|
||||
|
|
@ -425,7 +451,7 @@ defmodule PinchflatWeb.CoreComponents do
|
|||
slot :subtitle
|
||||
slot :actions
|
||||
|
||||
def header(assigns) do
|
||||
def old_header(assigns) do
|
||||
~H"""
|
||||
<header class={[@actions != [] && "flex items-center justify-between gap-6", @class]}>
|
||||
<div>
|
||||
|
|
@ -446,10 +472,10 @@ defmodule PinchflatWeb.CoreComponents do
|
|||
|
||||
## Examples
|
||||
|
||||
<.table id="users" rows={@users}>
|
||||
<.old_table id="users" rows={@users}>
|
||||
<:col :let={user} label="id"><%= user.id %></:col>
|
||||
<:col :let={user} label="username"><%= user.username %></:col>
|
||||
</.table>
|
||||
</.old_table>
|
||||
"""
|
||||
attr :id, :string, required: true
|
||||
attr :rows, :list, required: true
|
||||
|
|
@ -466,56 +492,54 @@ defmodule PinchflatWeb.CoreComponents do
|
|||
|
||||
slot :action, doc: "the slot for showing user actions in the last table column"
|
||||
|
||||
def table(assigns) do
|
||||
def old_table(assigns) do
|
||||
assigns =
|
||||
with %{rows: %Phoenix.LiveView.LiveStream{}} <- assigns do
|
||||
assign(assigns, row_id: assigns.row_id || fn {id, _item} -> id end)
|
||||
end
|
||||
|
||||
~H"""
|
||||
<div class="overflow-y-auto px-4 sm:overflow-visible sm:px-0">
|
||||
<table class="w-[40rem] mt-11 sm:w-full">
|
||||
<thead class="text-sm text-left leading-6 text-zinc-500">
|
||||
<tr>
|
||||
<th :for={col <- @col} class="p-0 pb-4 pr-6 font-normal"><%= col[:label] %></th>
|
||||
<th :if={@action != []} class="relative p-0 pb-4">
|
||||
<span class="sr-only"><%= gettext("Actions") %></span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody
|
||||
id={@id}
|
||||
phx-update={match?(%Phoenix.LiveView.LiveStream{}, @rows) && "stream"}
|
||||
class="relative divide-y divide-zinc-100 border-t border-zinc-200 text-sm leading-6 text-zinc-700"
|
||||
>
|
||||
<tr :for={row <- @rows} id={@row_id && @row_id.(row)} class="group hover:bg-zinc-50">
|
||||
<td
|
||||
:for={{col, i} <- Enum.with_index(@col)}
|
||||
phx-click={@row_click && @row_click.(row)}
|
||||
class={["relative p-0", @row_click && "hover:cursor-pointer"]}
|
||||
>
|
||||
<div class="block py-4 pr-6">
|
||||
<span class="absolute -inset-y-px right-0 -left-4 group-hover:bg-zinc-50 sm:rounded-l-xl" />
|
||||
<span class={["relative", i == 0 && "font-semibold text-zinc-900"]}>
|
||||
<%= render_slot(col, @row_item.(row)) %>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td :if={@action != []} class="relative w-14 p-0">
|
||||
<div class="relative whitespace-nowrap py-4 text-right text-sm font-medium">
|
||||
<span class="absolute -inset-y-px -right-4 left-0 group-hover:bg-zinc-50 sm:rounded-r-xl" />
|
||||
<span
|
||||
:for={action <- @action}
|
||||
class="relative ml-4 font-semibold leading-6 text-zinc-900 hover:text-zinc-700"
|
||||
>
|
||||
<%= render_slot(action, @row_item.(row)) %>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<table class="w-[40rem] mt-11 sm:w-full">
|
||||
<thead class="text-sm text-left leading-6 text-zinc-500">
|
||||
<tr>
|
||||
<th :for={col <- @col} class="p-0 pb-4 pr-6 font-normal"><%= col[:label] %></th>
|
||||
<th :if={@action != []} class="relative p-0 pb-4">
|
||||
<span class="sr-only"><%= gettext("Actions") %></span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody
|
||||
id={@id}
|
||||
phx-update={match?(%Phoenix.LiveView.LiveStream{}, @rows) && "stream"}
|
||||
class="relative divide-y divide-zinc-100 border-t border-zinc-200 text-sm leading-6 text-zinc-700"
|
||||
>
|
||||
<tr :for={row <- @rows} id={@row_id && @row_id.(row)} class="group hover:bg-zinc-50">
|
||||
<td
|
||||
:for={{col, i} <- Enum.with_index(@col)}
|
||||
phx-click={@row_click && @row_click.(row)}
|
||||
class={["relative p-0", @row_click && "hover:cursor-pointer"]}
|
||||
>
|
||||
<div class="block py-4 pr-6">
|
||||
<span class="absolute -inset-y-px right-0 -left-4 group-hover:bg-zinc-50 sm:rounded-l-xl" />
|
||||
<span class={["relative", i == 0 && "font-semibold text-zinc-900"]}>
|
||||
<%= render_slot(col, @row_item.(row)) %>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td :if={@action != []} class="relative w-14 p-0">
|
||||
<div class="relative whitespace-nowrap py-4 text-right text-sm font-medium">
|
||||
<span class="absolute -inset-y-px -right-4 left-0 group-hover:bg-zinc-50 sm:rounded-r-xl" />
|
||||
<span
|
||||
:for={action <- @action}
|
||||
class="relative ml-4 font-semibold leading-6 text-zinc-900 hover:text-zinc-700"
|
||||
>
|
||||
<%= render_slot(action, @row_item.(row)) %>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
"""
|
||||
end
|
||||
|
||||
|
|
@ -536,10 +560,10 @@ defmodule PinchflatWeb.CoreComponents do
|
|||
def list(assigns) do
|
||||
~H"""
|
||||
<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">
|
||||
<dt class="w-1/4 flex-none text-zinc-500"><%= item.title %></dt>
|
||||
<dd class="text-zinc-700"><%= render_slot(item) %></dd>
|
||||
<dt class="w-1/4 flex-none dark:text-white"><%= item.title %></dt>
|
||||
<dd class="dark:text-white"><%= render_slot(item) %></dd>
|
||||
</div>
|
||||
</dl>
|
||||
</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
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -1,32 +1,13 @@
|
|||
<header class="px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex items-center justify-between border-b border-zinc-100 py-3 text-sm">
|
||||
<div class="flex items-center gap-4">
|
||||
<a href="/">
|
||||
<img src={~p"/images/logo.svg"} width="36" />
|
||||
</a>
|
||||
<p class="bg-brand/5 text-brand rounded-full px-2 font-medium leading-6">
|
||||
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 class="flex h-screen overflow-hidden">
|
||||
<.sidebar />
|
||||
|
||||
<div class="relative flex flex-1 flex-col overflow-y-auto overflow-x-hidden">
|
||||
<.header />
|
||||
<main>
|
||||
<div class="mx-auto max-w-screen-2xl p-4 md:p-6 2xl:p-10">
|
||||
<.flash_group flash={@flash} />
|
||||
<%= @inner_content %>
|
||||
</div>
|
||||
</main>
|
||||
</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} />
|
||||
<%= @inner_content %>
|
||||
</div>
|
||||
</main>
|
||||
</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>
|
||||
<html lang="en" class="[scrollbar-gutter:stable]">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<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>
|
||||
</head>
|
||||
<body class="bg-white antialiased">
|
||||
<body x-data="{ 'sidebarToggle': false }" class="dark text-bodydark bg-boxdark-2">
|
||||
<%= @inner_content %>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,14 @@
|
|||
<.header>
|
||||
Edit Media profile <%= @media_profile.id %>
|
||||
<:subtitle>Use this form to manage media_profile records in your database.</:subtitle>
|
||||
</.header>
|
||||
<div class="mb-6 flex gap-3 flex-row items-center">
|
||||
<.link navigate={~p"/media_profiles"}>
|
||||
<.icon name="hero-arrow-left" class="w-10 h-10 hover:dark:text-white" />
|
||||
</.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}"} />
|
||||
|
||||
<.back navigate={~p"/media_profiles"}>Back to media_profiles</.back>
|
||||
<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">
|
||||
<.media_profile_form changeset={@changeset} action={~p"/media_profiles/#{@media_profile}"} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,30 +1,39 @@
|
|||
<.header>
|
||||
Listing Media profiles
|
||||
<:actions>
|
||||
<.link href={~p"/media_profiles/new"}>
|
||||
<.button>New Media profile</.button>
|
||||
<div class="mb-6 flex gap-3 flex-row items-center justify-between">
|
||||
<h2 class="text-title-md2 font-bold text-black dark:text-white">All Media Profiles</h2>
|
||||
<nav>
|
||||
<.link navigate={~p"/media_profiles/new"}>
|
||||
<.button color="bg-primary" rounding="rounded-full">
|
||||
<span class="font-bold mx-2">+</span> New Media Profile
|
||||
</.button>
|
||||
</.link>
|
||||
</:actions>
|
||||
</.header>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<.table
|
||||
id="media_profiles"
|
||||
rows={@media_profiles}
|
||||
row_click={&JS.navigate(~p"/media_profiles/#{&1}")}
|
||||
>
|
||||
<:col :let={media_profile} label="Name"><%= media_profile.name %></:col>
|
||||
<:col :let={media_profile} label="Output path template">
|
||||
<%= media_profile.output_path_template %>
|
||||
</:col>
|
||||
<:action :let={media_profile}>
|
||||
<div class="sr-only">
|
||||
<.link navigate={~p"/media_profiles/#{media_profile}"}>Show</.link>
|
||||
<div class="rounded-sm border border-stroke bg-white shadow-default dark:border-strokedark dark:bg-boxdark">
|
||||
<div class="max-w-full overflow-x-auto">
|
||||
<div class="flex flex-col gap-10">
|
||||
<.table rows={@media_profiles} table_class="text-black dark:text-white">
|
||||
<:col :let={media_profile} label="Name">
|
||||
<%= media_profile.name %>
|
||||
</:col>
|
||||
<:col :let={media_profile} label="Output Template">
|
||||
<code class="text-sm"><%= media_profile.output_path_template %></code>
|
||||
</:col>
|
||||
<:col :let={media_profile} label="" class="flex place-content-evenly">
|
||||
<.link
|
||||
navigate={~p"/media_profiles/#{media_profile.id}"}
|
||||
class="hover:text-secondary duration-200 ease-in-out mx-0.5"
|
||||
>
|
||||
<.icon name="hero-eye" />
|
||||
</.link>
|
||||
<.link
|
||||
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>
|
||||
<.link navigate={~p"/media_profiles/#{media_profile}/edit"}>Edit</.link>
|
||||
</:action>
|
||||
<:action :let={media_profile}>
|
||||
<.link href={~p"/media_profiles/#{media_profile}"} method="delete" data-confirm="Are you sure?">
|
||||
Delete
|
||||
</.link>
|
||||
</:action>
|
||||
</.table>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,29 +2,62 @@
|
|||
<.error :if={@changeset.action}>
|
||||
Oops, something went wrong! Please check the errors below.
|
||||
</.error>
|
||||
<.input field={f[:name]} type="text" label="Name" />
|
||||
<.input field={f[:output_path_template]} type="text" label="Output path template" />
|
||||
<h3 class="my-4 text-2xl text-black dark:text-white">
|
||||
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>
|
||||
<.input field={f[:download_subs]} type="checkbox" label="Download Subs" />
|
||||
<.input field={f[:download_auto_subs]} type="checkbox" label="Download Autogenerated Subs" />
|
||||
<.input field={f[:embed_subs]} type="checkbox" label="Embed Subs" />
|
||||
<.input field={f[:sub_langs]} type="text" label="Sub Langs" />
|
||||
<h3 class="mb-4 mt-8 text-2xl text-black dark:text-white">
|
||||
Subtitle Options
|
||||
</h3>
|
||||
<.input field={f[:download_subs]} type="toggle" label="Download Subtitles" />
|
||||
<.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>
|
||||
<.input field={f[:download_thumbnail]} type="checkbox" label="Download Thumbnail" />
|
||||
<.input field={f[:embed_thumbnail]} type="checkbox" label="Embed Thumbnail" />
|
||||
<h3 class="mb-4 mt-8 text-2xl text-black dark:text-white">
|
||||
Thumbnail Options
|
||||
</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>
|
||||
<.input field={f[:download_metadata]} type="checkbox" label="Download Metadata" />
|
||||
<.input field={f[:embed_metadata]} type="checkbox" label="Embed Metadata" />
|
||||
<h3 class="mb-4 mt-8 text-2xl text-black dark:text-white">
|
||||
Metadata Options
|
||||
</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
|
||||
field={f[:shorts_behaviour]}
|
||||
options={friendly_format_type_options()}
|
||||
type="select"
|
||||
label="Include Shorts?"
|
||||
help="Experimental"
|
||||
/>
|
||||
<.input
|
||||
field={f[:livestream_behaviour]}
|
||||
|
|
@ -34,6 +67,6 @@
|
|||
/>
|
||||
|
||||
<:actions>
|
||||
<.button>Save Media profile</.button>
|
||||
<.button class="mt-15 mb-5 sm:mb-7.5">Save Media profile</.button>
|
||||
</:actions>
|
||||
</.simple_form>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,14 @@
|
|||
<.header>
|
||||
New Media profile
|
||||
<:subtitle>Use this form to manage media_profile records in your database.</:subtitle>
|
||||
</.header>
|
||||
<div class="mb-6 flex gap-3 flex-row items-center">
|
||||
<.link navigate={~p"/media_profiles"}>
|
||||
<.icon name="hero-arrow-left" class="w-10 h-10 hover:dark:text-white" />
|
||||
</.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"} />
|
||||
|
||||
<.back navigate={~p"/media_profiles"}>Back to media_profiles</.back>
|
||||
<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">
|
||||
<.media_profile_form changeset={@changeset} action={~p"/media_profiles"} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,26 @@
|
|||
<.header>
|
||||
Media profile <%= @media_profile.id %>
|
||||
<:subtitle>This is a media_profile record from your database.</:subtitle>
|
||||
<:actions>
|
||||
<.link href={~p"/media_profiles/#{@media_profile}/edit"}>
|
||||
<.button>Edit media_profile</.button>
|
||||
<div class="mb-6 flex gap-3 flex-row items-center justify-between">
|
||||
<div class="flex gap-3 items-center">
|
||||
<.link navigate={~p"/media_profiles"}>
|
||||
<.icon name="hero-arrow-left" class="w-10 h-10 hover:dark:text-white" />
|
||||
</.link>
|
||||
</:actions>
|
||||
</.header>
|
||||
<h2 class="text-title-md2 font-bold text-black dark:text-white ml-4">
|
||||
Media Profile #<%= @media_profile.id %>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<.list_items_from_map map={Map.from_struct(@media_profile)} />
|
||||
|
||||
<.back navigate={~p"/media_profiles"}>Back to media_profiles</.back>
|
||||
<nav>
|
||||
<.link navigate={~p"/media_profiles/#{@media_profile}/edit"}>
|
||||
<.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
|
||||
|
||||
def index(conn, _params) do
|
||||
sources = MediaSource.list_sources()
|
||||
sources = Repo.preload(MediaSource.list_sources(), :media_profile)
|
||||
|
||||
render(conn, :index, sources: sources)
|
||||
end
|
||||
|
|
@ -23,7 +23,7 @@ defmodule PinchflatWeb.MediaSources.SourceController do
|
|||
{:ok, source} ->
|
||||
conn
|
||||
|> put_flash(:info, "Source created successfully.")
|
||||
|> redirect(to: ~p"/media_sources/sources/#{source}")
|
||||
|> redirect(to: ~p"/sources/#{source}")
|
||||
|
||||
{:error, %Ecto.Changeset{} = changeset} ->
|
||||
render(conn, :new, changeset: changeset, media_profiles: media_profiles())
|
||||
|
|
@ -53,7 +53,7 @@ defmodule PinchflatWeb.MediaSources.SourceController do
|
|||
{:ok, source} ->
|
||||
conn
|
||||
|> put_flash(:info, "Source updated successfully.")
|
||||
|> redirect(to: ~p"/media_sources/sources/#{source}")
|
||||
|> redirect(to: ~p"/sources/#{source}")
|
||||
|
||||
{:error, %Ecto.Changeset{} = changeset} ->
|
||||
render(conn, :edit,
|
||||
|
|
@ -70,7 +70,7 @@ defmodule PinchflatWeb.MediaSources.SourceController do
|
|||
|
||||
conn
|
||||
|> put_flash(:info, "Source deleted successfully.")
|
||||
|> redirect(to: ~p"/media_sources/sources")
|
||||
|> redirect(to: ~p"/sources")
|
||||
end
|
||||
|
||||
defp media_profiles do
|
||||
|
|
|
|||
|
|
@ -1,12 +1,18 @@
|
|||
<.header>
|
||||
Edit Source <%= @source.id %>
|
||||
<:subtitle>Use this form to manage source records in your database.</:subtitle>
|
||||
</.header>
|
||||
<div class="mb-6 flex gap-3 flex-row items-center">
|
||||
<.link navigate={~p"/sources"}>
|
||||
<.icon name="hero-arrow-left" class="w-10 h-10 hover:dark:text-white" />
|
||||
</.link>
|
||||
<h2 class="text-title-md2 font-bold text-black dark:text-white ml-4">Edit Source</h2>
|
||||
</div>
|
||||
|
||||
<.source_form
|
||||
changeset={@changeset}
|
||||
media_profiles={@media_profiles}
|
||||
action={~p"/media_sources/sources/#{@source}"}
|
||||
/>
|
||||
|
||||
<.back navigate={~p"/media_sources/sources"}>Back to sources</.back>
|
||||
<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}
|
||||
media_profiles={@media_profiles}
|
||||
action={~p"/sources/#{@source}"}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,24 +1,48 @@
|
|||
<.header>
|
||||
Listing Sources
|
||||
<:actions>
|
||||
<.link href={~p"/media_sources/sources/new"}>
|
||||
<.button>New Source</.button>
|
||||
<div class="mb-6 flex gap-3 flex-row items-center justify-between">
|
||||
<h2 class="text-title-md2 font-bold text-black dark:text-white">All Sources</h2>
|
||||
<nav>
|
||||
<.link navigate={~p"/sources/new"}>
|
||||
<.button color="bg-primary" rounding="rounded-full">
|
||||
<span class="font-bold mx-2">+</span> New Source
|
||||
</.button>
|
||||
</.link>
|
||||
</:actions>
|
||||
</.header>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<.table id="sources" rows={@sources} row_click={&JS.navigate(~p"/media_sources/sources/#{&1}")}>
|
||||
<:col :let={source} label="Collection Name"><%= source.collection_name %></:col>
|
||||
<:col :let={source} label="Collection ID"><%= source.collection_id %></:col>
|
||||
<:action :let={source}>
|
||||
<div class="sr-only">
|
||||
<.link navigate={~p"/media_sources/sources/#{source}"}>Show</.link>
|
||||
<div class="rounded-sm border border-stroke bg-white shadow-default dark:border-strokedark dark:bg-boxdark">
|
||||
<div class="max-w-full overflow-x-auto">
|
||||
<div class="flex flex-col gap-10">
|
||||
<.table rows={@sources} table_class="text-black dark:text-white">
|
||||
<:col :let={source} label="Name">
|
||||
<%= source.friendly_name || source.collection_name %>
|
||||
</:col>
|
||||
<:col :let={source} label="Type"><%= source.collection_type %></:col>
|
||||
<:col :let={source} label="Should Download?">
|
||||
<.icon name={if source.download_media, do: "hero-check", else: "hero-x-mark"} />
|
||||
</:col>
|
||||
<: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>
|
||||
</:col>
|
||||
<: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>
|
||||
<.link navigate={~p"/media_sources/sources/#{source}/edit"}>Edit</.link>
|
||||
</:action>
|
||||
<:action :let={source}>
|
||||
<.link href={~p"/media_sources/sources/#{source}"} method="delete" data-confirm="Are you sure?">
|
||||
Delete
|
||||
</.link>
|
||||
</:action>
|
||||
</.table>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
<.header>
|
||||
New Source
|
||||
<:subtitle>Use this form to manage source records in your database.</:subtitle>
|
||||
</.header>
|
||||
<div class="mb-6 flex gap-3 flex-row items-center">
|
||||
<.link navigate={~p"/sources"}>
|
||||
<.icon name="hero-arrow-left" class="w-10 h-10 hover:dark:text-white" />
|
||||
</.link>
|
||||
<h2 class="text-title-md2 font-bold text-black dark:text-white ml-4">New Source</h2>
|
||||
</div>
|
||||
|
||||
<.source_form
|
||||
changeset={@changeset}
|
||||
media_profiles={@media_profiles}
|
||||
action={~p"/media_sources/sources"}
|
||||
/>
|
||||
|
||||
<.back navigate={~p"/media_sources/sources"}>Back to sources</.back>
|
||||
<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} media_profiles={@media_profiles} action={~p"/sources"} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,23 +1,38 @@
|
|||
<.header>
|
||||
Source <%= @source.id %>
|
||||
<:subtitle>This is a source record from your database.</:subtitle>
|
||||
<:actions>
|
||||
<.link href={~p"/media_sources/sources/#{@source}/edit"}>
|
||||
<.button>Edit source</.button>
|
||||
<div class="mb-6 flex gap-3 flex-row items-center justify-between">
|
||||
<div class="flex gap-3 items-center">
|
||||
<.link navigate={~p"/sources"}>
|
||||
<.icon name="hero-arrow-left" class="w-10 h-10 hover:dark:text-white" />
|
||||
</.link>
|
||||
</:actions>
|
||||
</.header>
|
||||
<h2 class="text-title-md2 font-bold text-black dark:text-white ml-4">
|
||||
Source #<%= @source.id %>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<h3 class="mt-14">Relationships</h3>
|
||||
<.list>
|
||||
<:item title="media_profile">
|
||||
<.link href={~p"/media_profiles/#{@source.media_profile}"}>
|
||||
<%= @source.media_profile.name %>
|
||||
<nav>
|
||||
<.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>
|
||||
</:item>
|
||||
</.list>
|
||||
</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">
|
||||
<.link
|
||||
navigate={~p"/media_profiles/#{@source.media_profile_id}"}
|
||||
class="hover:text-secondary duration-200 ease-in-out"
|
||||
>
|
||||
<%= @source.media_profile.name %>
|
||||
</.link>
|
||||
</:item>
|
||||
</.list>
|
||||
|
||||
<h3>Attributes</h3>
|
||||
<.list_items_from_map map={Map.from_struct(@source)} />
|
||||
|
||||
<.back navigate={~p"/media_sources/sources"}>Back to sources</.back>
|
||||
<h3 class="font-bold text-xl">Attributes</h3>
|
||||
<.list_items_from_map map={Map.from_struct(@source)} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,13 @@
|
|||
Oops, something went wrong! Please check the errors below.
|
||||
</.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
|
||||
|
|
@ -16,21 +23,25 @@
|
|||
field={f[:collection_type]}
|
||||
options={friendly_collection_types()}
|
||||
type="select"
|
||||
label="Collection Type"
|
||||
label="Source Type"
|
||||
/>
|
||||
|
||||
<.input field={f[:original_url]} type="text" label="Source URL" />
|
||||
|
||||
<.input
|
||||
field={f[:index_frequency_minutes]}
|
||||
options={friendly_index_frequencies()}
|
||||
type="select"
|
||||
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>
|
||||
<.button>Save Source</.button>
|
||||
<.button class="mt-15 mb-5 sm:mb-7.5">Save Source</.button>
|
||||
</:actions>
|
||||
</.simple_form>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,6 @@ defmodule PinchflatWeb.PageController do
|
|||
def home(conn, _params) do
|
||||
# The home page is often custom made,
|
||||
# so skip the default app layout.
|
||||
render(conn, :home, layout: false)
|
||||
render(conn, :home)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -20,10 +20,7 @@ defmodule PinchflatWeb.Router do
|
|||
get "/", PageController, :home
|
||||
|
||||
resources "/media_profiles", MediaProfiles.MediaProfileController
|
||||
|
||||
scope "/media_sources", MediaSources do
|
||||
resources "/sources", SourceController
|
||||
end
|
||||
resources "/sources", MediaSources.SourceController
|
||||
end
|
||||
|
||||
# Other scopes may use custom stacks.
|
||||
|
|
|
|||
BIN
priv/static/fonts/satoshi/Satoshi-BlackItalic.eot
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-BlackItalic.eot
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-BlackItalic.ttf
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-BlackItalic.ttf
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-BlackItalic.woff
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-BlackItalic.woff
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-BlackItalic.woff2
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-BlackItalic.woff2
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-Bold.eot
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-Bold.eot
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-Bold.ttf
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-Bold.ttf
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-Bold.woff
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-Bold.woff
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-Bold.woff2
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-Bold.woff2
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-BoldItalic.eot
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-BoldItalic.eot
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-BoldItalic.ttf
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-BoldItalic.woff
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-BoldItalic.woff
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-BoldItalic.woff2
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-BoldItalic.woff2
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-Italic.eot
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-Italic.eot
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-Italic.ttf
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-Italic.ttf
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-Italic.woff
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-Italic.woff
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-Italic.woff2
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-Italic.woff2
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-Light.eot
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-Light.eot
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-Light.ttf
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-Light.ttf
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-Light.woff
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-Light.woff
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-Light.woff2
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-Light.woff2
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-LightItalic.eot
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-LightItalic.eot
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-LightItalic.ttf
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-LightItalic.ttf
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-LightItalic.woff
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-LightItalic.woff
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-LightItalic.woff2
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-LightItalic.woff2
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-Medium.eot
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-Medium.eot
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-Medium.ttf
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-Medium.ttf
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-Medium.woff
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-Medium.woff
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-Medium.woff2
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-Medium.woff2
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-MediumItalic.eot
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-MediumItalic.eot
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-MediumItalic.ttf
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-MediumItalic.ttf
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-MediumItalic.woff
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-MediumItalic.woff
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-MediumItalic.woff2
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-MediumItalic.woff2
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-Regular.eot
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-Regular.eot
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-Regular.ttf
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-Regular.ttf
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-Regular.woff
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-Regular.woff
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-Regular.woff2
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-Regular.woff2
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-Variable.eot
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-Variable.eot
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-Variable.ttf
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-Variable.ttf
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-Variable.woff
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-Variable.woff
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-Variable.woff2
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-Variable.woff2
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-VariableItalic.eot
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-VariableItalic.eot
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-VariableItalic.ttf
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-VariableItalic.ttf
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-VariableItalic.woff
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-VariableItalic.woff
Normal file
Binary file not shown.
BIN
priv/static/fonts/satoshi/Satoshi-VariableItalic.woff2
Normal file
BIN
priv/static/fonts/satoshi/Satoshi-VariableItalic.woff2
Normal file
Binary file not shown.
|
|
@ -13,14 +13,14 @@ defmodule PinchflatWeb.MediaProfileControllerTest do
|
|||
describe "index" do
|
||||
test "lists all media_profiles", %{conn: conn} do
|
||||
conn = get(conn, ~p"/media_profiles")
|
||||
assert html_response(conn, 200) =~ "Listing Media profiles"
|
||||
assert html_response(conn, 200) =~ "All Media Profiles"
|
||||
end
|
||||
end
|
||||
|
||||
describe "new media_profile" do
|
||||
test "renders form", %{conn: conn} do
|
||||
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
|
||||
|
||||
|
|
@ -32,12 +32,12 @@ defmodule PinchflatWeb.MediaProfileControllerTest do
|
|||
assert redirected_to(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
|
||||
|
||||
test "renders errors when data is invalid", %{conn: conn} do
|
||||
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
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ defmodule PinchflatWeb.MediaProfileControllerTest do
|
|||
media_profile: media_profile
|
||||
} do
|
||||
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
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ defmodule PinchflatWeb.MediaProfileControllerTest 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)
|
||||
assert html_response(conn, 200) =~ "Edit Media profile"
|
||||
assert html_response(conn, 200) =~ "Edit Media Profile"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -28,14 +28,14 @@ defmodule PinchflatWeb.SourceControllerTest do
|
|||
|
||||
describe "index" do
|
||||
test "lists all sources", %{conn: conn} do
|
||||
conn = get(conn, ~p"/media_sources/sources")
|
||||
assert html_response(conn, 200) =~ "Listing Sources"
|
||||
conn = get(conn, ~p"/sources")
|
||||
assert html_response(conn, 200) =~ "All Sources"
|
||||
end
|
||||
end
|
||||
|
||||
describe "new source" 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"
|
||||
end
|
||||
end
|
||||
|
|
@ -43,17 +43,17 @@ defmodule PinchflatWeb.SourceControllerTest do
|
|||
describe "create source" do
|
||||
test "redirects to show when data is valid", %{conn: conn, create_attrs: create_attrs} do
|
||||
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 redirected_to(conn) == ~p"/media_sources/sources/#{id}"
|
||||
assert redirected_to(conn) == ~p"/sources/#{id}"
|
||||
|
||||
conn = get(conn, ~p"/media_sources/sources/#{id}")
|
||||
assert html_response(conn, 200) =~ "Source #{id}"
|
||||
conn = get(conn, ~p"/sources/#{id}")
|
||||
assert html_response(conn, 200) =~ "Source ##{id}"
|
||||
end
|
||||
|
||||
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"
|
||||
end
|
||||
end
|
||||
|
|
@ -62,7 +62,7 @@ defmodule PinchflatWeb.SourceControllerTest do
|
|||
setup [:create_source]
|
||||
|
||||
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"
|
||||
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
|
||||
expect(YtDlpRunnerMock, :run, 1, &runner_function_mock/3)
|
||||
|
||||
conn = put(conn, ~p"/media_sources/sources/#{source}", source: update_attrs)
|
||||
assert redirected_to(conn) == ~p"/media_sources/sources/#{source}"
|
||||
conn = put(conn, ~p"/sources/#{source}", source: update_attrs)
|
||||
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"
|
||||
end
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ defmodule PinchflatWeb.SourceControllerTest do
|
|||
source: source,
|
||||
invalid_attrs: invalid_attrs
|
||||
} 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"
|
||||
end
|
||||
end
|
||||
|
|
@ -94,11 +94,11 @@ defmodule PinchflatWeb.SourceControllerTest do
|
|||
setup [:create_source]
|
||||
|
||||
test "deletes chosen source", %{conn: conn, source: source} do
|
||||
conn = delete(conn, ~p"/media_sources/sources/#{source}")
|
||||
assert redirected_to(conn) == ~p"/media_sources/sources"
|
||||
conn = delete(conn, ~p"/sources/#{source}")
|
||||
assert redirected_to(conn) == ~p"/sources"
|
||||
|
||||
assert_error_sent 404, fn ->
|
||||
get(conn, ~p"/media_sources/sources/#{source}")
|
||||
get(conn, ~p"/sources/#{source}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue