Nicer offer view
This commit is contained in:
parent
0abaee78f9
commit
12f95612d6
@ -74,36 +74,36 @@ h1, h2, h3, h4, h5, h6 {
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.4em;
|
||||
margin-bottom: .8em;
|
||||
font-size: 3.4rem;
|
||||
margin-bottom: .8rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 2.4em;
|
||||
padding-bottom: .2em;
|
||||
font-size: 2.4rem;
|
||||
padding-bottom: .2rem;
|
||||
border-bottom: 1px solid #333;
|
||||
margin-top: 1em;
|
||||
margin-bottom: .7em;
|
||||
margin-top: 1rem;
|
||||
margin-bottom: .7rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.8em;
|
||||
margin-bottom: .7em;
|
||||
font-size: 1.8rem;
|
||||
margin-bottom: .7rem;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 1rem;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 1.3em;
|
||||
margin-bottom: 1.3rem;
|
||||
}
|
||||
|
||||
ul, ol {
|
||||
font-size: 1.1rem;
|
||||
margin: 0 0 1.1rem 1.2em;
|
||||
margin: 0 0 1.1rem 1.2rem;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: .4em;
|
||||
margin-bottom: .4rem;
|
||||
}
|
||||
|
||||
terms-and-conditions li {
|
||||
@ -111,13 +111,13 @@ terms-and-conditions li {
|
||||
}
|
||||
|
||||
blockquote {
|
||||
padding-left: 1em;
|
||||
padding-left: 1rem;
|
||||
border-left: 3px solid #999;
|
||||
margin: 2.5em 2em;
|
||||
margin: 2.5rem 2rem;
|
||||
}
|
||||
|
||||
blockquote p {
|
||||
font: italic 1.2em/1.6 Georgia, "Times New Roman", Times, serif;
|
||||
font: italic 1.2rem/1.6 Georgia, "Times New Roman", Times, serif;
|
||||
}
|
||||
|
||||
local-businesses local-business p {
|
||||
|
@ -1,6 +1,8 @@
|
||||
{% extends "../base.html" %}
|
||||
{% block content %}
|
||||
<marketplace-offers>
|
||||
<h1>Rzeczy wystawione na sprzedaż</h1>
|
||||
|
||||
{% for offer in offers %}
|
||||
<marketplace-offer
|
||||
offer-id="{{offer.id}}"
|
||||
|
@ -1,6 +1,8 @@
|
||||
{% extends "../base.html" %}
|
||||
{% block content %}
|
||||
<marketplace-offers>
|
||||
<h1>Sprzedaż niepotrzebych rzeczy</h1>
|
||||
|
||||
<offer-form></offer-form>
|
||||
{% for offer in offers %}
|
||||
<marketplace-offer
|
||||
|
@ -1,14 +1,77 @@
|
||||
import { Component } from "../shared";
|
||||
import { Component, INPUT_STYLE } from "../shared";
|
||||
|
||||
customElements.define('marketplace-offer', class extends Component {
|
||||
static get observedAttributes() {
|
||||
return ['offer-id', 'description', 'picture-url']
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super(`
|
||||
<style>
|
||||
:host {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
section {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
img[src=""] { display: none; }
|
||||
img {
|
||||
width: 100%;
|
||||
}
|
||||
#preview {
|
||||
max-width: 50%;
|
||||
}
|
||||
#description {
|
||||
margin-left: 16px;
|
||||
width: 50%;
|
||||
}
|
||||
@media only screen and (min-device-width: 1200px) {
|
||||
#preview {
|
||||
max-width: 400px;
|
||||
max-height: 400px;
|
||||
}
|
||||
#description {
|
||||
min-height: 200px;
|
||||
}
|
||||
}
|
||||
${INPUT_STYLE}
|
||||
</style>
|
||||
<slot></slot>
|
||||
<section>
|
||||
<div id="preview">
|
||||
<img alt="" src="" id="picture" />
|
||||
</div>
|
||||
<p id="description"></p>
|
||||
</section>
|
||||
`);
|
||||
}
|
||||
|
||||
get offer_id() {
|
||||
const v = parseInt(this.getAttribute('offer-id'));
|
||||
return isNaN(v) ? null : v;
|
||||
}
|
||||
|
||||
set offer_id(v) {
|
||||
v = parseInt(v);
|
||||
this.setAttribute('offer-id', v);
|
||||
}
|
||||
|
||||
get description() {
|
||||
return this.getAttribute('description');
|
||||
}
|
||||
|
||||
set description(v) {
|
||||
this.setAttribute('description', v);
|
||||
this.shadowRoot.querySelector('#description').textContent = v;
|
||||
}
|
||||
|
||||
get picture_url() {
|
||||
return this.getAttribute('picture-url');
|
||||
}
|
||||
|
||||
set picture_url(v) {
|
||||
this.setAttribute('picture-url', v);
|
||||
this.shadowRoot.querySelector('#picture').src = v;
|
||||
}
|
||||
});
|
||||
|
@ -7,6 +7,10 @@ customElements.define('marketplace-offers', class extends Component {
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
h1 {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
<slot></slot>
|
||||
`);
|
||||
|
@ -33,14 +33,14 @@ customElements.define('offer-form', class extends Component {
|
||||
<input name="description" id="description" type="text" />
|
||||
</div>
|
||||
<div>
|
||||
<input id="submit" type="submit" value="Utwótz" />
|
||||
<input id="submit" type="submit" value="Utwórz" />
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
`);
|
||||
|
||||
this.addEventListener('image-input:uploaded', ev => {
|
||||
console.log(ev);
|
||||
this.picture_url = ev.detail;
|
||||
});
|
||||
}
|
||||
|
||||
@ -68,6 +68,16 @@ customElements.define('offer-form', class extends Component {
|
||||
this.shadowRoot.querySelector('#description').value = v;
|
||||
}
|
||||
|
||||
get picture_url() {
|
||||
return this.getAttribute('picture-url');
|
||||
}
|
||||
|
||||
set picture_url(v) {
|
||||
this.setAttribute('picture-url', v);
|
||||
this.shadowRoot.querySelector('#picture_url').value = v;
|
||||
this.shadowRoot.querySelector('image-input').url = v;
|
||||
}
|
||||
|
||||
#removeId() {
|
||||
const form = this.shadowRoot.querySelector('form');
|
||||
const input = form.querySelector('#offer-id');
|
||||
|
@ -144,6 +144,14 @@ customElements.define('image-input', class extends Component {
|
||||
view.innerHTML = `<img src="${ v }" alt=""/>`;
|
||||
}
|
||||
|
||||
get value() {
|
||||
return this.url;
|
||||
}
|
||||
|
||||
set value(v) {
|
||||
this.url = v;
|
||||
}
|
||||
|
||||
async #sendFile(file) {
|
||||
if (!file) return;
|
||||
const form = new FormData;
|
||||
@ -153,7 +161,11 @@ customElements.define('image-input', class extends Component {
|
||||
body: form,
|
||||
}).then(res => res.json()).then(({ path }) => {
|
||||
this.url = path;
|
||||
this.dispatchEvent(new CustomEvent('image-input:uploaded', { bubbles: true, composed: true }));
|
||||
this.dispatchEvent(new CustomEvent('image-input:uploaded', {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
detail: path
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1028,13 +1028,12 @@ pub async fn visible_offers(t: &mut T<'_>) -> Result<Vec<db::Offer>> {
|
||||
SELECT
|
||||
id,
|
||||
owner_id,
|
||||
name,
|
||||
description,
|
||||
picture_url,
|
||||
state,
|
||||
created_at
|
||||
FROM offers
|
||||
WHERE created_at + '2 weeks' <= now() AND state = 'Approved'
|
||||
WHERE created_at + '2 weeks' > now() AND state = 'Approved'
|
||||
"#,
|
||||
)
|
||||
.fetch_all(t)
|
||||
|
@ -8,7 +8,7 @@ use crate::model::view::Page;
|
||||
use crate::model::{db, view};
|
||||
use crate::routes::{Identity, Result};
|
||||
use crate::view::Helper;
|
||||
use crate::{authorize, ok_or_internal, queries};
|
||||
use crate::{authorize, not_xss, ok_or_internal, queries};
|
||||
|
||||
#[derive(Default, Template)]
|
||||
#[template(path = "./offers/index.html")]
|
||||
@ -56,6 +56,9 @@ async fn create_offer(
|
||||
let form = form.into_inner();
|
||||
dbg!(&form);
|
||||
|
||||
not_xss!(&form.description, t);
|
||||
not_xss!(&form.picture_url, t);
|
||||
|
||||
match queries::create_offer(
|
||||
&mut t,
|
||||
db::CreateOfferInput {
|
||||
@ -106,6 +109,9 @@ async fn update_offer(
|
||||
let form = form.into_inner();
|
||||
dbg!(&form);
|
||||
|
||||
not_xss!(&form.description, t);
|
||||
not_xss!(&form.picture_url, t);
|
||||
|
||||
match queries::update_offer(
|
||||
&mut t,
|
||||
db::UpdateOfferInput {
|
||||
|
@ -281,7 +281,6 @@ async fn login(form: web::Form<LoginForm>, db: Data<PgPool>, id: Identity) -> Re
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(
|
||||
AccountTemplate {
|
||||
account: Some(record),
|
||||
|
||||
page: Page::Login,
|
||||
..Default::default()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user