mirror of
https://github.com/mmjee/Piped-Material.git
synced 2024-12-06 19:26:36 +01:00
Remove things I don't care about and update
This commit is contained in:
+6
-22
@@ -20,13 +20,7 @@
|
||||
<v-spacer></v-spacer>
|
||||
|
||||
<v-responsive max-width="720">
|
||||
<v-text-field
|
||||
dense
|
||||
flat
|
||||
hide-details
|
||||
rounded
|
||||
solo-inverted
|
||||
></v-text-field>
|
||||
<SearchMenu />
|
||||
</v-responsive>
|
||||
</v-container>
|
||||
</v-app-bar>
|
||||
@@ -38,8 +32,13 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SearchMenu from '@/routes/SearchMenu'
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
SearchMenu
|
||||
},
|
||||
data: () => ({
|
||||
links: [
|
||||
{
|
||||
@@ -47,21 +46,6 @@ export default {
|
||||
name: 'Preferences',
|
||||
to: '/preferences'
|
||||
},
|
||||
{
|
||||
id: 'login',
|
||||
name: 'Login',
|
||||
to: '/login'
|
||||
},
|
||||
{
|
||||
id: 'register',
|
||||
name: 'Register',
|
||||
to: '/register'
|
||||
},
|
||||
{
|
||||
id: 'feed',
|
||||
name: 'Feed',
|
||||
to: '/feed'
|
||||
},
|
||||
{
|
||||
id: 'trending',
|
||||
name: 'Trending',
|
||||
|
||||
@@ -37,26 +37,6 @@ const routes = [
|
||||
name: 'Channel',
|
||||
component: () => import('@/routes/Channel')
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
name: 'Login',
|
||||
component: () => import('@/routes/LoginPage')
|
||||
},
|
||||
{
|
||||
path: '/register',
|
||||
name: 'Register',
|
||||
component: () => import('@/routes/RegisterPage')
|
||||
},
|
||||
{
|
||||
path: '/feed',
|
||||
name: 'Feed',
|
||||
component: () => import('@/routes/FeedPage')
|
||||
},
|
||||
{
|
||||
path: '/import',
|
||||
name: 'Import',
|
||||
component: () => import('@/routes/ImportPage')
|
||||
},
|
||||
{
|
||||
path: '/:videoId([a-zA-Z0-9_-]{11})',
|
||||
component: () => import('@/components/VideoRedirect')
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<ErrorHandler v-if="channel && channel.error" :message="channel.message" :error="channel.error" />
|
||||
|
||||
<div v-else-if="channel" v-show="!channel.error">
|
||||
<div v-else-if="channel">
|
||||
<h1 class="uk-text-center"><img height="48" width="48" v-bind:src="channel.avatarUrl" />{{ channel.name }}</h1>
|
||||
<img v-if="channel.bannerUrl" v-bind:src="channel.bannerUrl" style="width: 100%" loading="lazy" />
|
||||
<p style="white-space: pre-wrap">{{ channel.description }}</p>
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
<template>
|
||||
<v-container fluid>
|
||||
<h1 class="uk-text-bold uk-text-center">Feed</h1>
|
||||
|
||||
<small>You can import subscriptions from <router-link to="/import">here</router-link>.</small>
|
||||
|
||||
<div class="uk-align-right">
|
||||
<a :href="getRssUrl"><font-awesome-icon icon="rss"></font-awesome-icon></a>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="uk-grid-xl" uk-grid="parallax: 0">
|
||||
<div
|
||||
:style="[{ background: backgroundColor }]"
|
||||
class="uk-width-1-2 uk-width-1-3@s uk-width-1-4@m uk-width-1-5@l uk-width-1-6@xl"
|
||||
v-bind:key="video.url"
|
||||
v-for="video in videos"
|
||||
>
|
||||
<div class="uk-text-secondary" :style="[{ background: backgroundColor }]">
|
||||
<router-link class="uk-text-emphasis" v-bind:to="'/watch?v=' + video.id">
|
||||
<img style="width: 100%" v-bind:src="video.thumbnail" alt="thumbnail" loading="lazy" />
|
||||
<p>{{ video.title }}</p>
|
||||
</router-link>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<router-link class="uk-link-muted" :to="'/channel/' + video.uploader_id">
|
||||
<a>{{ video.uploader }}</a>
|
||||
</router-link>
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<b class="uk-text-small uk-align-left">
|
||||
<div v-if="video.views >= 0">
|
||||
<font-awesome-icon icon="eye"></font-awesome-icon>
|
||||
{{ numberFormat(video.views) }} views
|
||||
<br />
|
||||
</div>
|
||||
<div>
|
||||
{{ timeAgo(video.uploaded) }}
|
||||
</div>
|
||||
</b>
|
||||
<div class="uk-align-right">
|
||||
<b class="uk-text-small">{{ timeFormat(video.duration) }}</b>
|
||||
|
||||
<br />
|
||||
|
||||
<router-link :to="'/watch?v=' + video.id + '&listen=1'">
|
||||
<font-awesome-icon icon="headphones"></font-awesome-icon>
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { LibPiped } from '@/tools/libpiped'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
videos: []
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
// reimplement using vue-meta
|
||||
// document.title = 'Feed - Piped'
|
||||
|
||||
this.fetchFeed().then(videos => (this.videos = videos))
|
||||
},
|
||||
methods: {
|
||||
async fetchFeed () {
|
||||
return LibPiped.fetchJson('/feed')
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
getRssUrl () {
|
||||
return LibPiped.apiUrl() + '/feed/rss?authToken=' + LibPiped.getAuthToken()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,129 +0,0 @@
|
||||
<template>
|
||||
<div class="uk-vertical-align uk-text-center uk-height-1-1 ">
|
||||
<form class="uk-panel uk-panel-box">
|
||||
<div class="uk-form-row">
|
||||
<input type="file" @change="fileChange" ref="fileSelector" />
|
||||
</div>
|
||||
<div class="uk-form-row">
|
||||
<b>Selected Subscriptions: {{ selectedSubscriptions }}</b>
|
||||
</div>
|
||||
<div class="uk-form-row">
|
||||
<a
|
||||
class="uk-width-1-1 uk-button uk-button-primary uk-button-large uk-width-auto"
|
||||
style="background: #222"
|
||||
@click="handleImport"
|
||||
>Import</a
|
||||
>
|
||||
</div>
|
||||
</form>
|
||||
<br />
|
||||
<b>Importing Subscriptions from YouTube</b>
|
||||
<br />
|
||||
<div>
|
||||
Open
|
||||
<a href="https://takeout.google.com/takeout/custom/youtube">takeout.google.com/takeout/custom/youtube</a>
|
||||
<br />
|
||||
In "Select data to include", click on "All YouTube data included" and select only "subscriptions".
|
||||
<br />
|
||||
Create the export and download the zip file.
|
||||
<br />
|
||||
Extract subscriptions.json from the zip file.
|
||||
<br />
|
||||
Select and import the file above.
|
||||
</div>
|
||||
<br />
|
||||
<b>Importing Subscriptions from Invidious</b>
|
||||
<br />
|
||||
<div>
|
||||
Open
|
||||
<a href="https://invidio.us/data_control">invidiou.us/data_control</a>
|
||||
<br />
|
||||
Click on any of the export options.
|
||||
<br />
|
||||
Select and import the file above.
|
||||
</div>
|
||||
<br />
|
||||
<b>Importing Subscriptions from NewPipe</b>
|
||||
<br />
|
||||
<div>
|
||||
Go to the Feed tab.
|
||||
<br />
|
||||
Click on the arrow on where it says "Subscriptions".
|
||||
<br />
|
||||
Save the file somewhere.
|
||||
<br />
|
||||
Select and import the file above.
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
subscriptions: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
selectedSubscriptions () {
|
||||
return this.subscriptions.length
|
||||
}
|
||||
},
|
||||
activated () {
|
||||
if (!this.authenticated) this.$router.push('/login')
|
||||
},
|
||||
methods: {
|
||||
fileChange () {
|
||||
this.$refs.fileSelector.files[0].text().then(text => {
|
||||
this.subscriptions = []
|
||||
|
||||
// Invidious
|
||||
if (text.indexOf('opml') !== -1) {
|
||||
const parser = new DOMParser()
|
||||
const xmlDoc = parser.parseFromString(text, 'text/xml')
|
||||
xmlDoc.querySelectorAll('outline[xmlUrl]').forEach(item => {
|
||||
const url = item.getAttribute('xmlUrl')
|
||||
const id = url.substr(-24)
|
||||
this.subscriptions.push(id)
|
||||
})
|
||||
}
|
||||
// NewPipe
|
||||
if (text.indexOf('app_version') !== -1) {
|
||||
const json = JSON.parse(text)
|
||||
json.subscriptions
|
||||
.filter(item => item.service_id === 0)
|
||||
.forEach(item => {
|
||||
const url = item.url
|
||||
const id = url.substr(-24)
|
||||
this.subscriptions.push(id)
|
||||
})
|
||||
}
|
||||
// Invidious JSON
|
||||
if (text.indexOf('thin_mode') !== -1) {
|
||||
const json = JSON.parse(text)
|
||||
this.subscriptions = json.subscriptions
|
||||
}
|
||||
// Google Takeout
|
||||
if (text.indexOf('contentDetails') !== -1) {
|
||||
const json = JSON.parse(text)
|
||||
json.forEach(item => {
|
||||
const id = item.snippet.resourceId.channelId
|
||||
this.subscriptions.push(id)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
handleImport () {
|
||||
this.fetchJson(this.apiUrl() + '/import', null, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: this.getAuthToken()
|
||||
},
|
||||
body: JSON.stringify(this.subscriptions)
|
||||
}).then(json => {
|
||||
if (json.message === 'ok') window.location = '/feed'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,66 +0,0 @@
|
||||
<template>
|
||||
<div class="uk-vertical-align uk-text-center uk-height-1-1 ">
|
||||
<form class="uk-panel uk-panel-box">
|
||||
<div class="uk-form-row">
|
||||
<input
|
||||
class="uk-width-1-1 uk-form-large uk-input uk-width-auto"
|
||||
type="text"
|
||||
v-model="username"
|
||||
autocomplete="username"
|
||||
placeholder="Username"
|
||||
/>
|
||||
</div>
|
||||
<div class="uk-form-row">
|
||||
<input
|
||||
class="uk-width-1-1 uk-form-large uk-input uk-width-auto"
|
||||
type="password"
|
||||
v-model="password"
|
||||
autocomplete="password"
|
||||
placeholder="Password"
|
||||
/>
|
||||
</div>
|
||||
<div class="uk-form-row">
|
||||
<a
|
||||
class="uk-width-1-1 uk-button uk-button-primary uk-button-large uk-width-auto"
|
||||
style="background: #222"
|
||||
@click="login"
|
||||
>Login</a
|
||||
>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
username: null,
|
||||
password: null
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
// TODO: Add Server Side check
|
||||
if (this.getAuthToken()) {
|
||||
this.$router.push('/')
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
login () {
|
||||
console.log('authToken' + this.hashCode(this.apiUrl()))
|
||||
this.fetchJson(this.apiUrl() + '/login', null, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
username: this.username,
|
||||
password: this.password
|
||||
})
|
||||
}).then(resp => {
|
||||
if (resp.token) {
|
||||
this.setPreference('authToken' + this.hashCode(this.apiUrl()), resp.token)
|
||||
window.location = '/' // done to bypass cache
|
||||
} else alert(resp.error)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
+57
-9
@@ -1,6 +1,52 @@
|
||||
<template>
|
||||
<ErrorHandler v-if="playlist && playlist.error" :message="playlist.message" :error="playlist.error" />
|
||||
|
||||
<v-container fluid v-else-if="playlist">
|
||||
<v-row>
|
||||
<v-col md="8" offset-md="2">
|
||||
<v-card>
|
||||
<v-img v-if="playlist.avatarUrl" :src="playlist.avatarUrl" />
|
||||
<v-card-title class="display-1">
|
||||
{{ playlist.name }}
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<router-link v-if="playlist.uploaderUrl" :to="playlist.uploaderUrl" custom v-slot="{ navigate }">
|
||||
<div
|
||||
style="justify-items: center; align-items: center; vertical-align: center; display: flex; cursor: pointer"
|
||||
@click="navigate" @keypress.enter="navigate" role="link"
|
||||
>
|
||||
<div>
|
||||
<v-img :src="playlist.uploaderAvatar" height="48" width="48" class="rounded-circle" />
|
||||
</div>
|
||||
<div class="text-h5 ml-4">
|
||||
{{ playlist.uploader }}
|
||||
</div>
|
||||
<div class="ml-4">
|
||||
<v-btn
|
||||
v-if="$store.state.isAuthenticated"
|
||||
@click="subscribeHandler"
|
||||
color="primary"
|
||||
>
|
||||
{{ subscribed ? "Unsubscribe" : "Subscribe" }}
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</router-link>
|
||||
<h5 class="text-h5 ml-16">{{ playlist.videos }} Videos</h5>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-btn icon x-large link :href="getRssUrl"><v-icon x-large>mdi-rss-box</v-icon></v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
|
||||
<v-row v-for="(chunk, chunkId) in chunkedByFour" :key="chunkId" class="mt-4">
|
||||
<v-col md="3" v-for="video in chunk" :key="video.url">
|
||||
<VideoItem :video="video" />
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
<div v-else-if="playlist" v-show="!playlist.error">
|
||||
<h1 class="uk-text-center">
|
||||
<img v-bind:src="playlist.avatarUrl" height="48" width="48" loading="lazy" />
|
||||
@@ -38,6 +84,8 @@
|
||||
import ErrorHandler from '@/components/ErrorHandler.vue'
|
||||
import VideoItem from '@/components/VideoItem.vue'
|
||||
|
||||
import { chunk as _chunk } from 'lodash-es'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
@@ -47,20 +95,20 @@ export default {
|
||||
mounted () {
|
||||
this.getPlaylistData()
|
||||
},
|
||||
activated () {
|
||||
window.addEventListener('scroll', this.handleScroll)
|
||||
},
|
||||
deactivated () {
|
||||
window.removeEventListener('scroll', this.handleScroll)
|
||||
},
|
||||
computed: {
|
||||
getRssUrl: _this => {
|
||||
return _this.apiUrl() + '/rss/playlists/' + _this.$route.query.list
|
||||
getRssUrl () {
|
||||
return this.$store.getters.apiUrl + '/rss/playlists/' + this.$route.query.list
|
||||
},
|
||||
|
||||
chunkedByFour () {
|
||||
return _chunk(this.playlist.relatedStreams, 4)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async fetchPlaylist () {
|
||||
return await await this.fetchJson(this.apiUrl() + '/playlists/' + this.$route.query.list)
|
||||
return this.$store.dispatch('fetchJson', {
|
||||
path: '/playlists/' + this.$route.query.list
|
||||
})
|
||||
},
|
||||
async getPlaylistData () {
|
||||
this.fetchPlaylist()
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
<template>
|
||||
<div class="uk-vertical-align uk-text-center uk-height-1-1 ">
|
||||
<form class="uk-panel uk-panel-box">
|
||||
<div class="uk-form-row">
|
||||
<input
|
||||
class="uk-width-1-1 uk-form-large uk-input uk-width-auto"
|
||||
type="text"
|
||||
v-model="username"
|
||||
autocomplete="username"
|
||||
placeholder="Username"
|
||||
/>
|
||||
</div>
|
||||
<div class="uk-form-row">
|
||||
<input
|
||||
class="uk-width-1-1 uk-form-large uk-input uk-width-auto"
|
||||
type="password"
|
||||
v-model="password"
|
||||
autocomplete="password"
|
||||
placeholder="Password"
|
||||
/>
|
||||
</div>
|
||||
<div class="uk-form-row">
|
||||
<a
|
||||
class="uk-width-1-1 uk-button uk-button-primary uk-button-large uk-width-auto"
|
||||
style="background: #222"
|
||||
@click="register"
|
||||
>Register</a
|
||||
>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
username: null,
|
||||
password: null
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
// TODO: Add Server Side check
|
||||
if (this.getAuthToken()) {
|
||||
this.$router.push('/')
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
register () {
|
||||
console.log('authToken' + this.hashCode(this.apiUrl()))
|
||||
this.fetchJson(this.apiUrl() + '/register', null, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
username: this.username,
|
||||
password: this.password
|
||||
})
|
||||
}).then(resp => {
|
||||
if (resp.token) {
|
||||
this.setPreference('authToken' + this.hashCode(this.apiUrl()), resp.token)
|
||||
window.location = '/' // done to bypass cache
|
||||
} else alert(resp.error)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<v-autocomplete
|
||||
v-model="select"
|
||||
:loading="requestInProgress"
|
||||
:items="searchSuggestions"
|
||||
:search-input.sync="searchText"
|
||||
cache-items
|
||||
class="mx-4"
|
||||
flat
|
||||
hide-no-data
|
||||
hide-details
|
||||
label="What are you looking for?"
|
||||
solo-inverted
|
||||
></v-autocomplete>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'SearchMenu',
|
||||
data () {
|
||||
return {
|
||||
selected: 0,
|
||||
select: '',
|
||||
searchText: '',
|
||||
requestInProgress: false,
|
||||
searchSuggestions: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
searchText (val) {
|
||||
if (val && val !== this.select) {
|
||||
this.refreshSuggestions()
|
||||
}
|
||||
},
|
||||
|
||||
select (val) {
|
||||
this.$router.push({
|
||||
name: 'SearchResults',
|
||||
query: { search_query: val }
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
async refreshSuggestions () {
|
||||
this.requestInProgress = true
|
||||
this.searchSuggestions = await this.$store.dispatch('fetchJson', {
|
||||
path: '/suggestions',
|
||||
params: {
|
||||
query: this.searchText
|
||||
}
|
||||
})
|
||||
this.searchSuggestions.unshift(this.searchText)
|
||||
this.requestInProgress = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -97,7 +97,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
async fetchResults () {
|
||||
return await await this.fetchJson(this.apiUrl() + '/search', {
|
||||
return this.fetchJson(this.apiUrl() + '/search', {
|
||||
q: this.$route.query.search_query,
|
||||
filter: this.selectedFilter
|
||||
})
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
class="uk-position-absolute uk-panel uk-box-shadow-large suggestions-container"
|
||||
:style="[{ background: secondaryBackgroundColor }]"
|
||||
>
|
||||
<ul class="uk-list uk-margin-remove uk-text-secondary">
|
||||
<li
|
||||
v-for="(suggestion, i) in searchSuggestions"
|
||||
:key="i"
|
||||
:style="[selected === i ? { background: secondaryForegroundColor } : {}]"
|
||||
@mouseover="onMouseOver(i)"
|
||||
@mousedown.stop="onClick(i)"
|
||||
class="uk-margin-remove suggestion"
|
||||
>
|
||||
{{ suggestion }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
searchText: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
selected: 0,
|
||||
searchSuggestions: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onKeyUp (e) {
|
||||
if (e.key === 'ArrowUp') {
|
||||
if (this.selected <= 0) {
|
||||
this.setSelected(this.searchSuggestions.length - 1)
|
||||
} else {
|
||||
this.setSelected(this.selected - 1)
|
||||
}
|
||||
e.preventDefault()
|
||||
} else if (e.key === 'ArrowDown') {
|
||||
if (this.selected >= this.searchSuggestions.length - 1) {
|
||||
this.setSelected(0)
|
||||
} else {
|
||||
this.setSelected(this.selected + 1)
|
||||
}
|
||||
e.preventDefault()
|
||||
} else {
|
||||
this.refreshSuggestions()
|
||||
}
|
||||
},
|
||||
async refreshSuggestions () {
|
||||
this.searchSuggestions = await this.fetchJson(this.apiUrl() + '/suggestions', {
|
||||
query: this.searchText
|
||||
})
|
||||
this.searchSuggestions.unshift(this.searchText)
|
||||
this.setSelected(0)
|
||||
},
|
||||
onMouseOver (i) {
|
||||
if (i !== this.selected) {
|
||||
this.selected = i
|
||||
}
|
||||
},
|
||||
onClick (i) {
|
||||
this.setSelected(i)
|
||||
this.$router.push({
|
||||
name: 'SearchResults',
|
||||
query: { search_query: this.searchSuggestions[i] }
|
||||
})
|
||||
},
|
||||
setSelected (val) {
|
||||
this.selected = val
|
||||
this.$emit('searchchange', this.searchSuggestions[this.selected])
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.suggestions-container {
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
max-width: 640px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 5px 0;
|
||||
z-index: 10;
|
||||
}
|
||||
.suggestion {
|
||||
padding: 4px 15px;
|
||||
}
|
||||
@media screen and (max-width: 959px) {
|
||||
.suggestions-container {
|
||||
max-width: calc(100% - 60px);
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 639px) {
|
||||
.suggestions-container {
|
||||
max-width: calc(100% - 30px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user