From 4a3f5a802578f7af4874ef46a0c51161900949c2 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 16 Apr 2026 10:17:54 +0200 Subject: [PATCH] Changed to Postgres --- .env.example | 14 +- .github/copilot-instructions.md | 5 +- Dockerfile | 19 +- __pycache__/test_paypal.cpython-314.pyc | Bin 0 -> 4837 bytes .../test_product_cache.cpython-314.pyc | Bin 0 -> 4270 bytes entrypoint.sh | 3 +- manage.py | 7 + proyecto/settings.py | 49 +- requirements.txt | 16 +- test_paypal.py | 179 +- .../__pycache__/0001_initial.cpython-314.pyc | Bin 0 -> 12686 bytes ...ioncode_code_mode_and_more.cpython-314.pyc | Bin 0 -> 1057 bytes ...003_order_transaction_code.cpython-314.pyc | Bin 0 -> 2049 bytes ...ation_stockreservationitem.cpython-314.pyc | Bin 0 -> 3052 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 166 bytes tienda/models.py | 12 +- tienda/static/css/custom.css.map | 1 - tienda/static/scss/bootstrap/_accordion.scss | 118 -- tienda/static/scss/bootstrap/_alert.scss | 57 - tienda/static/scss/bootstrap/_badge.scss | 29 - tienda/static/scss/bootstrap/_breadcrumb.scss | 28 - .../static/scss/bootstrap/_button-group.scss | 139 -- tienda/static/scss/bootstrap/_buttons.scss | 111 -- tienda/static/scss/bootstrap/_card.scss | 215 --- tienda/static/scss/bootstrap/_carousel.scss | 229 --- tienda/static/scss/bootstrap/_close.scss | 40 - tienda/static/scss/bootstrap/_containers.scss | 41 - tienda/static/scss/bootstrap/_dropdown.scss | 240 --- tienda/static/scss/bootstrap/_forms.scss | 9 - tienda/static/scss/bootstrap/_functions.scss | 263 --- tienda/static/scss/bootstrap/_grid.scss | 22 - tienda/static/scss/bootstrap/_helpers.scss | 7 - tienda/static/scss/bootstrap/_images.scss | 42 - tienda/static/scss/bootstrap/_list-group.scss | 174 -- tienda/static/scss/bootstrap/_mixins.scss | 42 - tienda/static/scss/bootstrap/_modal.scss | 219 --- tienda/static/scss/bootstrap/_nav.scss | 139 -- tienda/static/scss/bootstrap/_navbar.scss | 306 ---- tienda/static/scss/bootstrap/_offcanvas.scss | 79 - tienda/static/scss/bootstrap/_pagination.scss | 64 - tienda/static/scss/bootstrap/_popover.scss | 158 -- tienda/static/scss/bootstrap/_progress.scss | 48 - tienda/static/scss/bootstrap/_reboot.scss | 621 ------- tienda/static/scss/bootstrap/_root.scss | 16 - tienda/static/scss/bootstrap/_spinners.scss | 69 - tienda/static/scss/bootstrap/_tables.scss | 151 -- tienda/static/scss/bootstrap/_toasts.scss | 51 - tienda/static/scss/bootstrap/_tooltip.scss | 115 -- .../static/scss/bootstrap/_transitions.scss | 21 - tienda/static/scss/bootstrap/_type.scss | 104 -- tienda/static/scss/bootstrap/_utilities.scss | 594 ------- tienda/static/scss/bootstrap/_variables.scss | 1468 ----------------- .../static/scss/bootstrap/bootstrap-grid.scss | 65 - .../scss/bootstrap/bootstrap-reboot.scss | 15 - .../scss/bootstrap/bootstrap-utilities.scss | 18 - tienda/static/scss/bootstrap/bootstrap.scss | 52 - .../bootstrap/forms/_floating-labels.scss | 63 - .../scss/bootstrap/forms/_form-check.scss | 152 -- .../scss/bootstrap/forms/_form-control.scss | 219 --- .../scss/bootstrap/forms/_form-range.scss | 91 - .../scss/bootstrap/forms/_form-select.scss | 70 - .../scss/bootstrap/forms/_form-text.scss | 11 - .../scss/bootstrap/forms/_input-group.scss | 121 -- .../static/scss/bootstrap/forms/_labels.scss | 36 - .../scss/bootstrap/forms/_validation.scss | 12 - .../scss/bootstrap/helpers/_clearfix.scss | 3 - .../bootstrap/helpers/_colored-links.scss | 12 - .../scss/bootstrap/helpers/_position.scss | 30 - .../static/scss/bootstrap/helpers/_ratio.scss | 26 - .../bootstrap/helpers/_stretched-link.scss | 15 - .../bootstrap/helpers/_text-truncation.scss | 7 - .../bootstrap/helpers/_visually-hidden.scss | 8 - .../static/scss/bootstrap/mixins/_alert.scss | 11 - .../scss/bootstrap/mixins/_border-radius.scss | 78 - .../scss/bootstrap/mixins/_box-shadow.scss | 18 - .../scss/bootstrap/mixins/_breakpoints.scss | 127 -- .../scss/bootstrap/mixins/_buttons.scss | 133 -- .../static/scss/bootstrap/mixins/_caret.scss | 64 - .../scss/bootstrap/mixins/_clearfix.scss | 9 - .../scss/bootstrap/mixins/_color-scheme.scss | 7 - .../scss/bootstrap/mixins/_container.scss | 9 - .../scss/bootstrap/mixins/_deprecate.scss | 10 - .../static/scss/bootstrap/mixins/_forms.scss | 144 -- .../scss/bootstrap/mixins/_gradients.scss | 47 - .../static/scss/bootstrap/mixins/_grid.scss | 132 -- .../static/scss/bootstrap/mixins/_image.scss | 16 - .../scss/bootstrap/mixins/_list-group.scss | 24 - .../static/scss/bootstrap/mixins/_lists.scss | 7 - .../scss/bootstrap/mixins/_pagination.scss | 31 - .../scss/bootstrap/mixins/_reset-text.scss | 17 - .../static/scss/bootstrap/mixins/_resize.scss | 6 - .../bootstrap/mixins/_table-variants.scss | 21 - .../scss/bootstrap/mixins/_text-truncate.scss | 8 - .../scss/bootstrap/mixins/_transition.scss | 26 - .../scss/bootstrap/mixins/_utilities.scss | 68 - .../bootstrap/mixins/_visually-hidden.scss | 29 - .../static/scss/bootstrap/utilities/_api.scss | 47 - tienda/static/scss/bootstrap/vendor/_rfs.scss | 354 ---- tienda/static/scss/custom.scss | 303 ---- .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 168 bytes .../__pycache__/vat_filters.cpython-314.pyc | Bin 0 -> 1484 bytes tienda/tests.py | 110 +- 102 files changed, 274 insertions(+), 8942 deletions(-) create mode 100644 __pycache__/test_paypal.cpython-314.pyc create mode 100644 __pycache__/test_product_cache.cpython-314.pyc create mode 100644 tienda/migrations/__pycache__/0001_initial.cpython-314.pyc create mode 100644 tienda/migrations/__pycache__/0002_verificationcode_code_mode_and_more.cpython-314.pyc create mode 100644 tienda/migrations/__pycache__/0003_order_transaction_code.cpython-314.pyc create mode 100644 tienda/migrations/__pycache__/0004_product_stock_stockreservation_stockreservationitem.cpython-314.pyc create mode 100644 tienda/migrations/__pycache__/__init__.cpython-314.pyc delete mode 100644 tienda/static/css/custom.css.map delete mode 100644 tienda/static/scss/bootstrap/_accordion.scss delete mode 100644 tienda/static/scss/bootstrap/_alert.scss delete mode 100644 tienda/static/scss/bootstrap/_badge.scss delete mode 100644 tienda/static/scss/bootstrap/_breadcrumb.scss delete mode 100644 tienda/static/scss/bootstrap/_button-group.scss delete mode 100644 tienda/static/scss/bootstrap/_buttons.scss delete mode 100644 tienda/static/scss/bootstrap/_card.scss delete mode 100644 tienda/static/scss/bootstrap/_carousel.scss delete mode 100644 tienda/static/scss/bootstrap/_close.scss delete mode 100644 tienda/static/scss/bootstrap/_containers.scss delete mode 100644 tienda/static/scss/bootstrap/_dropdown.scss delete mode 100644 tienda/static/scss/bootstrap/_forms.scss delete mode 100644 tienda/static/scss/bootstrap/_functions.scss delete mode 100644 tienda/static/scss/bootstrap/_grid.scss delete mode 100644 tienda/static/scss/bootstrap/_helpers.scss delete mode 100644 tienda/static/scss/bootstrap/_images.scss delete mode 100644 tienda/static/scss/bootstrap/_list-group.scss delete mode 100644 tienda/static/scss/bootstrap/_mixins.scss delete mode 100644 tienda/static/scss/bootstrap/_modal.scss delete mode 100644 tienda/static/scss/bootstrap/_nav.scss delete mode 100644 tienda/static/scss/bootstrap/_navbar.scss delete mode 100644 tienda/static/scss/bootstrap/_offcanvas.scss delete mode 100644 tienda/static/scss/bootstrap/_pagination.scss delete mode 100644 tienda/static/scss/bootstrap/_popover.scss delete mode 100644 tienda/static/scss/bootstrap/_progress.scss delete mode 100644 tienda/static/scss/bootstrap/_reboot.scss delete mode 100644 tienda/static/scss/bootstrap/_root.scss delete mode 100644 tienda/static/scss/bootstrap/_spinners.scss delete mode 100644 tienda/static/scss/bootstrap/_tables.scss delete mode 100644 tienda/static/scss/bootstrap/_toasts.scss delete mode 100644 tienda/static/scss/bootstrap/_tooltip.scss delete mode 100644 tienda/static/scss/bootstrap/_transitions.scss delete mode 100644 tienda/static/scss/bootstrap/_type.scss delete mode 100644 tienda/static/scss/bootstrap/_utilities.scss delete mode 100644 tienda/static/scss/bootstrap/_variables.scss delete mode 100644 tienda/static/scss/bootstrap/bootstrap-grid.scss delete mode 100644 tienda/static/scss/bootstrap/bootstrap-reboot.scss delete mode 100644 tienda/static/scss/bootstrap/bootstrap-utilities.scss delete mode 100644 tienda/static/scss/bootstrap/bootstrap.scss delete mode 100644 tienda/static/scss/bootstrap/forms/_floating-labels.scss delete mode 100644 tienda/static/scss/bootstrap/forms/_form-check.scss delete mode 100644 tienda/static/scss/bootstrap/forms/_form-control.scss delete mode 100644 tienda/static/scss/bootstrap/forms/_form-range.scss delete mode 100644 tienda/static/scss/bootstrap/forms/_form-select.scss delete mode 100644 tienda/static/scss/bootstrap/forms/_form-text.scss delete mode 100644 tienda/static/scss/bootstrap/forms/_input-group.scss delete mode 100644 tienda/static/scss/bootstrap/forms/_labels.scss delete mode 100644 tienda/static/scss/bootstrap/forms/_validation.scss delete mode 100644 tienda/static/scss/bootstrap/helpers/_clearfix.scss delete mode 100644 tienda/static/scss/bootstrap/helpers/_colored-links.scss delete mode 100644 tienda/static/scss/bootstrap/helpers/_position.scss delete mode 100644 tienda/static/scss/bootstrap/helpers/_ratio.scss delete mode 100644 tienda/static/scss/bootstrap/helpers/_stretched-link.scss delete mode 100644 tienda/static/scss/bootstrap/helpers/_text-truncation.scss delete mode 100644 tienda/static/scss/bootstrap/helpers/_visually-hidden.scss delete mode 100644 tienda/static/scss/bootstrap/mixins/_alert.scss delete mode 100644 tienda/static/scss/bootstrap/mixins/_border-radius.scss delete mode 100644 tienda/static/scss/bootstrap/mixins/_box-shadow.scss delete mode 100644 tienda/static/scss/bootstrap/mixins/_breakpoints.scss delete mode 100644 tienda/static/scss/bootstrap/mixins/_buttons.scss delete mode 100644 tienda/static/scss/bootstrap/mixins/_caret.scss delete mode 100644 tienda/static/scss/bootstrap/mixins/_clearfix.scss delete mode 100644 tienda/static/scss/bootstrap/mixins/_color-scheme.scss delete mode 100644 tienda/static/scss/bootstrap/mixins/_container.scss delete mode 100644 tienda/static/scss/bootstrap/mixins/_deprecate.scss delete mode 100644 tienda/static/scss/bootstrap/mixins/_forms.scss delete mode 100644 tienda/static/scss/bootstrap/mixins/_gradients.scss delete mode 100644 tienda/static/scss/bootstrap/mixins/_grid.scss delete mode 100644 tienda/static/scss/bootstrap/mixins/_image.scss delete mode 100644 tienda/static/scss/bootstrap/mixins/_list-group.scss delete mode 100644 tienda/static/scss/bootstrap/mixins/_lists.scss delete mode 100644 tienda/static/scss/bootstrap/mixins/_pagination.scss delete mode 100644 tienda/static/scss/bootstrap/mixins/_reset-text.scss delete mode 100644 tienda/static/scss/bootstrap/mixins/_resize.scss delete mode 100644 tienda/static/scss/bootstrap/mixins/_table-variants.scss delete mode 100644 tienda/static/scss/bootstrap/mixins/_text-truncate.scss delete mode 100644 tienda/static/scss/bootstrap/mixins/_transition.scss delete mode 100644 tienda/static/scss/bootstrap/mixins/_utilities.scss delete mode 100644 tienda/static/scss/bootstrap/mixins/_visually-hidden.scss delete mode 100644 tienda/static/scss/bootstrap/utilities/_api.scss delete mode 100644 tienda/static/scss/bootstrap/vendor/_rfs.scss delete mode 100644 tienda/static/scss/custom.scss create mode 100644 tienda/templatetags/__pycache__/__init__.cpython-314.pyc create mode 100644 tienda/templatetags/__pycache__/vat_filters.cpython-314.pyc diff --git a/.env.example b/.env.example index 2f79012..9a50945 100644 --- a/.env.example +++ b/.env.example @@ -3,13 +3,13 @@ SECRET_KEY=django-insecure-change-me DEBUG=True ALLOWED_HOSTS=localhost,127.0.0.1 -# MySQL (opcional, si MYSQL_ENABLED=False se usa SQLite) -MYSQL_ENABLED=False -MYSQL_DATABASE=tienda -MYSQL_USER=tienda_user -MYSQL_PASSWORD= -MYSQL_HOST=127.0.0.1 -MYSQL_PORT=3306 +# PostgreSQL (por defecto habilitado; si POSTGRES_ENABLED=False se usa SQLite) +POSTGRES_ENABLED=True +POSTGRES_DB=tienda +POSTGRES_USER=tienda_user +POSTGRES_PASSWORD= +POSTGRES_HOST=127.0.0.1 +POSTGRES_PORT=5432 # Redis REDIS_URL=redis://127.0.0.1:6379/1 diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 2d61140..b3470d7 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -27,10 +27,7 @@ Templates use Django's inheritance pattern: - **Collection directory**: `STATIC_ROOT = BASE_DIR / 'staticfiles'` for production - **Development dirs**: `STATICFILES_DIRS` includes `tienda/static/` - **URL prefix**: `STATIC_URL = 'static/'` -- **SCSS compilation**: Styles are authored in [tienda/static/scss/custom.scss](tienda/static/scss/custom.scss) and compiled to [tienda/static/css/custom.css](tienda/static/css/custom.css) - - **IMPORTANT**: Always edit `custom.scss`, never `custom.css` - CSS file is auto-generated - - Compile with Sass compiler (npm sass or similar) -- Bootstrap CSS is vendored in `tienda/static/css/styles.css` - don't add CDN links +- **Custom CSS**: Edit [tienda/static/css/custom.css](tienda/static/css/custom.css) directly - no compilation needed ## Media Files (User Uploads) Configuration - **Storage location**: `MEDIA_ROOT = BASE_DIR / 'tienda' / 'static' / 'media'` - all uploads go here diff --git a/Dockerfile b/Dockerfile index 90766f0..acf9d2d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,19 +1,28 @@ -FROM python:3.14-slim +FROM python:3.14-alpine ENV PYTHONDONTWRITEBYTECODE=1 ENV PYTHONUNBUFFERED=1 -ENV DEBIANFRONTEND=noninteractive WORKDIR /app -RUN apt update && apt install -y build-essential figlet libpq-dev default-libmysqlclient-dev pkg-config && rm -rf /var/lib/apt/lists/* +RUN adduser -D -S app COPY requirements.txt /app/ -RUN pip install --no-cache-dir -r requirements.txt +RUN apk --no-cache update && apk --no-cache upgrade +RUN apk add --no-cache --virtual .build-deps build-base mariadb-dev libffi-dev \ + && apk add --no-cache mariadb-connector-c \ + && pip install --no-cache-dir -r requirements.txt \ + && apk del .build-deps COPY . /app/ RUN chmod +x /app/entrypoint.sh + EXPOSE 8000 RUN mkdir -pv /fonts COPY tienda/static/fonts/ /fonts/ -CMD ["/app/entrypoint.sh"] \ No newline at end of file + +RUN chown -R app: /app /fonts +RUN chmod 770 /app/entrypoint.sh +USER app + +ENTRYPOINT ["/bin/sh", "/app/entrypoint.sh"] \ No newline at end of file diff --git a/__pycache__/test_paypal.cpython-314.pyc b/__pycache__/test_paypal.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bc3a279e693c8da88e7be839b8e2c785dd04c5f0 GIT binary patch literal 4837 zcmbstTWlN0agTSTP9#OkvL2K~Q71~4C0io(N~}=wL!}stHYL(4*-Ze)%$Yn{7gHp2 zcXTYGXq>``ji5jjq(Jo104h+R?q7<2G#>>TAT5wKDR6X|ki7_K(54^xV`>#GnxD=d zc_t;xD2gnOyR*BqGqdx$Ii7GdSrN3&fxn2qaUk?JGBKK|3Orl_;5NcYL01u`LX<-3 zqe(I8BdyTb)PXSFfs)M%^MV;O)6XH40Lm`(0@H`4s)Tysbie)^HfJxwqIEegi5Z2< z@Dk4{f~*L<#3gwyo=&Zb*Rv8I7eD-Eic1Jwl;4Q*No(*WA)Zxu$Gn`_ zhN{zhQ*FO))p4cYknS>t4;glTBp-N(3tgt70|r)Ygc~Q|1JuS08ntn+bpU6gwr4=i=vgm98Rjw*HJBS) zFk(M>7hH!7=0X=B@73{~ffG;Hp;p1YJTHJ$jmV7_&()ort-C|b`)GXXG4BJf0q>)u z(~t9cq#?*Gdo*g<85b@>R}`w@q(3>uPIP-2Eik}=iMKD=Uj zBHxxe4z;X4WYDXPedsDx!|j2{&X~@af>ikZ3M5h@nxT7;NP#?l;~dBX-n~zrGyCPy z^MpHNUNJ|{7$<9^;SjyZ;2M5+KhNQS);@oJZs}Ykwj5kp2`!yljx9#!FNK4-!^Ydy zD+`JurmoBIUS{$VznX`RH6Y3%-f0<6iEv zAc?DDoKGdv`|ArK#ThiAi16o{Ij(w|2om&jxwhI$ARG!Vt;9m}e$K!2RVz?m%F$l0 zH`@jvp#AmTA972PnmqH7T<2q_mxBQuTmiyv>%?Bsmgg_j>K*@5cBD%6$8STGM9Lfq zDhxSsgA>;?X-VPr+ei`=BmBCMQiLpd8v{SMu1tz2Kd0GZv72O;PQ_xHZC;R}yh_K# z1fL~uX}~2S2PG*DWmT3$1uQK`!k2VSLZu~UI58zFd@{LL1YQ5uNiPT0&^1G^!Y#dI z$)2u*Yn9P~S$Gl@>8XM1o8B_5MjSgPIT0=rmco8IHkAHHwO`9!rWca3Y|rF)8qoT;mFO5Ep_Kjh1g@HH%)e zj)TG^F)nEA%UM39h{{H`w`LigG?S6%BJFBs4ppfuOy~>$=Hy zR7hOHVPYsAcCJ-wdhj$-t`Nf;&d2ddjfMpUU}=4cV2z#)t}z_Q^#0=8Q)>7 zcf&sj-&y)QGw>zTcyH)VWQS=~ts@0y6aX^cwIH)qwayfnS+Zq!Z9P})8PE5OtF8&v zI$2<*VEH3wF?0J_vj|xS$>leFXT6WrVU+*hJ1OnyNyaC@>>sQ-itnbJn%PHmQ!; z0(%O8&8A@qW_O8g zE3&mH+3YVCysUvPu> zZ6)sL_N@|k?0!dyJAOY%y1BB=(&H}Etf#9?TRrXNj`qVXW!l-}C?D~7tq+mMX}f1H zFHp$tEZW?8o4aV^9@w}Y`(d?ZvS6PAU^B8E{#oQF5w(9xZF#C-f4bxxC_0Z9oX0nr z(vgmLrr(<0`u=A}Mt52}RoCQu^S=uHBJ|#j+I8l$*0cXGqs|k%aIqG(Wujo8+&R>~ z`MvG$77vX+I5hg+NO58w9(7`Vr@3v5-U=68-n`4JcKg)!u|o5>Zk&6*0@FpD!`fY7 zTmak~dOh;*-G~X8U{-o;g71*)QS!anoTx7fRYjm3s7T0<5=4^sV3+)HAvKatk8pMt%7$!GI4v#1 z8u<@FCZ8u|nxd$$8Jc1qvWT*Nj^JtfCqw>6DMJ=u?Duj7y7SKr`}(tA!?a7M_+PgA BQ=R|- literal 0 HcmV?d00001 diff --git a/__pycache__/test_product_cache.cpython-314.pyc b/__pycache__/test_product_cache.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..54b98ca56873d84749cf64417a2e53ee4897febd GIT binary patch literal 4270 zcmb_fTWk~A89w82?D5!f5<>#v;!Fr3F(eKN6o`S{0x`jmi#2h*3r(;lo=Gxbd!{qv zl(-ks?N)1{wy>}gY1N9Lm8u|BD%HNAwhvUipze#am<>Cm-HKAFQXd-1O0C+L{%7oo zClFRzZO?odw)SL!g6`@YJ zG?zgW5n7{J#|EUi$2_d_z?%s1fVKsVxvdB+(E{4Gpa7LSOOGTKQPvnF_xrnbkNY#K<$+l$2pKLDdqnVlXC*qd|Fw z9?~27P97QRA5M&fW3k9k|43qRxbJHN;anZ?&IkY+R0T~FGm~n7(4El|0FYG%M$+mA zCw!0y*`GhH!d@RG%uTj!Z<%hgt`cjmT6j03(X!tWikf$7g2Eid5?>hRJ;*4I+RA&A zUhHFwKDLTvmTUpeDD?sie98oCj}so$W0P%`vsJ*oMg({e>%iQsv!|+pKI$=XqoBi! zqZ!35npk8|7KDlyU6$2a6DztxnJWlYVo4?~8u%(4CS}z?w#V%gnHM}oTV#IzUDTVH zm6>(39=3Wf!~`DE4W-%o%X&@x=sN3qiH;L&&Hl3ea+SrBjW6>yqc>XFT2t1lIIA;d z!0L*(KHqO~vcq!6tgizi+8naOa#QQRIQAF46ElkW#ux5pecZlwB=%UN>i=P}(_(SG z#o|hAHpCt5hHAua>>=0OZ;U%%-j6%aq66m$Vjd1j=7^P=E=%zR?#N3 z75HTObs9@4Q6eFtgXC5u5`jRjJz8o?(2rD6)r2&M8`2uBDc2bbkHkXENQLXzN&_pm z6-xulVhx`B{D;ht#7uEB(EBVcF2yn9oGM^RJcrw!(Gr1WoKuE$s?3|nZUPK?`Np+h zFs6V?8x1iz2h$$u3o$wo$UyLXF8iD_Bncq!Y3cYDm;s3N8X zXu;E>Dry|l3GB)wm*H_MRzanseZgQbyB*Fj4D;k?KfoqH^SyTycW3MwfNmF588CP$ zpi@as6DB2PMz59unNwyG@H;8!&ZHuMb&6iA3P~x$uk7GXY!i900|GR=qatU;NW=XA z&d8F&e1%DinJjoo{2LVF>>g~(9@CZ)VKNKIue7D4F1BZDMNT*a>S$Q|ibWwN+lrB& zT>dp+gA1iJzLcbR?}H3>x*}wFF)a!iO$y~|z%iXnU)fu56J)SwLbs*WEN%jp&60Sy zB2vsuA#C!Wj`(6u4GCt8f`jzz;$Ev;%z(9sUv{cbNVXrw<2w zdKE-3LFj5_ot@nRTHA3Y6`B&x;?`|-r#4P?%;)#pb5HNgH+PVNkP-SDl8?n zgd(IMA9%f1R)h&bOHQqp(_89ukm`8t&3}zJ0&D;2kVdL!UX2%X`^#$#dm&k!o7PoI8tDhp}9!{c4dqx>VnI{q)t- z*S?;omm2*y8h_e2*ZZKcGw*%mZv4pIY)C&)^z<(ITW?4|krw@j7W{|qoVnjrIFo$f z=NJ9i1%GxKp>Glq+jE4PPTKwjzeBcX#xHEJwow~Qu!OhAZ24ipyd1d{xgy?fDSGx{ z3F|{e&!MGt8?N_W?Y(wzZqvhcyXLirzCC$oS<}8Eb^Mi@e(G*CK)P=S7kk1BJ>f$4 z@q(|v=sB^}u<5#ZRlIh7?&QOU;O*@X>-Xj9GUUD@bpRZ4rDo1KPtJa4{%FD5Rit(s zK5CgeIj9vt#qYg15Iw zg#fu`{blizIO}@g-IgZ}td9ASdC;i8;5|{KB4y#hlB6r1+0(P93f}f26)>1vi&UFI zynfep=Uexi3*LbuH3&DHmx`1h?|63?scs&t-+gjF`h7#B38p{ncc1DaKeTN-wUhjCXBE&o zl}MyHF_TCHs&!`~!Ar?RLbpjO6oYeIW>V6fLS|Z2Aem`MbY7U?vMI=SptG`G4P_kq zR4^?;P9D zA9*VL4@b)+K@iXEBw>F}A%cF4s+S#zAm5?CM=zrK1yo;X2o`o9E26$f$nlQnEzjHD rzoO= 2 and sys.argv[1] == "test": + has_test_labels = any(not arg.startswith("-") for arg in sys.argv[2:]) + if not has_test_labels: + sys.argv.append("tienda.tests") + try: from django.core.management import execute_from_command_line except ImportError as exc: diff --git a/proyecto/settings.py b/proyecto/settings.py index 1c9c39f..9eac4f9 100644 --- a/proyecto/settings.py +++ b/proyecto/settings.py @@ -15,6 +15,9 @@ import os, sys from pathlib import Path +RUNNING_TESTS = any(arg in {'test', 'pytest'} for arg in sys.argv) or 'PYTEST_CURRENT_TEST' in os.environ + + def load_dotenv(dotenv_path: Path) -> None: if not dotenv_path.exists(): return @@ -126,21 +129,24 @@ WSGI_APPLICATION = 'proyecto.wsgi.application' # Database # https://docs.djangoproject.com/en/6.0/ref/settings/#databases -# Activa MySQL con MYSQL_ENABLED=True en el .env; si no, se usa SQLite. +# Usa PostgreSQL por defecto (POSTGRES_ENABLED=True); si no, SQLite. -if env_bool('MYSQL_ENABLED', False): +if RUNNING_TESTS: DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.mysql', - 'NAME': os.getenv('MYSQL_DATABASE', 'tienda'), - 'USER': os.getenv('MYSQL_USER', 'root'), - 'PASSWORD': os.getenv('MYSQL_PASSWORD', ''), - 'HOST': os.getenv('MYSQL_HOST', '127.0.0.1'), - 'PORT': env_int('MYSQL_PORT', 3306), - 'OPTIONS': { - 'charset': 'utf8mb4', - 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", - }, + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } + } +elif env_bool('POSTGRES_ENABLED', True): + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': os.getenv('POSTGRES_DB', 'tienda'), + 'USER': os.getenv('POSTGRES_USER', 'postgres'), + 'PASSWORD': os.getenv('POSTGRES_PASSWORD', ''), + 'HOST': os.getenv('POSTGRES_HOST', '127.0.0.1'), + 'PORT': env_int('POSTGRES_PORT', 5432), } } else: @@ -207,16 +213,7 @@ STATICFILES_FINDERS = [ 'compressor.finders.CompressorFinder' ] -COMPRESS_PRECOMPILERS = ( - ('text/x-scss', 'sass {infile} {outfile} --load-path=tienda/static/scss'), -) - -import shutil -SASS_BINARY = shutil.which('sass') -if SASS_BINARY: - COMPRESS_PRECOMPILERS = ( - ('text/x-scss', f'{SASS_BINARY} {{infile}} {{outfile}} --load-path=tienda/static/scss'), - ) +COMPRESS_PRECOMPILERS = () # Media files (User uploads) MEDIA_URL = 'media/' @@ -267,7 +264,7 @@ SECURITY = os.getenv('SECURITY', 'tls') SMTP_USERNAME = os.getenv('SMTP_USERNAME', None) SMTP_PASSWORD = os.getenv('SMTP_PASSWORD', None) SMTP_EMAIL = os.getenv("SMTP_EMAIL", None) -if SMTP_USERNAME is None or SMTP_PASSWORD is None or SMTP_EMAIL is None: +if not RUNNING_TESTS and (SMTP_USERNAME is None or SMTP_PASSWORD is None or SMTP_EMAIL is None): print("Se requieren credenciales SMTP") sys.exit(1) @@ -354,7 +351,11 @@ logging.captureWarnings(True) -EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' +if RUNNING_TESTS: + EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend' +else: + EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' + EMAIL_HOST = SMTP_ENDPOINT EMAIL_PORT = SMTP_PORT EMAIL_USE_TLS = (SECURITY == 'tls') # True si SECURITY es 'tls' diff --git a/requirements.txt b/requirements.txt index 0f5f3e8..4b6da18 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,28 +9,26 @@ click==8.3.1 click-didyoumean==0.3.1 click-plugins==1.1.1.2 click-repl==0.3.0 -cryptography==46.0.4 -Django==6.0.1 +cryptography==46.0.7 +Django==6.0.4 django-appconf==1.2.0 -django-libsass==0.9 django-redis==5.4.0 django_compressor==4.6.0 gunicorn==25.1.0 idna==3.11 Jinja2==3.1.6 kombu==5.6.2 -libsass==0.23.0 MarkupSafe==3.0.3 packaging==26.0 paypalrestsdk==1.13.3 -pillow==12.1.0 +pillow==12.2.0 prompt_toolkit==3.0.52 pycparser==3.0 -pyOpenSSL==25.3.0 +pyOpenSSL==26.0.0 python-dateutil==2.9.0.post0 rcssmin==1.2.2 redis==5.2.1 -requests==2.32.5 +requests==2.33.0 rjsmin==1.2.5 six==1.17.0 sqlparse==0.5.5 @@ -42,5 +40,5 @@ urllib3==2.6.3 vine==5.1.0 wcwidth==0.6.0 whitenoise==6.12.0 -mysqlclient -fpdf2==2.8.7 \ No newline at end of file +fpdf2==2.8.7 +psycopg2-binary==2.9.11 \ No newline at end of file diff --git a/test_paypal.py b/test_paypal.py index c3e39da..fe056d0 100644 --- a/test_paypal.py +++ b/test_paypal.py @@ -7,98 +7,103 @@ import os import sys import django -# Configurar Django -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proyecto.settings') -sys.path.insert(0, os.path.dirname(__file__)) -django.setup() +def main() -> None: + # Configurar Django solo cuando se ejecuta script manualmente. + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proyecto.settings') + sys.path.insert(0, os.path.dirname(__file__)) + django.setup() -from django.conf import settings + from django.conf import settings -print("=" * 60) -print("TEST DE CONFIGURACIÓN DE PAYPAL") -print("=" * 60) + print("=" * 60) + print("TEST DE CONFIGURACIÓN DE PAYPAL") + print("=" * 60) -# Verificar configuración -print("\n1. Verificando configuración en settings.py:") -print(f" PAYPAL_MODE: {settings.PAYPAL_MODE}") -print(f" PAYPAL_CLIENT_ID: {settings.PAYPAL_CLIENT_ID[:20]}..." if settings.PAYPAL_CLIENT_ID else " ❌ NO CONFIGURADO") -print(f" PAYPAL_CLIENT_SECRET: {settings.PAYPAL_CLIENT_SECRET[:20]}..." if settings.PAYPAL_CLIENT_SECRET else " ❌ NO CONFIGURADO") + # Verificar configuración + print("\n1. Verificando configuración en settings.py:") + print(f" PAYPAL_MODE: {settings.PAYPAL_MODE}") + print(f" PAYPAL_CLIENT_ID: {settings.PAYPAL_CLIENT_ID[:20]}..." if settings.PAYPAL_CLIENT_ID else " ❌ NO CONFIGURADO") + print(f" PAYPAL_CLIENT_SECRET: {settings.PAYPAL_CLIENT_SECRET[:20]}..." if settings.PAYPAL_CLIENT_SECRET else " ❌ NO CONFIGURADO") -# Intentar importar paypalrestsdk -print("\n2. Verificando SDK de PayPal:") -try: - import paypalrestsdk - print(" ✓ paypalrestsdk importado correctamente") - print(f" Versión: {paypalrestsdk.__version__ if hasattr(paypalrestsdk, '__version__') else 'Desconocida'}") -except ImportError as e: - print(f" ❌ Error: {e}") - print(" SOLUCIÓN: pip install paypalrestsdk") - sys.exit(1) + # Intentar importar paypalrestsdk + print("\n2. Verificando SDK de PayPal:") + try: + import paypalrestsdk + print(" ✓ paypalrestsdk importado correctamente") + print(f" Versión: {paypalrestsdk.__version__ if hasattr(paypalrestsdk, '__version__') else 'Desconocida'}") + except ImportError as e: + print(f" ❌ Error: {e}") + print(" SOLUCIÓN: pip install paypalrestsdk") + sys.exit(1) -# Intentar conectar a PayPal -print("\n3. Probando conexión a PayPal:") -try: - paypalrestsdk.configure({ - "mode": settings.PAYPAL_MODE, - "client_id": settings.PAYPAL_CLIENT_ID, - "client_secret": settings.PAYPAL_CLIENT_SECRET - }) - print(" ✓ Configuración de PayPal aplicada") - - # Intentar crear un pago de prueba - print("\n4. Creando pago de prueba:") - test_payment = paypalrestsdk.Payment({ - "intent": "sale", - "payer": { - "payment_method": "paypal" - }, - "redirect_urls": { - "return_url": "http://localhost:8000/test-return", - "cancel_url": "http://localhost:8000/test-cancel" - }, - "transactions": [ - { - "amount": { - "total": "10.00", - "currency": "EUR", - "details": { - "subtotal": "10.00", - "tax": "0", - "shipping": "0" - } - }, - "description": "Pago de prueba", - "item_list": { - "items": [ - { - "name": "Test Item", - "sku": "test_1", - "price": "10.00", - "currency": "EUR", - "quantity": 1 + # Intentar conectar a PayPal + print("\n3. Probando conexión a PayPal:") + try: + paypalrestsdk.configure({ + "mode": settings.PAYPAL_MODE, + "client_id": settings.PAYPAL_CLIENT_ID, + "client_secret": settings.PAYPAL_CLIENT_SECRET + }) + print(" ✓ Configuración de PayPal aplicada") + + # Intentar crear un pago de prueba + print("\n4. Creando pago de prueba:") + test_payment = paypalrestsdk.Payment({ + "intent": "sale", + "payer": { + "payment_method": "paypal" + }, + "redirect_urls": { + "return_url": "http://localhost:8000/test-return", + "cancel_url": "http://localhost:8000/test-cancel" + }, + "transactions": [ + { + "amount": { + "total": "10.00", + "currency": "EUR", + "details": { + "subtotal": "10.00", + "tax": "0", + "shipping": "0" } - ] + }, + "description": "Pago de prueba", + "item_list": { + "items": [ + { + "name": "Test Item", + "sku": "test_1", + "price": "10.00", + "currency": "EUR", + "quantity": 1 + } + ] + } } - } - ] - }) - - if test_payment.create(): - print(" ✓ Pago creado exitosamente") - print(f" Payment ID: {test_payment.id}") - for link in test_payment.links: - if link.rel == "approval_url": - print(f" URL de aprobación: {link.href}") - else: - print(" ❌ Error al crear el pago:") - if hasattr(test_payment, 'error') and test_payment.error: - print(f" {test_payment.error}") - -except Exception as e: - print(f" ❌ Error de conexión: {e}") - import traceback - traceback.print_exc() + ] + }) -print("\n" + "=" * 60) -print("TEST COMPLETADO") -print("=" * 60) + if test_payment.create(): + print(" ✓ Pago creado exitosamente") + print(f" Payment ID: {test_payment.id}") + for link in test_payment.links: + if link.rel == "approval_url": + print(f" URL de aprobación: {link.href}") + else: + print(" ❌ Error al crear el pago:") + if hasattr(test_payment, 'error') and test_payment.error: + print(f" {test_payment.error}") + + except Exception as e: + print(f" ❌ Error de conexión: {e}") + import traceback + traceback.print_exc() + + print("\n" + "=" * 60) + print("TEST COMPLETADO") + print("=" * 60) + + +if __name__ == '__main__': + main() diff --git a/tienda/migrations/__pycache__/0001_initial.cpython-314.pyc b/tienda/migrations/__pycache__/0001_initial.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..407f3a4dacf51d8bb575645ac9fba4d867a2faf3 GIT binary patch literal 12686 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 RdaykkZ2vDPolY-d_kT65S9bsa literal 0 HcmV?d00001 diff --git a/tienda/migrations/__pycache__/0002_verificationcode_code_mode_and_more.cpython-314.pyc b/tienda/migrations/__pycache__/0002_verificationcode_code_mode_and_more.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cdafd5e8bf6ab8aa27e9979a2cd9e0c3058b3385 GIT binary patch literal 1057 zcmZ`%&rcIU6rTOjZFgHrDH2S82n7!tv_)d##TXh5L87FY5Dq5oWZ9k4G27iTJ5@ms z91Lgw4E+y0@+VY60-1vsPu`k9^y7T9aJeSH5oiFYJO>*JQ#Mql-T_l!0YG&cK&`ISj6^j0Khy@8X;5DTcIv03w#uzG z*`p34VGwbn9eUW0+>r`^?2ufZ2yg`IfGH3#wPA=txw69ada9QDTQI<)83n5KbggjX z-Wbf6Rj4&os6QGu22%+V6^l2j6lnanV!E*gGtf+GjH;DYW`EJiRMM=cbHEy1><)s;%*~+X{(`BcAqf)9Lz5_~pDqJ`VO+OYB>*V<>RinCo#& zH3{}TuE+Jjwyja=Ae9zzqZ^R@F8%_xgz*L=IPe^vTUl9ofJi_XaeP~)rpP?Z@5t5; z=But7b^|8TRaiUBLmXi?Uvr}9ZAd*k$1^BC8zF8X*>~5+0_PCg?>fHhN3d~(nuJEo zCjkyZx$WVOI2s2o!4Z}A^GwzA)@9>Vm(+aPa%jxCRrMK8aM;1gTbV*AV!}BWIgC-V z+hsUHh)xRmrC5Nwl~&ls70(Go-Aavy2iRp{ROt-S{U!+s3ke}U|+eGRr6T0}B8gQhvcO$SKe9Fqex!D*iG=a3vEp~YSz$UJG0 zL!F3-vH(Mg9ic$%hE-Z3je{xRDgyn#tK%6VOuU0Dz>JZ zZi=I^6`d$pwKTh;xC9&4%2T0iS5$M5j%9C+Pvj=2re|*7nZ28zD|{l~D}GwK|KPKS z>QY(LmseJeM~}^lWjjx>OR8(1uWvjZx_ss8@Q2q%u76Yx9C?%gJbTyvO^(G~LIv25 zFB!5i-2BQ3lmdmL7Mhm}eg=vO+H4*33j7-=F?jdG%xx5yjL40%}4w* z-)96}2{`=!_gms+-uGKLO=-(>^3kjb;+~rW3lLg=U zIdrFjkc7@c<)Nk`6^Nl*no2`+SkrM43fV=VimqB_1y;&XUPUont7@8{iyqhE6W|FH ztyM=;iLNXgx~aMORG3PvAH43ME%wqQy-c86mJO5Wn06NBZ2n$$yf`zLSH|Zia!NtY zP0l>PtS0}Voz3N^iqrJ;zdp;(7N)beaz!fW>xN5Q?>Urr)ipg8qP*%jE^T$ot9nIM zbj=_(#;kxeWV2`~&%$$=)BgV6-d)s1b>No&PHT?e*{OZ$}1e zx!+V%3_)${6eVU-+A{D zVnd9R0}CyM=#j%F3%Z~jTlqeqwl1*R=P4C|?rR8%}`ibBH* zgI(1G+|r1mJgKTC^8nH*1@H+2)-){LvYA@b9YDWsl?~m+EGJaVYT6_NG3J>ljjyWM zlc^+Et-=ObwJon_y^_+f?dbl0LAwHjAD&rOR04khOI4z~isFUj72E3z+zVzsk_5&r z0r?W`2}t^QFBoVOYO{M`Bqesm?pI=Wqw{PdcCiuf+Kpd$6~FL(+a~{Gye^mON_i)) zy=~#8aPxNZm6)vejBF;i#mT+ambmc6?E{z0TRwGyO4=jUTCvmGk{9MdaEaz&l^CX* zF5?Xc1_bL7%vuS@7-8*k81KRBS&DcQZuHVt^wOUQ1ke26Be~;6 literal 0 HcmV?d00001 diff --git a/tienda/migrations/__pycache__/0004_product_stock_stockreservation_stockreservationitem.cpython-314.pyc b/tienda/migrations/__pycache__/0004_product_stock_stockreservation_stockreservationitem.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ac75c7eea53c109a4ab50549181ae486602c32b1 GIT binary patch literal 3052 zcmcguO;FoL6qaOL{((5QYvKR_Odvld#n93gALtK(P~19=5s)^Wf<{=2Q6o$4YE9!# ze{$&b+#||sWpo$1d^PrcEGX|H`N*}>C5W_oDNAnoq^_U+qmzxP(x zqGuu;{NBCvleQP)xL;YP^9!^akJg}ZpWEalKF<*z-a=kj_7UF*8}sG;%K;Kt7Ku2* z^>L$|$y-tGxr8zSQ+VIx?Kon&J>ndLo; zCZuaw0nqVT;c+AhK%YN366u)^0}w^>DY(8a+_|UVQeC+7 zfEzev-QY&FIQ*pTBn1`IC*UqVIVSaQB#M_$7$2Bz>v~4WhNQs`GpC;Pg@1X{L$J@2 z6~-Sc4EW_w(g2;}kW&}L=*cL(esv1U?tPoZe)h$^wRCJF<+VOhh-WCk=Ls?N(8mU!P zwwLxCcY9!?{u*qDCS2xZ@Y!L*$^b_Y#aQ0ONgi=)MMMZ~&pJkE5)yrkh(U9!QO_pgymOlZtyzorng&n1hI{z`OAKKe>MrN8LGy7`?BiHTNLf6oD z$%Bz4JNA0l&@n2tch2dbX!cJ$NbWB_T>2sZecma&*C@Q_6i}mpoI<5hs6Ysx@GC5m z+rp;s7ke4P@7@c79B?C!SB1lPI2k<(^a3>lE`1&~SDs4E;NER#DAydyeHT9%TCih_ zt@yy+l5=6Qd0}#2{5Jee*vTz7a?4I`rIA~4a(5cJI}nM+UuOZmF1*cn8hXd&>5kB* z`nhKMx&5VY^WWs1xk6*E;LNQz=GL9LjmF%Dty?g$4xfoIadg$4xF#Hi1Ig%Nl#5@q z$6v9>UIiWWMUUb=u$L<%3Gwqc@JdHAnGo&wvLdT)Wxa3LY$rAF8%)zZZF|Wyw!It) zKc3-cubZ=;3a6Q0*SW-|hUUDQ@Cv>SUG}kRu`i!PAJ6lTM2;W*kxT!~T|E*n@#2>e PCpO-QjsM9($Mx|ypRMwu literal 0 HcmV?d00001 diff --git a/tienda/migrations/__pycache__/__init__.cpython-314.pyc b/tienda/migrations/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a48244fcd1ab438e6cda84f8d119cab11d79faaa GIT binary patch literal 166 zcmdPq_I|p@<2{{|u76<*c8PpPQgQ&r7bTWt=I0gb$H!;pWtPOp k>lIYq;;_lhPbtkwwJTx;nhCPC7{vI*%*e=C#0+Es0JbA2nE(I) literal 0 HcmV?d00001 diff --git a/tienda/models.py b/tienda/models.py index ab57703..6b74a54 100644 --- a/tienda/models.py +++ b/tienda/models.py @@ -36,10 +36,20 @@ class VerificationCode(models.Model): choices = VerificationModes.choices, default = VerificationModes.VERIFY_ACCOUNT ) + + def generate(user: User, code_mode: str) -> VerificationCode: + while True: + code = "".join(random.choices(string.ascii_letters+string.digits+string.punctuation)) + if not VerificationCode.objects.filter(code=code).exists(): + return VerificationCode.objects.create( + code = code, + user = user, + code_mode = code_mode + ) # Create your models here. class Category(models.Model): - name = models.CharField(max_length=200) + name = models.CharField(max_length=200, unique=True) def __str__(self): return self.name diff --git a/tienda/static/css/custom.css.map b/tienda/static/css/custom.css.map deleted file mode 100644 index e4356e9..0000000 --- a/tienda/static/css/custom.css.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sourceRoot":"","sources":["../scss/custom.scss"],"names":[],"mappings":"AAuBA;EACI;IANA;IACA;;;AAUJ;EACI;IAZA;IACA;;;AAgBJ;EACI;IAlBA;IACA;;;AAsBJ;EACI,OAzCS;EA0CT;;;AAIA;EACI;EACA;EACA;;;AAKJ;EACI;EACA;EACA;;AAJR;EAMI;;;AAIA;EACI;EACA;EACA;EACA;;AACA;EACI;EACA;;;AAMZ;EACI;EACA;;AAEA;EACI;;AAGJ;EACI;;AAGJ;EACI;;AAEA;EACI;;AAIR;EACI;;AAGJ;EACI;EACA;;AAEA;EACI;EACA;;AAIR;EACI;EACA;;AAEA;EACI;EACA;;AAIR;EACI;EACA;EACA;;AAEA;EACI;EACA;;;AAMZ;EACI;IACI;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;EAEA;IACI;;EAIR;IACI;IACA;;EAEA;IACI;IACA;;EAIR;IACI;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;EAEA;IACI;IACA;;EAIR;IACI;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;EAEA;IACI;;;AAKZ;EACI;IACI;;EAGJ;IACI;;EAGJ;IACI;;;AAMJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;EACA;;AAGJ;EACI;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;;;AAKZ;EACI;EACA;;;AAKA;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;EACA","file":"custom.css"} \ No newline at end of file diff --git a/tienda/static/scss/bootstrap/_accordion.scss b/tienda/static/scss/bootstrap/_accordion.scss deleted file mode 100644 index fc62ceb..0000000 --- a/tienda/static/scss/bootstrap/_accordion.scss +++ /dev/null @@ -1,118 +0,0 @@ -// -// Base styles -// - -.accordion-button { - position: relative; - display: flex; - align-items: center; - width: 100%; - padding: $accordion-button-padding-y $accordion-button-padding-x; - @include font-size($font-size-base); - color: $accordion-button-color; - text-align: left; // Reset button style - background-color: $accordion-button-bg; - border: 0; - @include border-radius(0); - overflow-anchor: none; - @include transition($accordion-transition); - - &:not(.collapsed) { - color: $accordion-button-active-color; - background-color: $accordion-button-active-bg; - box-shadow: inset 0 ($accordion-border-width * -1) 0 $accordion-border-color; - - &::after { - background-image: escape-svg($accordion-button-active-icon); - transform: $accordion-icon-transform; - } - } - - // Accordion icon - &::after { - flex-shrink: 0; - width: $accordion-icon-width; - height: $accordion-icon-width; - margin-left: auto; - content: ""; - background-image: escape-svg($accordion-button-icon); - background-repeat: no-repeat; - background-size: $accordion-icon-width; - @include transition($accordion-icon-transition); - } - - &:hover { - z-index: 2; - } - - &:focus { - z-index: 3; - border-color: $accordion-button-focus-border-color; - outline: 0; - box-shadow: $accordion-button-focus-box-shadow; - } -} - -.accordion-header { - margin-bottom: 0; -} - -.accordion-item { - background-color: $accordion-bg; - border: $accordion-border-width solid $accordion-border-color; - - &:first-of-type { - @include border-top-radius($accordion-border-radius); - - .accordion-button { - @include border-top-radius($accordion-inner-border-radius); - } - } - - &:not(:first-of-type) { - border-top: 0; - } - - // Only set a border-radius on the last item if the accordion is collapsed - &:last-of-type { - @include border-bottom-radius($accordion-border-radius); - - .accordion-button { - &.collapsed { - @include border-bottom-radius($accordion-inner-border-radius); - } - } - - .accordion-collapse { - @include border-bottom-radius($accordion-border-radius); - } - } -} - -.accordion-body { - padding: $accordion-body-padding-y $accordion-body-padding-x; -} - - -// Flush accordion items -// -// Remove borders and border-radius to keep accordion items edge-to-edge. - -.accordion-flush { - .accordion-collapse { - border-width: 0; - } - - .accordion-item { - border-right: 0; - border-left: 0; - @include border-radius(0); - - &:first-child { border-top: 0; } - &:last-child { border-bottom: 0; } - - .accordion-button { - @include border-radius(0); - } - } -} diff --git a/tienda/static/scss/bootstrap/_alert.scss b/tienda/static/scss/bootstrap/_alert.scss deleted file mode 100644 index 34f1e84..0000000 --- a/tienda/static/scss/bootstrap/_alert.scss +++ /dev/null @@ -1,57 +0,0 @@ -// -// Base styles -// - -.alert { - position: relative; - padding: $alert-padding-y $alert-padding-x; - margin-bottom: $alert-margin-bottom; - border: $alert-border-width solid transparent; - @include border-radius($alert-border-radius); -} - -// Headings for larger alerts -.alert-heading { - // Specified to prevent conflicts of changing $headings-color - color: inherit; -} - -// Provide class for links that match alerts -.alert-link { - font-weight: $alert-link-font-weight; -} - - -// Dismissible alerts -// -// Expand the right padding and account for the close button's positioning. - -.alert-dismissible { - padding-right: $alert-dismissible-padding-r; - - // Adjust close link position - .btn-close { - position: absolute; - top: 0; - right: 0; - z-index: $stretched-link-z-index + 1; - padding: $alert-padding-y * 1.25 $alert-padding-x; - } -} - - -// scss-docs-start alert-modifiers -// Generate contextual modifier classes for colorizing the alert. - -@each $state, $value in $theme-colors { - $alert-background: shift-color($value, $alert-bg-scale); - $alert-border: shift-color($value, $alert-border-scale); - $alert-color: shift-color($value, $alert-color-scale); - @if (contrast-ratio($alert-background, $alert-color) < $min-contrast-ratio) { - $alert-color: mix($value, color-contrast($alert-background), abs($alert-color-scale)); - } - .alert-#{$state} { - @include alert-variant($alert-background, $alert-border, $alert-color); - } -} -// scss-docs-end alert-modifiers diff --git a/tienda/static/scss/bootstrap/_badge.scss b/tienda/static/scss/bootstrap/_badge.scss deleted file mode 100644 index 08df1b8..0000000 --- a/tienda/static/scss/bootstrap/_badge.scss +++ /dev/null @@ -1,29 +0,0 @@ -// Base class -// -// Requires one of the contextual, color modifier classes for `color` and -// `background-color`. - -.badge { - display: inline-block; - padding: $badge-padding-y $badge-padding-x; - @include font-size($badge-font-size); - font-weight: $badge-font-weight; - line-height: 1; - color: $badge-color; - text-align: center; - white-space: nowrap; - vertical-align: baseline; - @include border-radius($badge-border-radius); - @include gradient-bg(); - - // Empty badges collapse automatically - &:empty { - display: none; - } -} - -// Quick fix for badges in buttons -.btn .badge { - position: relative; - top: -1px; -} diff --git a/tienda/static/scss/bootstrap/_breadcrumb.scss b/tienda/static/scss/bootstrap/_breadcrumb.scss deleted file mode 100644 index f7fafe7..0000000 --- a/tienda/static/scss/bootstrap/_breadcrumb.scss +++ /dev/null @@ -1,28 +0,0 @@ -.breadcrumb { - display: flex; - flex-wrap: wrap; - padding: $breadcrumb-padding-y $breadcrumb-padding-x; - margin-bottom: $breadcrumb-margin-bottom; - @include font-size($breadcrumb-font-size); - list-style: none; - background-color: $breadcrumb-bg; - @include border-radius($breadcrumb-border-radius); -} - -.breadcrumb-item { - // The separator between breadcrumbs (by default, a forward-slash: "/") - + .breadcrumb-item { - padding-left: $breadcrumb-item-padding-x; - - &::before { - float: left; // Suppress inline spacings and underlining of the separator - padding-right: $breadcrumb-item-padding-x; - color: $breadcrumb-divider-color; - content: var(--#{$variable-prefix}breadcrumb-divider, escape-svg($breadcrumb-divider)) #{"/* rtl:"} var(--#{$variable-prefix}breadcrumb-divider, escape-svg($breadcrumb-divider-flipped)) #{"*/"}; - } - } - - &.active { - color: $breadcrumb-active-color; - } -} diff --git a/tienda/static/scss/bootstrap/_button-group.scss b/tienda/static/scss/bootstrap/_button-group.scss deleted file mode 100644 index 13aa056..0000000 --- a/tienda/static/scss/bootstrap/_button-group.scss +++ /dev/null @@ -1,139 +0,0 @@ -// Make the div behave like a button -.btn-group, -.btn-group-vertical { - position: relative; - display: inline-flex; - vertical-align: middle; // match .btn alignment given font-size hack above - - > .btn { - position: relative; - flex: 1 1 auto; - } - - // Bring the hover, focused, and "active" buttons to the front to overlay - // the borders properly - > .btn-check:checked + .btn, - > .btn-check:focus + .btn, - > .btn:hover, - > .btn:focus, - > .btn:active, - > .btn.active { - z-index: 1; - } -} - -// Optional: Group multiple button groups together for a toolbar -.btn-toolbar { - display: flex; - flex-wrap: wrap; - justify-content: flex-start; - - .input-group { - width: auto; - } -} - -.btn-group { - // Prevent double borders when buttons are next to each other - > .btn:not(:first-child), - > .btn-group:not(:first-child) { - margin-left: -$btn-border-width; - } - - // Reset rounded corners - > .btn:not(:last-child):not(.dropdown-toggle), - > .btn-group:not(:last-child) > .btn { - @include border-end-radius(0); - } - - // The left radius should be 0 if the button is: - // - the "third or more" child - // - the second child and the previous element isn't `.btn-check` (making it the first child visually) - // - part of a btn-group which isn't the first child - > .btn:nth-child(n + 3), - > :not(.btn-check) + .btn, - > .btn-group:not(:first-child) > .btn { - @include border-start-radius(0); - } -} - -// Sizing -// -// Remix the default button sizing classes into new ones for easier manipulation. - -.btn-group-sm > .btn { @extend .btn-sm; } -.btn-group-lg > .btn { @extend .btn-lg; } - - -// -// Split button dropdowns -// - -.dropdown-toggle-split { - padding-right: $btn-padding-x * .75; - padding-left: $btn-padding-x * .75; - - &::after, - .dropup &::after, - .dropend &::after { - margin-left: 0; - } - - .dropstart &::before { - margin-right: 0; - } -} - -.btn-sm + .dropdown-toggle-split { - padding-right: $btn-padding-x-sm * .75; - padding-left: $btn-padding-x-sm * .75; -} - -.btn-lg + .dropdown-toggle-split { - padding-right: $btn-padding-x-lg * .75; - padding-left: $btn-padding-x-lg * .75; -} - - -// The clickable button for toggling the menu -// Set the same inset shadow as the :active state -.btn-group.show .dropdown-toggle { - @include box-shadow($btn-active-box-shadow); - - // Show no shadow for `.btn-link` since it has no other button styles. - &.btn-link { - @include box-shadow(none); - } -} - - -// -// Vertical button groups -// - -.btn-group-vertical { - flex-direction: column; - align-items: flex-start; - justify-content: center; - - > .btn, - > .btn-group { - width: 100%; - } - - > .btn:not(:first-child), - > .btn-group:not(:first-child) { - margin-top: -$btn-border-width; - } - - // Reset rounded corners - > .btn:not(:last-child):not(.dropdown-toggle), - > .btn-group:not(:last-child) > .btn { - @include border-bottom-radius(0); - } - - > .btn ~ .btn, - > .btn-group:not(:first-child) > .btn { - @include border-top-radius(0); - } -} diff --git a/tienda/static/scss/bootstrap/_buttons.scss b/tienda/static/scss/bootstrap/_buttons.scss deleted file mode 100644 index ee4287c..0000000 --- a/tienda/static/scss/bootstrap/_buttons.scss +++ /dev/null @@ -1,111 +0,0 @@ -// -// Base styles -// - -.btn { - display: inline-block; - font-family: $btn-font-family; - font-weight: $btn-font-weight; - line-height: $btn-line-height; - color: $body-color; - text-align: center; - text-decoration: if($link-decoration == none, null, none); - white-space: $btn-white-space; - vertical-align: middle; - cursor: if($enable-button-pointers, pointer, null); - user-select: none; - background-color: transparent; - border: $btn-border-width solid transparent; - @include button-size($btn-padding-y, $btn-padding-x, $btn-font-size, $btn-border-radius); - @include transition($btn-transition); - - &:hover { - color: $body-color; - text-decoration: if($link-hover-decoration == underline, none, null); - } - - .btn-check:focus + &, - &:focus { - outline: 0; - box-shadow: $btn-focus-box-shadow; - } - - .btn-check:checked + &, - .btn-check:active + &, - &:active, - &.active { - @include box-shadow($btn-active-box-shadow); - - &:focus { - @include box-shadow($btn-focus-box-shadow, $btn-active-box-shadow); - } - } - - &:disabled, - &.disabled, - fieldset:disabled & { - pointer-events: none; - opacity: $btn-disabled-opacity; - @include box-shadow(none); - } -} - - -// -// Alternate buttons -// - -// scss-docs-start btn-variant-loops -@each $color, $value in $theme-colors { - .btn-#{$color} { - @include button-variant($value, $value); - } -} - -@each $color, $value in $theme-colors { - .btn-outline-#{$color} { - @include button-outline-variant($value); - } -} -// scss-docs-end btn-variant-loops - - -// -// Link buttons -// - -// Make a button look and behave like a link -.btn-link { - font-weight: $font-weight-normal; - color: $btn-link-color; - text-decoration: $link-decoration; - - &:hover { - color: $btn-link-hover-color; - text-decoration: $link-hover-decoration; - } - - &:focus { - text-decoration: $link-hover-decoration; - } - - &:disabled, - &.disabled { - color: $btn-link-disabled-color; - } - - // No need for an active state here -} - - -// -// Button Sizes -// - -.btn-lg { - @include button-size($btn-padding-y-lg, $btn-padding-x-lg, $btn-font-size-lg, $btn-border-radius-lg); -} - -.btn-sm { - @include button-size($btn-padding-y-sm, $btn-padding-x-sm, $btn-font-size-sm, $btn-border-radius-sm); -} diff --git a/tienda/static/scss/bootstrap/_card.scss b/tienda/static/scss/bootstrap/_card.scss deleted file mode 100644 index b077858..0000000 --- a/tienda/static/scss/bootstrap/_card.scss +++ /dev/null @@ -1,215 +0,0 @@ -// -// Base styles -// - -.card { - position: relative; - display: flex; - flex-direction: column; - min-width: 0; // See https://github.com/twbs/bootstrap/pull/22740#issuecomment-305868106 - height: $card-height; - word-wrap: break-word; - background-color: $card-bg; - background-clip: border-box; - border: $card-border-width solid $card-border-color; - @include border-radius($card-border-radius); - - > hr { - margin-right: 0; - margin-left: 0; - } - - > .list-group { - border-top: inherit; - border-bottom: inherit; - - &:first-child { - border-top-width: 0; - @include border-top-radius($card-inner-border-radius); - } - - &:last-child { - border-bottom-width: 0; - @include border-bottom-radius($card-inner-border-radius); - } - } - - // Due to specificity of the above selector (`.card > .list-group`), we must - // use a child selector here to prevent double borders. - > .card-header + .list-group, - > .list-group + .card-footer { - border-top: 0; - } -} - -.card-body { - // Enable `flex-grow: 1` for decks and groups so that card blocks take up - // as much space as possible, ensuring footers are aligned to the bottom. - flex: 1 1 auto; - padding: $card-spacer-y $card-spacer-x; - color: $card-color; -} - -.card-title { - margin-bottom: $card-title-spacer-y; -} - -.card-subtitle { - margin-top: -$card-title-spacer-y * .5; - margin-bottom: 0; -} - -.card-text:last-child { - margin-bottom: 0; -} - -.card-link { - &:hover { - text-decoration: none; - } - - + .card-link { - margin-left: $card-spacer-x; - } -} - -// -// Optional textual caps -// - -.card-header { - padding: $card-cap-padding-y $card-cap-padding-x; - margin-bottom: 0; // Removes the default margin-bottom of - color: $card-cap-color; - background-color: $card-cap-bg; - border-bottom: $card-border-width solid $card-border-color; - - &:first-child { - @include border-radius($card-inner-border-radius $card-inner-border-radius 0 0); - } -} - -.card-footer { - padding: $card-cap-padding-y $card-cap-padding-x; - color: $card-cap-color; - background-color: $card-cap-bg; - border-top: $card-border-width solid $card-border-color; - - &:last-child { - @include border-radius(0 0 $card-inner-border-radius $card-inner-border-radius); - } -} - - -// -// Header navs -// - -.card-header-tabs { - margin-right: -$card-cap-padding-x * .5; - margin-bottom: -$card-cap-padding-y; - margin-left: -$card-cap-padding-x * .5; - border-bottom: 0; - - @if $nav-tabs-link-active-bg != $card-bg { - .nav-link.active { - background-color: $card-bg; - border-bottom-color: $card-bg; - } - } -} - -.card-header-pills { - margin-right: -$card-cap-padding-x * .5; - margin-left: -$card-cap-padding-x * .5; -} - -// Card image -.card-img-overlay { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - padding: $card-img-overlay-padding; - @include border-radius($card-inner-border-radius); -} - -.card-img, -.card-img-top, -.card-img-bottom { - width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch -} - -.card-img, -.card-img-top { - @include border-top-radius($card-inner-border-radius); -} - -.card-img, -.card-img-bottom { - @include border-bottom-radius($card-inner-border-radius); -} - - -// -// Card groups -// - -.card-group { - // The child selector allows nested `.card` within `.card-group` - // to display properly. - > .card { - margin-bottom: $card-group-margin; - } - - @include media-breakpoint-up(sm) { - display: flex; - flex-flow: row wrap; - // The child selector allows nested `.card` within `.card-group` - // to display properly. - > .card { - // Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4 - flex: 1 0 0%; - margin-bottom: 0; - - + .card { - margin-left: 0; - border-left: 0; - } - - // Handle rounded corners - @if $enable-rounded { - &:not(:last-child) { - @include border-end-radius(0); - - .card-img-top, - .card-header { - // stylelint-disable-next-line property-disallowed-list - border-top-right-radius: 0; - } - .card-img-bottom, - .card-footer { - // stylelint-disable-next-line property-disallowed-list - border-bottom-right-radius: 0; - } - } - - &:not(:first-child) { - @include border-start-radius(0); - - .card-img-top, - .card-header { - // stylelint-disable-next-line property-disallowed-list - border-top-left-radius: 0; - } - .card-img-bottom, - .card-footer { - // stylelint-disable-next-line property-disallowed-list - border-bottom-left-radius: 0; - } - } - } - } - } -} diff --git a/tienda/static/scss/bootstrap/_carousel.scss b/tienda/static/scss/bootstrap/_carousel.scss deleted file mode 100644 index 3d8fb15..0000000 --- a/tienda/static/scss/bootstrap/_carousel.scss +++ /dev/null @@ -1,229 +0,0 @@ -// Notes on the classes: -// -// 1. .carousel.pointer-event should ideally be pan-y (to allow for users to scroll vertically) -// even when their scroll action started on a carousel, but for compatibility (with Firefox) -// we're preventing all actions instead -// 2. The .carousel-item-start and .carousel-item-end is used to indicate where -// the active slide is heading. -// 3. .active.carousel-item is the current slide. -// 4. .active.carousel-item-start and .active.carousel-item-end is the current -// slide in its in-transition state. Only one of these occurs at a time. -// 5. .carousel-item-next.carousel-item-start and .carousel-item-prev.carousel-item-end -// is the upcoming slide in transition. - -.carousel { - position: relative; -} - -.carousel.pointer-event { - touch-action: pan-y; -} - -.carousel-inner { - position: relative; - width: 100%; - overflow: hidden; - @include clearfix(); -} - -.carousel-item { - position: relative; - display: none; - float: left; - width: 100%; - margin-right: -100%; - backface-visibility: hidden; - @include transition($carousel-transition); -} - -.carousel-item.active, -.carousel-item-next, -.carousel-item-prev { - display: block; -} - -/* rtl:begin:ignore */ -.carousel-item-next:not(.carousel-item-start), -.active.carousel-item-end { - transform: translateX(100%); -} - -.carousel-item-prev:not(.carousel-item-end), -.active.carousel-item-start { - transform: translateX(-100%); -} - -/* rtl:end:ignore */ - - -// -// Alternate transitions -// - -.carousel-fade { - .carousel-item { - opacity: 0; - transition-property: opacity; - transform: none; - } - - .carousel-item.active, - .carousel-item-next.carousel-item-start, - .carousel-item-prev.carousel-item-end { - z-index: 1; - opacity: 1; - } - - .active.carousel-item-start, - .active.carousel-item-end { - z-index: 0; - opacity: 0; - @include transition(opacity 0s $carousel-transition-duration); - } -} - - -// -// Left/right controls for nav -// - -.carousel-control-prev, -.carousel-control-next { - position: absolute; - top: 0; - bottom: 0; - z-index: 1; - // Use flex for alignment (1-3) - display: flex; // 1. allow flex styles - align-items: center; // 2. vertically center contents - justify-content: center; // 3. horizontally center contents - width: $carousel-control-width; - padding: 0; - color: $carousel-control-color; - text-align: center; - background: none; - border: 0; - opacity: $carousel-control-opacity; - @include transition($carousel-control-transition); - - // Hover/focus state - &:hover, - &:focus { - color: $carousel-control-color; - text-decoration: none; - outline: 0; - opacity: $carousel-control-hover-opacity; - } -} -.carousel-control-prev { - left: 0; - background-image: if($enable-gradients, linear-gradient(90deg, rgba($black, .25), rgba($black, .001)), null); -} -.carousel-control-next { - right: 0; - background-image: if($enable-gradients, linear-gradient(270deg, rgba($black, .25), rgba($black, .001)), null); -} - -// Icons for within -.carousel-control-prev-icon, -.carousel-control-next-icon { - display: inline-block; - width: $carousel-control-icon-width; - height: $carousel-control-icon-width; - background-repeat: no-repeat; - background-position: 50%; - background-size: 100% 100%; -} - -/* rtl:options: { - "autoRename": true, - "stringMap":[ { - "name" : "prev-next", - "search" : "prev", - "replace" : "next" - } ] -} */ -.carousel-control-prev-icon { - background-image: escape-svg($carousel-control-prev-icon-bg); -} -.carousel-control-next-icon { - background-image: escape-svg($carousel-control-next-icon-bg); -} - -// Optional indicator pips/controls -// -// Add a container (such as a list) with the following class and add an item (ideally a focusable control, -// like a button) with data-bs-target for each slide your carousel holds. - -.carousel-indicators { - position: absolute; - right: 0; - bottom: 0; - left: 0; - z-index: 2; - display: flex; - justify-content: center; - padding: 0; - // Use the .carousel-control's width as margin so we don't overlay those - margin-right: $carousel-control-width; - margin-bottom: 1rem; - margin-left: $carousel-control-width; - list-style: none; - - [data-bs-target] { - box-sizing: content-box; - flex: 0 1 auto; - width: $carousel-indicator-width; - height: $carousel-indicator-height; - padding: 0; - margin-right: $carousel-indicator-spacer; - margin-left: $carousel-indicator-spacer; - text-indent: -999px; - cursor: pointer; - background-color: $carousel-indicator-active-bg; - background-clip: padding-box; - border: 0; - // Use transparent borders to increase the hit area by 10px on top and bottom. - border-top: $carousel-indicator-hit-area-height solid transparent; - border-bottom: $carousel-indicator-hit-area-height solid transparent; - opacity: $carousel-indicator-opacity; - @include transition($carousel-indicator-transition); - } - - .active { - opacity: $carousel-indicator-active-opacity; - } -} - - -// Optional captions -// -// - -.carousel-caption { - position: absolute; - right: (100% - $carousel-caption-width) * .5; - bottom: $carousel-caption-spacer; - left: (100% - $carousel-caption-width) * .5; - padding-top: $carousel-caption-padding-y; - padding-bottom: $carousel-caption-padding-y; - color: $carousel-caption-color; - text-align: center; -} - -// Dark mode carousel - -.carousel-dark { - .carousel-control-prev-icon, - .carousel-control-next-icon { - filter: $carousel-dark-control-icon-filter; - } - - .carousel-indicators [data-bs-target] { - background-color: $carousel-dark-indicator-active-bg; - } - - .carousel-caption { - color: $carousel-dark-caption-color; - } -} diff --git a/tienda/static/scss/bootstrap/_close.scss b/tienda/static/scss/bootstrap/_close.scss deleted file mode 100644 index 32a0f68..0000000 --- a/tienda/static/scss/bootstrap/_close.scss +++ /dev/null @@ -1,40 +0,0 @@ -// transparent background and border properties included for button version. -// iOS requires the button element instead of an anchor tag. -// If you want the anchor version, it requires `href="#"`. -// See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile - -.btn-close { - box-sizing: content-box; - width: $btn-close-width; - height: $btn-close-height; - padding: $btn-close-padding-y $btn-close-padding-x; - color: $btn-close-color; - background: transparent escape-svg($btn-close-bg) center / $btn-close-width auto no-repeat; // include transparent for button elements - border: 0; // for button elements - @include border-radius(); - opacity: $btn-close-opacity; - - // Override 's hover style - &:hover { - color: $btn-close-color; - text-decoration: none; - opacity: $btn-close-hover-opacity; - } - - &:focus { - outline: 0; - box-shadow: $btn-close-focus-shadow; - opacity: $btn-close-focus-opacity; - } - - &:disabled, - &.disabled { - pointer-events: none; - user-select: none; - opacity: $btn-close-disabled-opacity; - } -} - -.btn-close-white { - filter: $btn-close-white-filter; -} diff --git a/tienda/static/scss/bootstrap/_containers.scss b/tienda/static/scss/bootstrap/_containers.scss deleted file mode 100644 index f88f1e5..0000000 --- a/tienda/static/scss/bootstrap/_containers.scss +++ /dev/null @@ -1,41 +0,0 @@ -// Container widths -// -// Set the container width, and override it for fixed navbars in media queries. - -@if $enable-grid-classes { - // Single container class with breakpoint max-widths - .container, - // 100% wide container at all breakpoints - .container-fluid { - @include make-container(); - } - - // Responsive containers that are 100% wide until a breakpoint - @each $breakpoint, $container-max-width in $container-max-widths { - .container-#{$breakpoint} { - @extend .container-fluid; - } - - @include media-breakpoint-up($breakpoint, $grid-breakpoints) { - %responsive-container-#{$breakpoint} { - max-width: $container-max-width; - } - - // Extend each breakpoint which is smaller or equal to the current breakpoint - $extend-breakpoint: true; - - @each $name, $width in $grid-breakpoints { - @if ($extend-breakpoint) { - .container#{breakpoint-infix($name, $grid-breakpoints)} { - @extend %responsive-container-#{$breakpoint}; - } - - // Once the current breakpoint is reached, stop extending - @if ($breakpoint == $name) { - $extend-breakpoint: false; - } - } - } - } - } -} diff --git a/tienda/static/scss/bootstrap/_dropdown.scss b/tienda/static/scss/bootstrap/_dropdown.scss deleted file mode 100644 index adc1143..0000000 --- a/tienda/static/scss/bootstrap/_dropdown.scss +++ /dev/null @@ -1,240 +0,0 @@ -// The dropdown wrapper (`
`) -.dropup, -.dropend, -.dropdown, -.dropstart { - position: relative; -} - -.dropdown-toggle { - white-space: nowrap; - - // Generate the caret automatically - @include caret(); -} - -// The dropdown menu -.dropdown-menu { - position: absolute; - z-index: $zindex-dropdown; - display: none; // none by default, but block on "open" of the menu - min-width: $dropdown-min-width; - padding: $dropdown-padding-y $dropdown-padding-x; - margin: 0; // Override default margin of ul - @include font-size($dropdown-font-size); - color: $dropdown-color; - text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer) - list-style: none; - background-color: $dropdown-bg; - background-clip: padding-box; - border: $dropdown-border-width solid $dropdown-border-color; - @include border-radius($dropdown-border-radius); - @include box-shadow($dropdown-box-shadow); - - &[data-bs-popper] { - top: 100%; - left: 0; - margin-top: $dropdown-spacer; - } -} - -// scss-docs-start responsive-breakpoints -// We deliberately hardcode the `bs-` prefix because we check -// this custom property in JS to determine Popper's positioning - -@each $breakpoint in map-keys($grid-breakpoints) { - @include media-breakpoint-up($breakpoint) { - $infix: breakpoint-infix($breakpoint, $grid-breakpoints); - - .dropdown-menu#{$infix}-start { - --bs-position: start; - - &[data-bs-popper] { - right: auto; - left: 0; - } - } - - .dropdown-menu#{$infix}-end { - --bs-position: end; - - &[data-bs-popper] { - right: 0; - left: auto; - } - } - } -} -// scss-docs-end responsive-breakpoints - -// Allow for dropdowns to go bottom up (aka, dropup-menu) -// Just add .dropup after the standard .dropdown class and you're set. -.dropup { - .dropdown-menu[data-bs-popper] { - top: auto; - bottom: 100%; - margin-top: 0; - margin-bottom: $dropdown-spacer; - } - - .dropdown-toggle { - @include caret(up); - } -} - -.dropend { - .dropdown-menu[data-bs-popper] { - top: 0; - right: auto; - left: 100%; - margin-top: 0; - margin-left: $dropdown-spacer; - } - - .dropdown-toggle { - @include caret(end); - &::after { - vertical-align: 0; - } - } -} - -.dropstart { - .dropdown-menu[data-bs-popper] { - top: 0; - right: 100%; - left: auto; - margin-top: 0; - margin-right: $dropdown-spacer; - } - - .dropdown-toggle { - @include caret(start); - &::before { - vertical-align: 0; - } - } -} - - -// Dividers (basically an `
`) within the dropdown -.dropdown-divider { - height: 0; - margin: $dropdown-divider-margin-y 0; - overflow: hidden; - border-top: 1px solid $dropdown-divider-bg; -} - -// Links, buttons, and more within the dropdown menu -// -// `