diff --git a/Cargo.lock b/Cargo.lock index 56b0651..75260ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3318,7 +3318,7 @@ dependencies = [ [[package]] name = "tetratto" -version = "15.0.0" +version = "14.0.0" dependencies = [ "ammonia", "async-stripe", @@ -3350,7 +3350,7 @@ dependencies = [ [[package]] name = "tetratto-core" -version = "15.0.0" +version = "14.0.0" dependencies = [ "async-recursion", "base16ct", diff --git a/Cargo.toml b/Cargo.toml index c25b56f..b5beca0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,9 +10,9 @@ package.homepage = "https://tetratto.com" incremental = true [profile.release] -opt-level = 3 +opt-level = "z" lto = true -codegen-units = 2 +codegen-units = 1 # panic = "abort" panic = "unwind" strip = true diff --git a/crates/app/Cargo.toml b/crates/app/Cargo.toml index bbbe59c..4fb69e9 100644 --- a/crates/app/Cargo.toml +++ b/crates/app/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tetratto" -version = "15.0.0" +version = "14.0.0" edition = "2024" authors.workspace = true repository.workspace = true diff --git a/crates/app/src/assets.rs b/crates/app/src/assets.rs index 393fe54..3ab9d32 100644 --- a/crates/app/src/assets.rs +++ b/crates/app/src/assets.rs @@ -38,7 +38,6 @@ pub const STREAMS_JS: &str = include_str!("./public/js/streams.js"); pub const CARP_JS: &str = include_str!("./public/js/carp.js"); pub const PROTO_LINKS_JS: &str = include_str!("./public/js/proto_links.js"); pub const APP_SDK_JS: &str = include_str!("./public/js/app_sdk.js"); -pub const ADS_JS: &str = include_str!("./public/js/ads.js"); // html pub const BODY: &str = include_str!("./public/html/body.lisp"); @@ -56,6 +55,7 @@ pub const AUTH_BASE: &str = include_str!("./public/html/auth/base.lisp"); pub const AUTH_LOGIN: &str = include_str!("./public/html/auth/login.lisp"); pub const AUTH_REGISTER: &str = include_str!("./public/html/auth/register.lisp"); pub const AUTH_CONNECTION: &str = include_str!("./public/html/auth/connection.lisp"); +pub const AUTH_SELLER_CONNECTION: &str = include_str!("./public/html/auth/seller_connection.lisp"); pub const PROFILE_BASE: &str = include_str!("./public/html/profile/base.lisp"); pub const PROFILE_POSTS: &str = include_str!("./public/html/profile/posts.lisp"); @@ -70,7 +70,6 @@ pub const PROFILE_REPLIES: &str = include_str!("./public/html/profile/replies.li pub const PROFILE_MEDIA: &str = include_str!("./public/html/profile/media.lisp"); pub const PROFILE_OUTBOX: &str = include_str!("./public/html/profile/outbox.lisp"); pub const PROFILE_RESPONSES: &str = include_str!("./public/html/profile/responses.lisp"); -pub const PROFILE_SHOP: &str = include_str!("./public/html/profile/shop.lisp"); pub const COMMUNITIES_LIST: &str = include_str!("./public/html/communities/list.lisp"); pub const COMMUNITIES_BASE: &str = include_str!("./public/html/communities/base.lisp"); @@ -89,8 +88,6 @@ pub const POST_POST: &str = include_str!("./public/html/post/post.lisp"); pub const POST_REPOSTS: &str = include_str!("./public/html/post/reposts.lisp"); pub const POST_QUOTES: &str = include_str!("./public/html/post/quotes.lisp"); pub const POST_LIKES: &str = include_str!("./public/html/post/likes.lisp"); -pub const POST_FORUM_QUICK_REPLIES: &str = - include_str!("./public/html/post/forum_quick_replies.lisp"); pub const TIMELINES_HOME: &str = include_str!("./public/html/timelines/home.lisp"); pub const TIMELINES_POPULAR: &str = include_str!("./public/html/timelines/popular.lisp"); @@ -106,8 +103,6 @@ pub const TIMELINES_ALL_QUESTIONS: &str = include_str!("./public/html/timelines/all_questions.lisp"); pub const TIMELINES_SEARCH: &str = include_str!("./public/html/timelines/search.lisp"); pub const TIMELINES_SWISS_ARMY: &str = include_str!("./public/html/timelines/swiss_army.lisp"); -pub const TIMELINES_ALL_FORUM_POSTS: &str = - include_str!("./public/html/timelines/all_forum_posts.lisp"); pub const MOD_AUDIT_LOG: &str = include_str!("./public/html/mod/audit_log.lisp"); pub const MOD_REPORTS: &str = include_str!("./public/html/mod/reports.lisp"); @@ -144,18 +139,13 @@ pub const LITTLEWEB_SERVICE: &str = include_str!("./public/html/littleweb/servic pub const LITTLEWEB_DOMAIN: &str = include_str!("./public/html/littleweb/domain.lisp"); pub const LITTLEWEB_BROWSER: &str = include_str!("./public/html/littleweb/browser.lisp"); +pub const MARKETPLACE_SELLER: &str = include_str!("./public/html/marketplace/seller.lisp"); + pub const MAIL_RECEIVED: &str = include_str!("./public/html/mail/received.lisp"); pub const MAIL_SENT: &str = include_str!("./public/html/mail/sent.lisp"); pub const MAIL_COMPOSE: &str = include_str!("./public/html/mail/compose.lisp"); pub const MAIL_LETTER: &str = include_str!("./public/html/mail/letter.lisp"); -pub const ECONOMY_WALLET: &str = include_str!("./public/html/economy/wallet.lisp"); -pub const ECONOMY_PRODUCTS: &str = include_str!("./public/html/economy/products.lisp"); -pub const ECONOMY_EDIT: &str = include_str!("./public/html/economy/edit.lisp"); -pub const ECONOMY_PRODUCT: &str = include_str!("./public/html/economy/product.lisp"); -pub const ECONOMY_EDIT_AD: &str = include_str!("./public/html/economy/edit_ad.lisp"); -pub const ECONOMY_AD: &str = include_str!("./public/html/economy/ad.lisp"); - // langs pub const LANG_EN_US: &str = include_str!("./langs/en-US.toml"); @@ -303,6 +293,7 @@ pub(crate) async fn write_assets(config: &Config) -> PathBufD { write_template!(html_path->"auth/login.html"(crate::assets::AUTH_LOGIN) --config=config --lisp plugins); write_template!(html_path->"auth/register.html"(crate::assets::AUTH_REGISTER) --config=config --lisp plugins); write_template!(html_path->"auth/connection.html"(crate::assets::AUTH_CONNECTION) --config=config --lisp plugins); + write_template!(html_path->"auth/seller_connection.html"(crate::assets::AUTH_SELLER_CONNECTION) --config=config --lisp plugins); write_template!(html_path->"profile/base.html"(crate::assets::PROFILE_BASE) -d "profile" --config=config --lisp plugins); write_template!(html_path->"profile/posts.html"(crate::assets::PROFILE_POSTS) --config=config --lisp plugins); @@ -317,7 +308,6 @@ pub(crate) async fn write_assets(config: &Config) -> PathBufD { write_template!(html_path->"profile/media.html"(crate::assets::PROFILE_MEDIA) --config=config --lisp plugins); write_template!(html_path->"profile/outbox.html"(crate::assets::PROFILE_OUTBOX) --config=config --lisp plugins); write_template!(html_path->"profile/responses.html"(crate::assets::PROFILE_RESPONSES) --config=config --lisp plugins); - write_template!(html_path->"profile/shop.html"(crate::assets::PROFILE_SHOP) --config=config --lisp plugins); write_template!(html_path->"communities/list.html"(crate::assets::COMMUNITIES_LIST) -d "communities" --config=config --lisp plugins); write_template!(html_path->"communities/base.html"(crate::assets::COMMUNITIES_BASE) --config=config --lisp plugins); @@ -335,7 +325,6 @@ pub(crate) async fn write_assets(config: &Config) -> PathBufD { write_template!(html_path->"post/reposts.html"(crate::assets::POST_REPOSTS) --config=config --lisp plugins); write_template!(html_path->"post/quotes.html"(crate::assets::POST_QUOTES) --config=config --lisp plugins); write_template!(html_path->"post/likes.html"(crate::assets::POST_LIKES) --config=config --lisp plugins); - write_template!(html_path->"post/forum_quick_replies.html"(crate::assets::POST_FORUM_QUICK_REPLIES) --config=config --lisp plugins); write_template!(html_path->"timelines/home.html"(crate::assets::TIMELINES_HOME) -d "timelines" --config=config --lisp plugins); write_template!(html_path->"timelines/popular.html"(crate::assets::TIMELINES_POPULAR) --config=config --lisp plugins); @@ -347,7 +336,6 @@ pub(crate) async fn write_assets(config: &Config) -> PathBufD { write_template!(html_path->"timelines/all_questions.html"(crate::assets::TIMELINES_ALL_QUESTIONS) --config=config --lisp plugins); write_template!(html_path->"timelines/search.html"(crate::assets::TIMELINES_SEARCH) --config=config --lisp plugins); write_template!(html_path->"timelines/swiss_army.html"(crate::assets::TIMELINES_SWISS_ARMY) --config=config --lisp plugins); - write_template!(html_path->"timelines/all_forum_posts.html"(crate::assets::TIMELINES_ALL_FORUM_POSTS) --config=config --lisp plugins); write_template!(html_path->"mod/audit_log.html"(crate::assets::MOD_AUDIT_LOG) -d "mod" --config=config --lisp plugins); write_template!(html_path->"mod/reports.html"(crate::assets::MOD_REPORTS) --config=config --lisp plugins); @@ -384,18 +372,13 @@ pub(crate) async fn write_assets(config: &Config) -> PathBufD { write_template!(html_path->"littleweb/domain.html"(crate::assets::LITTLEWEB_DOMAIN) --config=config --lisp plugins); write_template!(html_path->"littleweb/browser.html"(crate::assets::LITTLEWEB_BROWSER) --config=config --lisp plugins); + write_template!(html_path->"marketplace/seller.html"(crate::assets::MARKETPLACE_SELLER) -d "marketplace" --config=config --lisp plugins); + write_template!(html_path->"mail/received.html"(crate::assets::MAIL_RECEIVED) -d "mail" --config=config --lisp plugins); write_template!(html_path->"mail/sent.html"(crate::assets::MAIL_SENT) --config=config --lisp plugins); write_template!(html_path->"mail/compose.html"(crate::assets::MAIL_COMPOSE) --config=config --lisp plugins); write_template!(html_path->"mail/letter.html"(crate::assets::MAIL_LETTER) --config=config --lisp plugins); - write_template!(html_path->"economy/wallet.html"(crate::assets::ECONOMY_WALLET) -d "economy" --config=config --lisp plugins); - write_template!(html_path->"economy/products.html"(crate::assets::ECONOMY_PRODUCTS) --config=config --lisp plugins); - write_template!(html_path->"economy/edit.html"(crate::assets::ECONOMY_EDIT) --config=config --lisp plugins); - write_template!(html_path->"economy/product.html"(crate::assets::ECONOMY_PRODUCT) --config=config --lisp plugins); - write_template!(html_path->"economy/edit_ad.html"(crate::assets::ECONOMY_EDIT_AD) --config=config --lisp plugins); - write_template!(html_path->"economy/ad.html"(crate::assets::ECONOMY_AD) --config=config --lisp plugins); - html_path } @@ -469,15 +452,10 @@ pub(crate) async fn initial_context( .check(SecondaryPermission::DEVELOPER_PASS), ); ctx.insert("home", &ua.settings.default_timeline.relative_url()); - ctx.insert( - "renew_policy_consent", - &(ua.last_policy_consent < config.policies.last_updated), - ); } else { ctx.insert("is_helper", &false); ctx.insert("is_manager", &false); ctx.insert("home", &DefaultTimelineChoice::default().relative_url()); - ctx.insert("renew_policy_consent", &false); } ctx.insert("lang", &lang.data); diff --git a/crates/app/src/langs/en-US.toml b/crates/app/src/langs/en-US.toml index e06e6ed..fdd6ffc 100644 --- a/crates/app/src/langs/en-US.toml +++ b/crates/app/src/langs/en-US.toml @@ -20,7 +20,6 @@ version = "1.0.0" "general:link.achievements" = "Achievements" "general:link.little_web" = "Little web" "general:link.mail" = "Mail" -"general:link.wallet" = "Wallet" "general:action.save" = "Save" "general:action.delete" = "Delete" "general:action.purge" = "Purge" @@ -51,8 +50,6 @@ version = "1.0.0" "general:label.loading" = "Working on it!" "general:label.send_anonymously" = "Send anonymously" "general:label.must_activate_account" = "You need to activate your account!" -"general:action.load_more" = "Load more" -"general:action.show_thread" = "Show thread" "general:label.supporter_motivation" = "Become a supporter!" "general:action.become_supporter" = "Become supporter" @@ -88,7 +85,6 @@ version = "1.0.0" "auth:label.replies" = "Replies" "auth:label.media" = "Media" "auth:label.outbox" = "Outbox" -"auth:label.shop" = "Shop" "auth:label.before_you_view" = "Before you view" "auth:label.private_profile" = "Private profile" "auth:label.private_profile_message" = "This profile is private, meaning you can only view it if they follow you." @@ -120,9 +116,7 @@ version = "1.0.0" "communities:label.content" = "Content" "communities:label.title" = "Title" "communities:label.posts" = "Posts" -"communities:label.forum_posts" = "Forum posts" "communities:label.topics" = "Topics" -"communities:label.topic" = "Topic" "communities:label.questions" = "Questions" "communities:label.not_allowed_to_read" = "You're not allowed to view this community's posts" "communities:label.might_need_to_join" = "You might need to join this community in order to interact with it!" @@ -208,7 +202,6 @@ version = "1.0.0" "settings:tab.billing" = "Billing" "settings:tab.uploads" = "Uploads" "settings:tab.invites" = "Invites" -"setttings:label.applied_configurations" = "Applied configurations" "mod_panel:label.open_reported_content" = "Open reported content" "mod_panel:label.manage_profile" = "Manage profile" @@ -219,7 +212,6 @@ version = "1.0.0" "mod_panel:label.invited_by" = "Invited by" "mod_panel:label.send_debug_payload" = "Send debug payload" "mod_panel:label.ban_reason" = "Ban reason" -"mod_panel:label.ban_expiration" = "Ban expiration" "requests:label.requests" = "Requests" "requests:label.community_join_request" = "Community join request" @@ -229,7 +221,6 @@ version = "1.0.0" "requests:label.user_follow_request" = "User follow request" "requests:action.view_profile" = "View profile" "requests:label.user_follow_request_message" = "Accepting this request will not allow them to see your profile. For that, you must follow them back." -"requests:label.coin_transfer_request" = "Coin transfer request" "chats:label.my_chats" = "My chats" "chats:action.move" = "Move" @@ -320,6 +311,12 @@ version = "1.0.0" "littleweb:action.rename" = "Rename" "littleweb:action.add" = "Add" +"marketplace:label.products" = "Products" +"marketplace:label.status" = "Status" +"marketplace:action.get_started" = "Get started" +"marketplace:action.finsh_setting_up_account" = "Finish setting up my account" +"marketplace:action.open_seller_dashboard" = "Open seller dashboard" + "mail:label.received" = "Received" "mail:label.sent" = "Sent" "mail:label.compose" = "Compose" @@ -328,32 +325,3 @@ version = "1.0.0" "mail:label.content" = "Content" "mail:action.send" = "Send" "mail:action.send_mail" = "Send mail" - -"economy:label.recent_transfers" = "Recent transfers" -"economy:action.request" = "Request" -"economy:label.title" = "Title" -"economy:label.description" = "Description" -"economy:label.my_products" = "My products" -"economy:label.my_wallet" = "My wallet" -"economy:label.create_new" = "Create new product" -"economy:label.price" = "Price" -"economy:label.on_sale" = "On sale" -"economy:label.single_use" = "Only allow users to purchase once" -"economy:label.stock" = "Stock" -"economy:label.unlimited" = "Unlimited" -"economy:label.fulfillment_style" = "Fulfillment style" -"economy:label.use_automail" = "Use automail" -"economy:label.automail_message" = "Automail message" -"economy:action.buy" = "Buy" -"economy:label.already_purchased" = "Already purchased" -"economy:label.snippet_data" = "Snippet data" -"economy:action.apply" = "Apply" -"economy:action.unapply" = "Unapply" -"economy:label.thumbnails" = "Thumbnails" -"economy:label.my_ads" = "My ads" -"economy:label.create_new_ad" = "Create new advertisement" -"economy:label.target" = "Target URL" -"economy:label.image" = "Image" -"economy:label.size_base" = "Size base" -"economy:label.running" = "Running" -"economy:label.embed_ads_on_my_site" = "Embed ads on my site" diff --git a/crates/app/src/macros.rs b/crates/app/src/macros.rs index c50c68d..9fbda85 100644 --- a/crates/app/src/macros.rs +++ b/crates/app/src/macros.rs @@ -87,31 +87,10 @@ macro_rules! get_user_from_token { { Ok(ua) => { if ua.permissions.check_banned() { - // check expiration - let now = tetratto_shared::unix_epoch_timestamp(); - let expired = ua.ban_expire <= now; + let mut banned_user = tetratto_core::model::auth::User::banned(); + banned_user.ban_reason = ua.ban_reason; - if expired && ua.ban_expire != 0 { - $db.update_user_role( - ua.id, - ua.permissions - - tetratto_core::model::permissions::FinePermission::BANNED, - &ua, - true, - ) - .await - .expect("failed to auto unban user"); - - Some(ua) - } else { - // banned - let mut banned_user = tetratto_core::model::auth::User::banned(); - - banned_user.ban_reason = ua.ban_reason; - banned_user.ban_expire = ua.ban_expire; - - Some(banned_user) - } + Some(banned_user) } else { Some(ua) } diff --git a/crates/app/src/public/css/root.css b/crates/app/src/public/css/root.css index 1a53a2e..a0c2a18 100644 --- a/crates/app/src/public/css/root.css +++ b/crates/app/src/public/css/root.css @@ -5,26 +5,22 @@ --hue: 16; --sat: 6%; --lit: 0%; - --color-surface: hsl(var(--hue), var(--sat), calc(94% - var(--lit))); - --color-lowered: hsl(var(--hue), var(--sat), calc(90% - var(--lit))); - --color-raised: hsl(var(--hue), var(--sat), calc(97% - var(--lit))); + --color-surface: hsl(var(--hue), var(--sat), calc(97% - var(--lit))); + --color-lowered: hsl(var(--hue), var(--sat), calc(94% - var(--lit))); + --color-raised: hsl(var(--hue), var(--sat), calc(99% - var(--lit))); --color-super-lowered: hsl(var(--hue), var(--sat), calc(85% - var(--lit))); - --color-super-raised: hsl(var(--hue), var(--sat), calc(99% - var(--lit))); - --color-text: hsl(0, 0%, 9%); + --color-super-raised: hsl(var(--hue), var(--sat), calc(100% - var(--lit))); + --color-text: hsl(0, 0%, 0%); --color-text-raised: var(--color-text); --color-text-lowered: var(--color-text); --color-primary: hsl(330, 18%, 26%); --color-primary-lowered: hsl(330, 18%, 21%); - --color-text-primary: hsl(0, 0%, 91%); + --color-text-primary: hsl(0, 0%, 100%); - --color-secondary: hsl(277, 27%, 70%); - --color-secondary-lowered: hsl(277, 27%, 65%); - --color-text-secondary: hsl(0, 0%, 9%); - - --color-accent: hsl(237, 27%, 28%); - --color-accent-lowered: hsl(237, 27%, 23%); - --color-text-accent: hsl(0, 0%, 91%); + --color-secondary: hsl(6, 18%, 66%); + --color-secondary-lowered: hsl(6, 18%, 61%); + --color-text-secondary: hsl(0, 0%, 0%); --color-link: #2949b2; --color-shadow: rgba(0, 0, 0, 0.08); @@ -58,19 +54,15 @@ --color-raised: hsl(var(--hue), var(--sat), calc(2% + var(--lit))); --color-super-lowered: hsl(var(--hue), var(--sat), calc(12% + var(--lit))); --color-super-raised: hsl(var(--hue), var(--sat), calc(4% + var(--lit))); - --color-text: hsl(0, 0%, 91%); + --color-text: hsl(0, 0%, 95%); --color-primary: hsl(331, 18%, 74%); --color-primary-lowered: hsl(331, 18%, 69%); - --color-text-primary: hsl(0, 0%, 9%); + --color-text-primary: hsl(0, 0%, 0%); - --color-secondary: hsl(277, 27%, 30%); - --color-secondary-lowered: hsl(277, 27%, 25%); - --color-text-secondary: hsl(0, 0%, 91%); - - --color-accent: hsl(237, 27%, 72%); - --color-accent-lowered: hsl(237, 27%, 67%); - --color-text-accent: hsl(0, 0%, 9%); + --color-secondary: hsl(6, 18%, 34%); + --color-secondary-lowered: hsl(6, 18%, 29%); + --color-text-secondary: hsl(0, 0%, 100%); --color-link: #93c5fd; --color-red: hsl(0, 94%, 82%); @@ -201,7 +193,8 @@ p { .name { max-width: 250px; overflow: hidden; - white-space: nowrap; + /* overflow-wrap: break-word; */ + overflow-wrap: anywhere; text-overflow: ellipsis; } @@ -249,8 +242,7 @@ svg.icon { height: 1em; } -svg.icon.filled, -.filled svg.icon { +svg.icon.filled { fill: currentColor; } diff --git a/crates/app/src/public/css/style.css b/crates/app/src/public/css/style.css index 52f3464..88a1864 100644 --- a/crates/app/src/public/css/style.css +++ b/crates/app/src/public/css/style.css @@ -1,11 +1,5 @@ @import url("root.css"); -/* ads */ -.tetratto_ad iframe { - border-radius: var(--radius); -} - -/* media gallery */ .media_gallery { display: grid; grid-auto-columns: 1fr 1fr; @@ -17,9 +11,7 @@ @media screen and (max-width: 900px) { .media_gallery { - /* grid-auto-flow: row dense; */ /* safari is the most shit browser ever dude, this property causes safari to make images overlap for lord knows why */ - display: flex; - flex-direction: column; + grid-auto-flow: row dense; } } @@ -279,16 +271,6 @@ table ol { } } -.card.button { - justify-content: flex-start; - align-items: flex-start; - flex-direction: column; - gap: var(--pad-2); - width: 100%; - height: max-content; - padding: var(--pad-4); -} - /* supporter card */ @property --border-angle { syntax: ""; @@ -330,7 +312,7 @@ button, transition: background 0.15s; width: max-content; height: 32px; - padding: 0 var(--pad-4); + padding: var(--pad-1) var(--pad-4); border-radius: var(--radius); cursor: pointer; display: flex; @@ -387,17 +369,7 @@ button.secondary, .button.secondary { background: var(--color-secondary); color: var(--color-text-secondary); -} - -button.accent:hover, -.button.accent:hover { - background: var(--color-accent-lowered); -} - -button.accent, -.button.accent { - background: var(--color-accent); - color: var(--color-text-accent); + font-weight: 500; } button.secondary:hover, @@ -467,6 +439,7 @@ textarea, select { padding: 0.35rem var(--pad-3); border-radius: var(--radius); + border: solid 1px var(--color-super-lowered); outline: none; transition: background 0.15s; resize: vertical; @@ -474,10 +447,8 @@ select { font-family: inherit; font-size: 16px; /* personality */ - --background: var(--color-lowered); - border: solid 1px var(--background); - background: var(--background); - color: var(--color-text-lowered); + background: transparent; + color: inherit; } textarea { @@ -487,14 +458,8 @@ textarea { input:focus, textarea:focus, select:focus { - border-color: var(--color-super-lowered); -} - -input:disabled, -textarea:disabled, -select:disabled { - opacity: 50%; - cursor: not-allowed; + background: var(--color-super-raised); + color: var(--color-text-raised); } .poll_bar { @@ -526,7 +491,7 @@ select:disabled { } input[type="checkbox"] { - --color: #93c5fd; + --color: #c9b1bc; appearance: none; border-radius: var(--radius); transition: @@ -563,10 +528,6 @@ input[type="checkbox"]:checked { background-image: url("/icons/check.svg"); } -label { - cursor: pointer; -} - /* pillmenu */ .pillmenu { display: flex; @@ -899,19 +860,18 @@ dialog { display: none; background: var(--color-surface); border: solid 1px var(--color-super-lowered) !important; - border-radius: calc(var(--radius) * 2); - max-width: 95%; + border-radius: var(--radius); + max-width: 100%; border-style: none; margin: auto; color: var(--color-text); - animation: popin ease-in-out 1 0.15s forwards running; + animation: popin ease-in-out 1 0.1s forwards running; } dialog .inner { padding: var(--pad-4); width: 25rem; max-width: 100%; - font-weight: 500; } dialog .inner hr:not(.flipped):last-of-type { @@ -930,11 +890,6 @@ dialog[open] { dialog::backdrop { background: hsla(0, 0%, 0%, 50%); backdrop-filter: blur(5px); - animation: fadein ease-in-out 1 0.1s forwards running; -} - -dialog:is(.dark *)::backdrop { - background: hsla(0, 0%, 100%, 15%); } /* dropdown */ @@ -947,9 +902,9 @@ dialog:is(.dark *)::backdrop { display: none; position: absolute; background: var(--color-raised); - /* border: solid 1px var(--color-super-lowered); */ + border: solid 1px var(--color-super-lowered); z-index: 2; - border-radius: calc(var(--radius) * 2); + border-radius: var(--radius); top: calc(100% + 5px); right: 0; width: max-content; @@ -1449,55 +1404,3 @@ details.accordion .inner { background-color: var(--color-primary) !important; color: var(--color-text-primary) !important; } - -/* threads */ -.squig { - --color: var(--color-super-lowered); - --background: var(--color-raised); - --size: 10px; - position: relative; - width: 100%; - height: 20px; - display: block; -} - -.squig::before, -.squig::after { - content: ""; - position: absolute; - width: inherit; - height: inherit; - background-size: var(--size) 100%; -} - -.squig::before { - top: -2px; - background-image: - linear-gradient(45deg, var(--color) 35%, transparent 0), - linear-gradient(-45deg, var(--color) 35%, transparent 0); -} - -.squig::after { - top: 0px; - background-image: - linear-gradient(45deg, var(--background) 35%, transparent 0), - linear-gradient(-45deg, var(--background) 35%, transparent 0); -} - -.thread { - --pad: 15px; - --squig-height: 20px; - position: relative; - padding-left: var(--pad); -} - -.thread::before { - content: ""; - position: absolute; - background: var(--color-super-lowered); - height: calc(100% - var(--squig-height)); - width: 5px; - left: 0; - top: 0; - border-radius: var(--radius); -} diff --git a/crates/app/src/public/css/utility.css b/crates/app/src/public/css/utility.css index f5f834f..4b0460f 100644 --- a/crates/app/src/public/css/utility.css +++ b/crates/app/src/public/css/utility.css @@ -35,7 +35,7 @@ justify-content: right; } -.justify_start { +.justify-start { justify-content: flex-start !important; } diff --git a/crates/app/src/public/html/auth/base.lisp b/crates/app/src/public/html/auth/base.lisp index e9a8b9b..4940089 100644 --- a/crates/app/src/public/html/auth/base.lisp +++ b/crates/app/src/public/html/auth/base.lisp @@ -3,7 +3,7 @@ ("class" "flex flex_col gap_2") ("style" "max-width: 48ch") (h2 - ("class" "w_full text_center") + ("class" "w_full text-center") ; block for title (text "{% block title %}{% endblock %}")) (div diff --git a/crates/app/src/public/html/auth/login.lisp b/crates/app/src/public/html/auth/login.lisp index c2e3cf0..9c1e2e4 100644 --- a/crates/app/src/public/html/auth/login.lisp +++ b/crates/app/src/public/html/auth/login.lisp @@ -113,9 +113,10 @@ (text "{% endblock %} {% block footer %}") (span - ("class" "small w_full text_center") + ("class" "small w_full text-center") (text "Or, ") (a ("href" "/auth/register") (text "register"))) + (text "{% endblock %}") diff --git a/crates/app/src/public/html/auth/register.lisp b/crates/app/src/public/html/auth/register.lisp index 0fd9ae9..4beb2fb 100644 --- a/crates/app/src/public/html/auth/register.lisp +++ b/crates/app/src/public/html/auth/register.lisp @@ -170,9 +170,10 @@ (text "{% endblock %} {% block footer %}") (span - ("class" "small w_full text_center") + ("class" "small w_full text-center") (text "Or, ") (a ("href" "/auth/login") (text "login"))) + (text "{% endblock %}") diff --git a/crates/app/src/public/html/auth/seller_connection.lisp b/crates/app/src/public/html/auth/seller_connection.lisp new file mode 100644 index 0000000..c13b498 --- /dev/null +++ b/crates/app/src/public/html/auth/seller_connection.lisp @@ -0,0 +1,25 @@ +(text "{% extends \"auth/base.html\" %} {% block head %}") +(title + (text "Connection")) + +(text "{% endblock %} {% block title %}Connection{% endblock %} {% block content %}") +(div + ("class" "w_full flex_col gap_2") + ("id" "status") + (b + (text "Working..."))) + +(text "{% if connection_type == \"refresh\" %}") +(script + ("defer" "true") + (text "setTimeout(async () => { + trigger(\"seller::onboarding\"); + }, 1000);")) +(text "{% elif connection_type == \"return\" %}") +(script + ("defer" "true") + (text "setTimeout(async () => { + document.getElementById(\"status\").innerHTML = + `Account updated. You can now close this tab.`; + }, 1000);")) +(text "{%- endif %} {% endblock %}") diff --git a/crates/app/src/public/html/body.lisp b/crates/app/src/public/html/body.lisp index 599106e..00dcfd8 100644 --- a/crates/app/src/public/html/body.lisp +++ b/crates/app/src/public/html/body.lisp @@ -1,10 +1,5 @@ (div ("id" "toast_zone")) -; ads -(script ("src" "/js/ads.js?v=tetratto-{{ random_cache_breaker }}")) -(script - (text "TetrattoAds.init();")) - ; large text (text "{% if user and user.settings.large_text -%}") (style @@ -81,8 +76,6 @@ return; } - TetrattoAds.render_ads(\"{{ config.system_user }}\", \"\"); - atto.disconnect_observers(); atto.remove_false_options(); atto.clean_date_codes(); @@ -176,20 +169,21 @@ ("id" "littleweb") (div ("class" "inner flex flex_col gap_2") + (a - ("class" "button w_full lowered justify_start") + ("class" "button w_full lowered justify-start") ("href" "/net") (icon (text "globe")) (str (text "littleweb:label.browser"))) (a - ("class" "button w_full lowered justify_start") + ("class" "button w_full lowered justify-start") ("href" "/services") (icon (text "panel-top")) (str (text "littleweb:label.my_services"))) (a - ("class" "button w_full lowered justify_start") + ("class" "button w_full lowered justify-start") ("href" "/domains") (icon (text "panel-top")) (str (text "littleweb:label.my_domains"))) @@ -317,7 +311,7 @@ (div ("id" "tokens") ("style" "display: contents")) (div - ("class" "flex justify_right gap_2") + ("class" "flex justify_between") (a ("href" "/auth/login") ("class" "button") @@ -329,8 +323,7 @@ ("class" "lowered") ("onclick" "document.getElementById('tokens_dialog').close()") ("type" "button") - (icon (text "check")) - (str (text "dialog:action.okay"))))))) + (icon (text "check"))))))) ; user scripts (text "{%- endif %} {% if user and use_user_theme -%} {{ components::theme(user=user, theme_preference=user.settings.theme_preference) }} diff --git a/crates/app/src/public/html/chats/app.lisp b/crates/app/src/public/html/chats/app.lisp index e64dc0b..8d0b3d4 100644 --- a/crates/app/src/public/html/chats/app.lisp +++ b/crates/app/src/public/html/chats/app.lisp @@ -73,7 +73,7 @@ (text "{%- endif %}")) (text "{% if can_manage_channels -%}") (a - ("class" "button w_full justify_start lowered") + ("class" "button w_full justify-start lowered") ("href" "/community/{{ selected_community }}/manage#/channels") (text "{{ icon \"plus\" }}") (span diff --git a/crates/app/src/public/html/chats/channels.lisp b/crates/app/src/public/html/chats/channels.lisp index ced2f93..2e12b18 100644 --- a/crates/app/src/public/html/chats/channels.lisp +++ b/crates/app/src/public/html/chats/channels.lisp @@ -7,7 +7,7 @@ (div ("class" "flex flex_row gap_1") (a - ("class" "w_full justify_start button {% if selected_channel == channel.id -%}lowered{% else %}camo{%- endif %}") + ("class" "w_full justify-start button {% if selected_channel == channel.id -%}lowered{% else %}camo{%- endif %}") ("href" "/chats/{{ selected_community }}/{{ channel.id }}") ("data-turbo" "{{ selected_community == '0' }}") (text "{{ icon \"rss\" }}") @@ -24,18 +24,32 @@ (text "{{ icon \"ellipsis\" }}")) (div ("class" "inner") + (text "{% if user.id == channel.owner -%} {% if selected_community == 0 %}") (button - ("onclick" "trigger('atto::copy_text', ['{{ channel.id }}'])") - (icon (text "copy")) - (str (text "general:action.copy_id"))) - (text "{% if user.id == channel.owner or can_manage_channels -%}") - ; owner/manager controls - (button + ("class" "lowered small") ("onclick" "add_member('{{ channel.id }}')") (text "{{ icon \"user-plus\" }}") (span (text "{{ text \"chats:action.add_someone\" }}"))) + ; mute/unmute (button + ("class" "lowered small {% if channel.id in user.channel_mutes -%} hidden {%- endif %}") + ("ui_ident" "channel.mute:{{ channel.id }}") + ("onclick" "mute_channel('{{ channel.id }}')") + (icon (text "bell-off")) + (span + (str (text "chats:action.mute")))) + (button + ("class" "lowered small {% if not channel.id in user.channel_mutes -%} hidden {%- endif %}") + ("ui_ident" "channel.unmute:{{ channel.id }}") + ("onclick" "mute_channel('{{ channel.id }}', false)") + (icon (text "bell-ring")) + (span + (str (text "chats:action.unmute")))) + ; ... + (text "{%- endif %}") + (button + ("class" "lowered small") ("onclick" "update_channel_title('{{ channel.id }}')") (text "{{ icon \"pencil\" }}") (span @@ -46,32 +60,14 @@ (text "{{ icon \"trash\" }}") (span (text "{{ text \"general:action.delete\" }}"))) - (text "{%- endif %} {% if selected_community == 0 %}") - ; mute/unmute - (button - ("class" "{% if channel.id in user.channel_mutes -%} hidden {%- endif %}") - ("ui_ident" "channel.mute:{{ channel.id }}") - ("onclick" "mute_channel('{{ channel.id }}')") - (icon (text "bell-off")) - (span - (str (text "chats:action.mute")))) - (button - ("class" "{% if not channel.id in user.channel_mutes -%} hidden {%- endif %}") - ("ui_ident" "channel.unmute:{{ channel.id }}") - ("onclick" "mute_channel('{{ channel.id }}', false)") - (icon (text "bell-ring")) - (span - (str (text "chats:action.unmute")))) - ; ... - (text "{% if user.id != channel.owner -%}") - ; group chat member controls + (text "{% elif selected_community == 0 %}") (button ("onclick" "kick_member('{{ channel.id }}', '{{ user.id }}')") ("class" "red") (text "{{ icon \"door-open\" }}") (span (text "{{ text \"chats:action.leave\" }}"))) - (text "{%- endif %} {%- endif %}")))) + (text "{%- endif %}")))) (text "{% endfor %}")) (text "{% if selected_community == 0 and selected_channel -%}") (div diff --git a/crates/app/src/public/html/communities/create_post.lisp b/crates/app/src/public/html/communities/create_post.lisp index 62a1c00..09b55f8 100644 --- a/crates/app/src/public/html/communities/create_post.lisp +++ b/crates/app/src/public/html/communities/create_post.lisp @@ -109,23 +109,6 @@ ("class" "card flex flex_col gap_2") ("id" "create_form") ("onsubmit" "create_post_from_form(event)") - (text "{% if show_topics -%}") - (div - ("class" "flex flex_col gap_1") - (label - ("for" "topic") - (str (text "communities:label.topic"))) - (select - ("id" "topic") - ("name" "topic") - (text "{% for id, topic in topics %}") - (option - ("value" "{{ id }}") - ("selected" "{% if selected_topic|int == id|int -%}true{% else %}false{%- endif %}") - (text "{{ topic.title }}")) - (text "{% endfor %}"))) - (text "{%- endif %}") - (div ("class" "flex flex_col gap_1 hidden") ("id" "title_field") @@ -151,12 +134,7 @@ ("placeholder" "content") ("minlength" "2") ("maxlength" "4096") - (text "{% if draft -%}{{ draft.content }}{%- endif %}") - (text "{%- if use_signature %}") - (text " - -{{ user.settings.forum_signature }}") - (text "{%- endif %}"))) + (text "{% if draft -%}{{ draft.content }}{%- endif %}"))) (div ("id" "files_list") ("class" "flex gap_2 flex_wrap")) @@ -182,10 +160,11 @@ (text "{%- endif %} {%- endif %}") (button ("class" "primary") - (str (text "communities:action.create"))))))) + (text "{{ text \"communities:action.create\" }}")))))) (text "{% if not quoting -%}") (script - (text "async function create_post_from_form(e) { + (text "globalThis.SEARCH_PARAMS = new URLSearchParams(window.location.search); + async function create_post_from_form(e) { e.preventDefault(); await trigger(\"atto::debounce\", [\"posts::create\"]); @@ -226,7 +205,7 @@ content: e.target.content.value, community: !is_selected_stack ? selected_community : \"0\", stack: is_selected_stack ? selected_community : \"0\", - topic: (e.target.topic || { selectedOptions: [{ value: \"0\" }] }).selectedOptions[0].value, + topic: !is_selected_stack ? SEARCH_PARAMS.get(\"topic\") || \"0\" : \"0\", poll: poll_data[1], title: e.target.title.value, }), @@ -473,19 +452,14 @@ } setTimeout(() => { - const fake_select = { - parentElement: document.getElementById(\"community_to_post_to\").parentElement, - selectedOptions: [{ - value: \"{{ selected_community }}\", - getAttribute() { - return \"{{ selected_stack != 0 }}\"; - } - }], - }; + update_community_avatar({ + target: document.getElementById(\"community_to_post_to\"), + }); - update_community_avatar({ target: fake_select }); - check_community_supports_title({ target: fake_select }); - }, 150); + check_community_supports_title({ + target: document.getElementById(\"community_to_post_to\"), + }); + }, 250); window.cancel_create_post = async () => { if ( diff --git a/crates/app/src/public/html/communities/feed.lisp b/crates/app/src/public/html/communities/feed.lisp index ccf868e..9c73512 100644 --- a/crates/app/src/public/html/communities/feed.lisp +++ b/crates/app/src/public/html/communities/feed.lisp @@ -1,7 +1,18 @@ (text "{% import \"components.html\" as components %} {% extends \"communities/base.html\" %} {% block content %}") (div ("class" "flex flex_col gap_4 w_full") - (text "{{ macros::community_nav(community=community, selected=\"posts\") }}") + (text "{{ macros::community_nav(community=community, selected=\"posts\") }} {% if pinned|length != 0 %}") + (div + ("class" "card_nest") + (div + ("class" "card small flex gap_2 items_center") + (text "{{ icon \"pin\" }}") + (span + (text "{{ text \"communities:label.pinned\" }}"))) + (div + ("class" "card flex flex_col gap_4") + (text "{% for post in pinned %} {% if post[0].context.repost and post[0].context.repost.reposting -%} {{ components::repost(repost=post[2], post=post[0], owner=post[1], secondary=true, show_community=false, can_manage_post=can_manage_posts) }} {% else %} {{ components::post(post=post[0], owner=post[1], question=post[3], secondary=true, show_community=false, can_manage_post=can_manage_posts, poll=post[4]) }} {%- endif %} {% endfor %}"))) + (text "{%- endif %}") (div ("class" "card_nest") (div @@ -11,6 +22,5 @@ (text "{{ text \"communities:label.posts\" }}"))) (div ("class" "card flex flex_col gap_4") - (text "{% for post in pinned %} {% if post[0].context.repost and post[0].context.repost.reposting -%} {{ components::repost(repost=post[2], post=post[0], owner=post[1], secondary=true, show_community=false, can_manage_post=can_manage_posts) }} {% else %} {{ components::post(post=post[0], owner=post[1], question=post[3], secondary=true, show_community=false, can_manage_post=can_manage_posts, poll=post[4]) }} {%- endif %} {% endfor %}") (text "{% for post in feed %} {% if post[0].context.repost and post[0].context.repost.reposting -%} {{ components::repost(repost=post[2], post=post[0], owner=post[1], secondary=true, show_community=false, can_manage_post=can_manage_posts) }} {% else %} {{ components::post(post=post[0], owner=post[1], question=post[3], secondary=true, show_community=false, can_manage_post=can_manage_posts, poll=post[4]) }} {%- endif %} {% endfor %} {{ components::pagination(page=page, items=feed|length) }}")))) (text "{% endblock %}") diff --git a/crates/app/src/public/html/communities/list.lisp b/crates/app/src/public/html/communities/list.lisp index e65cd8a..5c0abac 100644 --- a/crates/app/src/public/html/communities/list.lisp +++ b/crates/app/src/public/html/communities/list.lisp @@ -37,9 +37,9 @@ ("name" "is_forum") ("class" "w_content")) (span - (text "Make this a forum community"))) + (text "Is forum"))) (button - (str (text "communities:action.create"))))) + (text "{{ text \"communities:action.create\" }}")))) (text "{% if list|length >= 4 -%} {{ components::supporter_ad(body=\"Become a supporter to create up to 10 communities!\") }} {%- endif %} {%- endif %}") (div ("class" "card_nest w_full") diff --git a/crates/app/src/public/html/communities/settings.lisp b/crates/app/src/public/html/communities/settings.lisp index 622b569..239d3cc 100644 --- a/crates/app/src/public/html/communities/settings.lisp +++ b/crates/app/src/public/html/communities/settings.lisp @@ -1,6 +1,7 @@ (text "{% extends \"root.html\" %} {% block head %}") (title (text "Community settings - {{ config.name }}")) + (text "{% endblock %} {% block body %} {{ macros::nav() }}") (main ("class" "flex flex_col gap_2") @@ -36,14 +37,14 @@ (text "{{ icon \"rss\" }}") (span (text "{{ text \"communities:tab.channels\" }}"))) - (text "{%- endif %}") + (text "{%- endif %} {% if community.is_forum -%}") (a ("href" "#/topics") ("data-tab-button" "topics") (icon (text "list")) (span (str (text "communities:tab.topics")))) - (text "{% if can_manage_emojis -%}") + (text "{%- endif %} {% if can_manage_emojis -%}") (a ("href" "#/emojis") ("data-tab-button" "emojis") @@ -302,7 +303,7 @@ ("minlength" "2") ("maxlength" "32"))) (button - (str (text "communities:action.create"))))) + (text "{{ text \"communities:action.create\" }}")))) (text "{% for channel in channels %}") (div ("class" "card_nest") @@ -446,7 +447,7 @@ (text "{{ text \"communities:label.upload\" }}"))) (form ("class" "card flex flex_col gap_2") - ("onsubmit" "create_emoji_from_form(event)") + ("onsubmit" "upload_emoji(event)") (div ("class" "flex flex_col gap_1") (label @@ -472,10 +473,11 @@ ("accept" "image/png,image/jpeg,image/avif,image/webp") ("class" "w_full"))) (button - (str (text "communities:action.create"))) + (text "{{ text \"communities:action.create\" }}")) (span ("class" "fade") - (text "Emojis can be a maximum of 256 KiB.")))) + (text "Emojis can be a maximum of 256 KiB, or 512x512px (width x + height).")))) (text "{% for emoji in emojis %}") (div ("class" "card secondary flex flex_wrap gap_2 items_center justify_between") @@ -504,7 +506,7 @@ (text "{{ text \"stacks:label.remove\" }}"))))) (text "{% endfor %}")) (script - (text "globalThis.create_emoji_from_form = (e) => { + (text "globalThis.upload_emoji = (e) => { e.preventDefault(); e.target.querySelector(\"button\").style.display = \"none\"; @@ -523,10 +525,6 @@ ]); e.target.querySelector(\"button\").removeAttribute(\"style\"); - - if (res.ok) { - e.target.reset(); - } }); alert(\"Emoji upload in progress. Please wait!\"); @@ -646,7 +644,7 @@ ("min" "0") ("max" "256"))) (button - (str (text "communities:action.create"))))) + (text "{{ text \"communities:action.create\" }}")))) (text "{% for id, topic in community.topics %}") (div ("class" "card_nest") @@ -688,12 +686,12 @@ (div ("class" "flex flex_col gap_1") (label - ("for" "{{ id }}-description") + ("for" "description") (str (text "communities:label.description"))) (input ("type" "text") ("name" "description") - ("id" "{{ id }}-description") + ("id" "description") ("placeholder" "description") ("value" "{{ topic.description }}") ("required" "") @@ -702,12 +700,12 @@ (div ("class" "flex flex_col gap_1") (label - ("for" "{{ id }}-color") + ("for" "color") (str (text "communities:label.color"))) (input ("type" "color") ("name" "color") - ("id" "{{ id }}-color") + ("id" "color") ("placeholder" "color") ("required" "") ("value" "{{ topic.color }}") @@ -715,37 +713,17 @@ (div ("class" "flex flex_col gap_1") (label - ("for" "{{ id }}-position") + ("for" "position") (str (text "communities:label.position"))) (input ("type" "number") ("name" "position") - ("id" "{{ id }}-position") + ("id" "position") ("placeholder" "position") ("required" "") ("value" "{{ topic.position }}") ("min" "0") ("max" "256"))) - (div - ("class" "flex flex_col gap_1") - (label - ("for" "{{ id }}-write_access") - (text "Post permission")) - (select - ("name" "write_access") - ("id" "{{ id }}-write_access") - (option - ("value" "Everybody") - ("selected" "{% if topic.write_access == 'Everybody' -%}true{% else %}false{%- endif %}") - (text "Everybody")) - (option - ("value" "Joined") - ("selected" "{% if topic.write_access == 'Joined' -%}true{% else %}false{%- endif %}") - (text "Joined")) - (option - ("value" "Owner") - ("selected" "{% if topic.write_access == 'Owner' -%}true{% else %}false{%- endif %}") - (text "Owner only")))) (button (icon (text "check")) (str (text "general:action.save"))))))) @@ -816,7 +794,6 @@ description: e.target.description.value, color: e.target.color.value, position: Number.parseInt(e.target.position.value), - write_access: e.target.write_access.selectedOptions[0].value, }), }) .then((res) => res.json()) @@ -827,42 +804,6 @@ ]); }); }")) - (text "{% else %}") - (div - ("class" "card lowered w_full hidden flex flex_col gap_2") - ("data-tab" "topics") - (p (text "You can only manage topics for forum communities. You can convert this community into a forum, but you will not be able to go back.")) - (p (text "This will permanently change your community. Currently existing posts will no longer be visible on the community.")) - (button - ("onclick" "convert_to_forum()") - (icon (text "circle-fading-arrow-up")) - (text "Switch to forum"))) - - (script - (text "globalThis.convert_to_forum = async () => { - if ( - !(await trigger(\"atto::confirm\", [ - \"Are you sure you would like to do this? It cannot be undone.\", - ])) - ) { - return; - } - - fetch(\"/api/v1/communities/{{ community.id }}/is_forum\", { - method: \"POST\", - }) - .then((res) => res.json()) - .then((res) => { - trigger(\"atto::toast\", [ - res.ok ? \"success\" : \"error\", - res.message, - ]); - - if (res.ok) { - window.location.reload(); - } - }); - }")) (text "{%- endif %}")) (script diff --git a/crates/app/src/public/html/communities/topic.lisp b/crates/app/src/public/html/communities/topic.lisp index dba3c24..817c1b0 100644 --- a/crates/app/src/public/html/communities/topic.lisp +++ b/crates/app/src/public/html/communities/topic.lisp @@ -9,15 +9,13 @@ (text "{{ components::topic_display(id=topic_id, topic=topic, community=community, show_description=false) }}") (div ("class" "flex gap_2") - (text "{% if can_post -%}") (a - ("href" "/communities/intents/post?community={{ community.id }}&topic={{ topic_id }}&sig=true&topics=true") + ("href" "/communities/intents/post?community={{ community.id }}&topic={{ topic_id }}") ("class" "button small lowered") ("data-turbo" "false") (icon (text "plus")) (span (str (text "general:action.post")))) - (text "{%- endif %}") (a ("href" "/community/{{ community.title }}") ("class" "button lowered small") diff --git a/crates/app/src/public/html/components.lisp b/crates/app/src/public/html/components.lisp index 6b2832a..55d3bf1 100644 --- a/crates/app/src/public/html/components.lisp +++ b/crates/app/src/public/html/components.lisp @@ -6,6 +6,7 @@ ("class" "avatar shadow") ("loading" "lazy") ("style" "--size: {{ size }}")) + (text "{%- endmacro %} {% macro community_avatar(id, community=false, size=\"24px\") -%} {% if community -%}") (img ("src" "/api/v1/communities/{{ id }}/avatar") @@ -13,6 +14,7 @@ ("class" "avatar shadow") ("loading" "lazy") ("style" "--size: {{ size }}")) + (text "{% else %}") (img ("src" "/api/v1/communities/{{ id }}/avatar") @@ -20,6 +22,7 @@ ("class" "avatar shadow") ("loading" "lazy") ("style" "--size: {{ size }}")) + (text "{%- endif %} {%- endmacro %} {% macro banner(username, border_radius=\"var(--radius)\") -%}") (img ("title" "{{ username }}'s banner") @@ -28,18 +31,21 @@ ("class" "banner shadow w_full") ("loading" "lazy") ("style" "border-radius: {{ border_radius }};")) + (text "{%- endmacro %} {% macro community_banner(id, community=false) -%} {% if community %}") (img ("src" "/api/v1/communities/{{ id }}/banner") ("alt" "{{ community.title }}'s banner") ("class" "banner shadow") ("loading" "lazy")) + (text "{% else %}") (img ("src" "/api/v1/communities/{{ id }}/banner") ("alt" "{{ id }}'s banner") ("class" "banner shadow") ("loading" "lazy")) + (text "{%- endif %} {%- endmacro %} {% macro community_listing_card(community) -%}") (a ("class" "card secondary w_full flex items_center gap_4") @@ -63,10 +69,12 @@ (b (text "{{ community.member_count }} ")) (text "members")))) + (text "{%- endmacro %} {% macro username(user) -%}") (div ("style" "display: contents") (text "{% if user.settings.display_name -%} {{ user.settings.display_name }} {% else %} {{ user.username }} {%- endif %}")) + (text "{%- endmacro %} {% macro likes(id, asset_type, likes=0, dislikes=0, secondary=false, disable_dislikes=false) -%}") (button ("title" "Like") @@ -77,6 +85,7 @@ (span (text "{{ likes }}")) (text "{%- endif %}")) + (text "{% if not user or not user.settings.hide_dislikes and not disable_dislikes -%}") (button ("title" "Dislike") @@ -87,27 +96,21 @@ (span (text "{{ dislikes }}")) (text "{%- endif %}")) -(text "{%- endif %} {%- endmacro %} {% macro full_username(user, wrap=true, max_width=\"180px\") -%} {% if user and user.username -%}") + +(text "{%- endif %} {%- endmacro %} {% macro full_username(user) -%} {% if user and user.username -%}") (div - ("class" "flex {% if wrap -%} flex_wrap {%- endif %} items_center") + ("class" "flex items_center") (a ("href" "/@{{ user.username }}") - ("class" "name flush flex gap_1") - ("style" "font-weight: 600; max-width: {{ max_width }}") + ("class" "flush") + ("style" "font-weight: 600") ("target" "_top") - (text "{% if user.settings.private_profile -%}") - (span - ("title" "Private") - ("class" "flex items_center") - (icon (text "lock"))) - (text "{%- endif %}") - (text "{% if user.permissions|has_banned -%}") (del ("class" "fade") (text "{{ self::username(user=user) }}")) (text "{% else %}") (text "{{ self::username(user=user) }}") (text "{%- endif %}")) - (text "{{ self::online_indicator(user=user) }} {% if not user.settings.hide_username_badges -%} {% if user.is_verified -%}") + (text "{{ self::online_indicator(user=user) }} {% if user.is_verified -%}") (span ("title" "Verified") ("style" "color: var(--color-primary)") @@ -119,24 +122,19 @@ ("style" "color: var(--color-primary);") ("class" "flex items_center") (text "{{ icon \"star\" }}")) - (text "{%- endif %} {% if user.checkouts|length > 0 -%}") - (span - ("title" "Donator") - ("style" "color: var(--color-primary);") - ("class" "flex items_center") - (text "{{ icon \"hand-heart\" }}")) (text "{%- endif %} {% if user.permissions|has_staff_badge -%}") (span ("title" "Staff") ("style" "color: var(--color-primary);") ("class" "flex items_center") (text "{{ icon \"shield-user\" }}")) - (text "{%- endif %} {%- endif %}")) + (text "{%- endif %}")) (text "{%- endif %} {%- endmacro %} {% macro repost(repost, post, owner, secondary=false, community=false, show_community=true, can_manage_post=false) -%}") (div ("style" "display: contents") (text "{{ self::post(post=post, owner=owner, secondary=secondary, community=community, show_community=show_community, can_manage_post=can_manage_post, repost=repost, expect_repost=true) }}")) (text "{%- endmacro %}") + (text "{% macro post_info(post, community) -%}") ; info about the post: edited, date, etc. (text "{% if post.context.edited != 0 -%}") @@ -202,7 +200,8 @@ (text "{{ icon \"trash-2\" }}")) (text "{%- endif %}") (text "{%- endmacro %}") -(text "{% macro post_buttons_box(post, community, owner, can_manage_post, show_comments=true) -%}") + +(text "{% macro post_buttons_box(post, community, owner, can_manage_post) -%}") (div ("class" "flex justify_between items_center gap_2 w_full") (text "{% if user -%}") @@ -221,7 +220,7 @@ (text "{%- endif %}") (div ("class" "flex gap_1 buttons_box") - (text "{% if show_comments and post.context.comments_enabled %}") + (text "{% if post.context.comments_enabled %}") (a ("href" "/post/{{ post.id }}") ("class" "button camo small") @@ -359,7 +358,8 @@ ("class" "flush flex gap_1 items_center") (text "{{ self::community_avatar(id=post.community, community=community) }}") (b - (text "{% if community.context.display_name -%} {{ community.context.display_name }} {% else %} {{ community.title }} {%- endif %}")))) + (text "{% if community.context.display_name -%} {{ community.context.display_name }} {% else %} {{ community.title }} {%- endif %}")) + (text "{% if post.context.is_pinned or post.context.is_profile_pinned -%} {{ icon \"pin\" }} {%- endif %}"))) (text "{%- endif %} {%- endif %}") (div ("class" "card flex flex_col post gap_2 post:{{ post.id }} {% if secondary -%}secondary{%- endif %}") @@ -384,10 +384,9 @@ (text "{{ self::avatar(username=owner.username, size=\"24px\", selector_type=\"username\") }}")) (text "{%- endif %}") (span - ; ("class" "name") + ("class" "name") (text "{{ self::full_username(user=owner) }}")) - (text "{{ self::post_info(post=post, community=community) }}") - (text "{% if post.context.is_pinned or post.context.is_profile_pinned -%} {{ icon \"pin\" }} {%- endif %}")) + (text "{{ self::post_info(post=post, community=community) }}")) (text "{% if not dont_show_title and post.title and community and community.context.enable_titles -%}") ; post has a title AND whatever is rendering this component wants to see it (a @@ -465,15 +464,14 @@ (text "{% if community and show_community and community.id != config.town_square or question %}")) (text "{%- endif %} {%- endmacro %}") -(text "{% macro post_media(upload_ids, custom_click=false) -%} {% if upload_ids|length > 0 -%}") +(text "{% macro post_media(upload_ids) -%} {% if upload_ids|length > 0 -%}") (div ("class" "media_gallery gap_2") (text "{% for upload in upload_ids %}") (img ("src" "/api/v1/uploads/{{ upload }}") - ("data-upload-id" "{{ upload }}") ("alt" "Image upload") - ("onclick" "{% if custom_click -%} {{ custom_click }} {%- else -%} trigger('ui::lightbox_open', ['/api/v1/uploads/{{ upload }}']) {%- endif %}")) + ("onclick" "trigger('ui::lightbox_open', ['/api/v1/uploads/{{ upload }}'])")) (text "{% endfor %}")) (text "{%- endif %} {%- endmacro %} {% macro notification(notification) -%}") (div @@ -528,7 +526,7 @@ (text "{{ text \"general:action.delete\" }}")))))) (text "{%- endmacro %}") -(text "{% macro forum_post(post, owner, community, can_manage_post, poll=false, show_show_thread=true) -%}") +(text "{% macro forum_post(post, owner, community, can_manage_post, poll=false) -%}") (div ("class" "card_nest_horizontal_wrapper post post:{{ post.id }}") ("data-community" "{{ post.community }}") @@ -576,38 +574,12 @@ (div ("class" "flex flex_col gap_2") ("style" "flex: 1 0 auto") - (b ("class" "no_p_margin") (text "{{ post.title|markdown|safe }}")) (span ("class" "no_p_margin") (text "{{ post.content|markdown|safe }}")) (text "{{ self::post_media(upload_ids=post.uploads) }}") (text "{% if poll -%} {{ self::poll(post=post, poll=poll) }} {%- endif %}")) (hr ("class" "margin_top")) - (text "{{ self::post_buttons_box(post=post, community=community, owner=owner, can_manage_post=can_manage_post, show_comments=false) }}")))) - -; show thread -(text "{% if show_show_thread and post.comment_count > 0 -%}") -(div - ("class" "flex gap_2") - (text "{% if post.context.comments_enabled %}") - (a - ("href" "/post/{{ post.id }}") - ("class" "button lowered") - (icon (text "message-circle")) - (span - (text "{{ post.comment_count }}"))) - (text "{% endif %}") - - (button - ("class" "lowered") - ("onclick" "globalThis.continue_thread(event.target, '{{ post.id }}', 'replies_{{ post.id }}', 0)") - (icon (text "chevron-down")) - (str (text "general:action.show_thread")))) -(text "{%- endif %}") - -; replies -(div - ("class" "flex flex_col gap_2 hidden thread") - ("id" "replies_{{ post.id }}")) + (text "{{ self::post_buttons_box(post=post, community=community, owner=owner, can_manage_post=can_manage_post) }}")))) (text "{%- endmacro %}") (text "{% macro user_card(user) -%}") @@ -624,8 +596,9 @@ (div ("class" "flex items_center") (b - (text "{{ self::full_username(user=user) }}")) + (text "{{ self::username(user=user) }}")) (text "{{ self::online_indicator(user=user) }}")))) + (text "{%- endmacro %} {% macro pagination(page=0, items=0, key=\"\", value=\"\") -%}") (div ("class" "flex justify_between gap_2 w_full") @@ -894,7 +867,7 @@ (div ("class" "flex gap_2") (button - (str (text "communities:action.create"))) + (text "{{ text \"communities:action.create\" }}")) (text "{% if drawing_enabled -%}") (button @@ -1210,8 +1183,6 @@ (text "{%- endif %}")) (div ("class" "flex gap_2 hidden") - ("onclick" "window.EMOJI_PICKER_REACTION_MESSAGE_ID = '{{ message.id }}'") - (text "{{ self::emoji_picker(element_id=\"react_emoji_picker_field\", render_dialog=false, render_button=true, small=true) }}") (text "{{ self::message_actions(owner=user, message=message, can_manage_message=can_manage_message) }}"))) (text "{%- endif %}") (div @@ -1234,12 +1205,14 @@ ("ui_ident" "emoji_{{ emoji }}") ("onclick" "trigger('me::message_react', [event.target.parentElement.parentElement, '{{ message.id }}', '{{ emoji }}'])") (span (text "{{ emoji|emojis|safe }} {{ num }}"))) - (text "{%- endfor %}"))) + (text "{%- endfor %}") + + (div + ("class" "hidden") + (text "{{ self::emoji_picker(element_id=\"react_emoji_picker_field\", render_dialog=false, render_button=true, small=true) }}")))) (text "{% if grouped -%}") (div - ("class" "hidden flex gap_2 items_center") - ("onclick" "window.EMOJI_PICKER_REACTION_MESSAGE_ID = '{{ message.id }}'") - (text "{{ self::emoji_picker(element_id=\"react_emoji_picker_field\", render_dialog=false, render_button=true, small=true) }}") + ("class" "hidden") (text "{{ self::message_actions(owner=user, message=message, can_manage_message=can_manage_message) }}")) (text "{%- endif %}")))) @@ -1350,15 +1323,15 @@ (text "Listening to ")) (text "{{ other_user.connections.Spotify[1].data.artist }}"))) -(text "{%- endif %} {%- endmacro %} {% macro user_plate(user, show_menu=false, show_kick=false, secondary=false, full=false) -%}") +(text "{%- endif %} {%- endmacro %} {% macro user_plate(user, show_menu=false, show_kick=false, secondary=false) -%}") (div - ("class" "flex gap_2 items_center card tiny user_plate {% if secondary -%}secondary{%- endif %} {% if full -%} w_full {%- endif %}") + ("class" "flex gap_2 items_center card tiny user_plate {% if secondary -%}secondary{%- endif %}") (a ("href" "/@{{ user.username }}") (text "{{ self::avatar(username=user.username, size=\"42px\", selector_type=\"username\") }}")) (div ("class" "flex justify_center flex_col") - ("style" "{% if show_menu or show_kick -%}width: 60%{% else %}max-width: calc(100% - 42px - var(--pad-4)){%- endif %}") + ("style" "{% if show_menu or show_kick -%}width: 60%{% else %}max-width: 150px{%- endif %}") (text "{{ self::full_username(user=user) }}") (div ("class" "user_status") @@ -1869,14 +1842,14 @@ ; option a (button - ("class" "hover_left_bar raised justify_start w_full poll_option") + ("class" "hover_left_bar raised justify-start w_full poll_option") ("onclick" "trigger('me::vote', ['{{ post.id }}', 'A'])") (icon (text "tally-1")) (text "{{ poll[0].option_a }}")) ; option b (button - ("class" "hover_left_bar raised justify_start w_full poll_option") + ("class" "hover_left_bar raised justify-start w_full poll_option") ("onclick" "trigger('me::vote', ['{{ post.id }}', 'B'])") (icon (text "tally-2")) (text "{{ poll[0].option_b }}")) @@ -1884,7 +1857,7 @@ ; option c (text "{% if poll[0].option_c -%}") (button - ("class" "hover_left_bar raised justify_start w_full poll_option") + ("class" "hover_left_bar raised justify-start w_full poll_option") ("onclick" "trigger('me::vote', ['{{ post.id }}', 'C'])") (icon (text "tally-3")) (text "{{ poll[0].option_c }}")) @@ -1893,7 +1866,7 @@ ; option d (text "{% if poll[0].option_d -%}") (button - ("class" "hover_left_bar raised justify_start w_full poll_option") + ("class" "hover_left_bar raised justify-start w_full poll_option") ("onclick" "trigger('me::vote', ['{{ post.id }}', 'D'])") (icon (text "tally-4")) (text "{{ poll[0].option_d }}")) @@ -2187,7 +2160,7 @@ ("class" "flex flex_row gap_1") (a ("href" "/journals/{{ journal.id }}/0?view={{ view_mode }}") - ("class" "button justify_start lowered w_full") + ("class" "button justify-start lowered w_full") (icon (text "notebook")) (text "{{ journal.title }}")) @@ -2213,7 +2186,7 @@ (div ("class" "flex flex_row gap_1") (button - ("class" "justify_start lowered w_full") + ("class" "justify-start lowered w_full") (icon (text "arrow-down")) (text "{{ journal.title }}")) @@ -2263,7 +2236,7 @@ ; create note (text "{% if user and user.id == journal.owner -%}") (button - ("class" "lowered justify_start w_full") + ("class" "lowered justify-start w_full") ("onclick" "create_note()") (icon (text "plus")) (str (text "journals:action.create_note"))) @@ -2277,7 +2250,7 @@ (text "{% macro notes_list_dir_listing(dir, dirs, notes, owner, journal, view_mode=false) -%}") (details (summary - ("class" "button w_full justify_start raised w_full") + ("class" "button w_full justify-start raised w_full") (icon (text "folder")) (text "{{ dir[2] }}")) @@ -2305,7 +2278,7 @@ ("ui_ident" "{% if selected_note == note.id -%} active_note {%- else -%} inactive_note {%- endif %}") (a ("href" "{% if owner -%} /@{{ owner.username }}/{{ journal.title }}/{{ note.title }} {%- else -%} /journals/{{ journal.id }}/{{ note.id }} {%- endif %}") - ("class" "button justify_start w_full {% if selected_note == note.id -%} lowered {%- else -%} raised {%- endif %}") + ("class" "button justify-start w_full {% if selected_note == note.id -%} lowered {%- else -%} raised {%- endif %}") (icon (text "file-text")) (text "{{ note.title }}")) @@ -2386,7 +2359,7 @@ (div ("class" "flex flex_row gap_1") (button - ("class" "justify_start lowered w_full") + ("class" "justify-start lowered w_full") (icon (text "folder-open")) (text "{{ dir[2] }}")) @@ -2429,7 +2402,7 @@ (text "{% macro note_mover_dirs_listing(dir, dirs) -%}") (button ("onclick" "move_note_dir(window.NOTE_MOVER_NOTE_ID, '{{ dir[0] }}'); document.getElementById('note_mover_dialog').close()") - ("class" "justify_start lowered w_full") + ("class" "justify-start lowered w_full") (icon (text "folder-open")) (text "{{ dir[2] }}")) @@ -2491,13 +2464,6 @@ (text "Create infinite Littleweb sites")) (li (text "Create infinite Littleweb domains")) - (li - (text "Create and sell CSS snippet products")) - - (text "{% if config.enable_user_ads -%}") - (li - (text "No ads")) - (text "{%- endif %}") (text "{% if config.security.enable_invite_codes -%}") (li @@ -2670,18 +2636,8 @@ (text "{%- endif %}") (text "{%- endmacro %}") -(text "{% macro topic_post_display(post, owner, is_pinned=false, community=false) -%}") +(text "{% macro topic_post_display(post, owner, is_pinned=false) -%}") (tr - (text "{% if community %}") - (td - (a - ("href" "/community/{{ community.title }}/topic/{{ post.topic }}") - ("class" "flex gap_1 items_center w_content") - (text "{{ self::community_avatar(id=post.community, community=community) }}") - (span - (text "{% if community.context.display_name -%} {{ community.context.display_name }} {% else %} {{ community.title }} {%- endif %}")))) - (text "{%- endif %}") - (td ("class" "flex gap_1") (a @@ -2692,55 +2648,5 @@ (text "{{ self::full_username(user=owner) }}")) (td (text "{{ post.comment_count }}")) (td (text "{{ ((post.likes + 1) / (post.dislikes + 1))|round(method=\"ceil\", precision=2) }}")) - (td (span ("class" "date short") (text "{{ post.created }}")))) -(text "{%- endmacro %}") - -(text "{% macro product_listing_card(product, owner=false, edit=false) -%}") -(a - ("class" "card button lowered w_full flex flex_col gap_2") - ("href" "/product/{{ product.id }}{% if edit -%} /edit {%- endif %}") - (text "{% if owner -%}") - (text "{{ self::full_username(user=owner) }}") - (text "{%- endif %}") - - (h3 - ("class" "flex gap_2 items_center {% if not product.on_sale -%} fade {%- endif %}") - ("style" "height: 24px; text-decoration: {% if not product.on_sale -%} line-through {%- else -%} none {%- endif %}") - (icon (text "package")) - (text "{{ product.title }}")) - (h4 - ("class" "flex gap_2 items_center") - ("style" "height: 18px") - (icon (text "badge-cent")) - (text "{{ product.price }}"))) -(text "{%- endmacro %}") - -(text "{% macro ad_listing_card(ad) -%}") -(a - ("class" "card button lowered w_full flex flex_col gap_2") - ("href" "/product/ad/{{ ad.id }}/edit") - (b - ("class" "flex gap_2 items_center") - ("style" "height: 24px; text-decoration: {% if not ad.is_running -%} line-through {%- else -%} none {%- endif %}") - (icon (text "link")) - (text "{{ ad.target }}")) - (b - ("style" "height: 18px") - (text "{% if ad.is_running -%}") - (span - ("class" "green flex gap_2 items_center") - (icon (text "circle-check")) - (text "Running")) - (text "{% else %}") - (span - ("class" "red flex gap_2 items_center") - (icon (text "circle-x")) - (text "Not running")) - (text "{%- endif %}"))) -(text "{%- endmacro %}") - -(text "{% macro advertisement(size=\"Leaderboard\") -%}") -(text "{% if user and not is_supporter and config.enable_user_ads -%}") -(object ("class" "tetratto_ad") ("data-ad-size" "{{ size }}")) -(text "{%- endif %}") + (td (span ("class" "date") (text "{{ post.created }}")))) (text "{%- endmacro %}") diff --git a/crates/app/src/public/html/developer/home.lisp b/crates/app/src/public/html/developer/home.lisp index 21dc65e..a5f31e9 100644 --- a/crates/app/src/public/html/developer/home.lisp +++ b/crates/app/src/public/html/developer/home.lisp @@ -54,7 +54,7 @@ ("placeholder" "redirect URL") ("minlength" "2"))) (button - (str (text "communities:action.create"))))) + (text "{{ text \"communities:action.create\" }}")))) ; app listing (div diff --git a/crates/app/src/public/html/economy/ad.lisp b/crates/app/src/public/html/economy/ad.lisp deleted file mode 100644 index fe4581f..0000000 --- a/crates/app/src/public/html/economy/ad.lisp +++ /dev/null @@ -1,63 +0,0 @@ -(text "") -(html - ("lang" "en") - (head - (meta ("charset" "UTF-8")) - (meta ("name" "viewport") ("content" "width=device-width, initial-scale=1.0")) - (meta ("http-equiv" "X-UA-Compatible") ("content" "ie=edge"))) - (body - (a - ("href" "{% if not disable_click -%} {{ config.host }}/api/v1/ads/host/{{ host }}/{{ ad.id }}/click {%- endif %}") - ("title" "Advertisement") - ("target" "_blank") - ("class" "ad")) - - (span ("class" "display_tag") (text "Ad")) - - (style - (text "* { - margin: 0; - padding: 0; - box-sizing: border-box; - } - - html, - body { - line-height: 1.5; - letter-spacing: 0.15px; - font-family: - \"Inter\", \"Poppins\", \"Roboto\", ui-sans-serif, system-ui, sans-serif, - \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", - \"Noto Color Emoji\"; - } - - body { - overflow: hidden; - display: grid; - place-items: center; - } - - a.ad { - display: inline; - width: 100dvw; - height: 100dvh; - background-image: url(\"{{ config.host|safe }}/api/v1/uploads/{{ ad.upload_id }}\"); - background-position: center; - background-size: contain; - } - - .display_tag { - position: absolute; - top: 0.5rem; - left: 0.5rem; - padding: 0.15rem 0.5rem; - background: hsla(0, 0%, 0%, 50%); - color: white; - font-weight: 600; - font-size: 10px; - user-select: none; - pointer-events: none; - border-radius: 0.4rem; - box-shadow: 0 0 2px hsla(0, 0%, 0%, 25%); - opacity: 25%; - }")))) diff --git a/crates/app/src/public/html/economy/edit.lisp b/crates/app/src/public/html/economy/edit.lisp deleted file mode 100644 index 28e5db5..0000000 --- a/crates/app/src/public/html/economy/edit.lisp +++ /dev/null @@ -1,568 +0,0 @@ -(text "{% extends \"root.html\" %} {% block head %}") -(title - (text "Manage product - {{ config.name }}")) -(text "{% endblock %} {% block body %} {{ macros::nav(selected=\"\") }}") -(main - ("class" "flex flex_col gap_2") - (div - ("class" "card_nest") - (div - ("class" "card small flex items_center gap_2") - (icon (text "images")) - (b - (str (text "economy:label.thumbnails")))) - (div - ("class" "card flex flex_col gap_2") - (text "{{ components::post_media(upload_ids=product.uploads.thumbnails, custom_click=\"remove_thumbnail(event.target)\") }}") - (text "{% if product.uploads.thumbnails|length < 4 -%}") - (button - ("onclick" "add_thumbnail()") - (icon (text "plus")) - (str (text "communities:label.upload"))) - (text "{%- endif %}"))) - - (div - ("class" "card_nest") - (div - ("class" "card small flex gap_2 items_center") - (icon (text "pencil-line")) - (b - (str (text "economy:label.title")))) - (form - ("class" "card flex flex_col gap_2") - ("onsubmit" "update_title_from_form(event)") - (div - ("class" "flex flex_col gap_1") - (label - ("for" "title") - (str (text "economy:label.title"))) - (input - ("type" "text") - ("name" "title") - ("id" "title") - ("placeholder" "title") - ("required" "") - ("minlength" "2") - ("maxlength" "128") - ("value" "{{ product.title }}"))) - (button (str (text "general:action.save"))))) - - (div - ("class" "card_nest") - (div - ("class" "card small flex gap_2 items_center") - (icon (text "pencil-line")) - (b - (str (text "economy:label.description")))) - (form - ("class" "card flex flex_col gap_2") - ("onsubmit" "update_description_from_form(event)") - (div - ("class" "flex flex_col gap_1") - (label - ("for" "description") - (str (text "economy:label.description"))) - (textarea - ("name" "description") - ("id" "description") - ("placeholder" "description") - ("required" "") - ("minlength" "2") - ("maxlength" "1024") - (text "{{ product.description }}"))) - (button (str (text "general:action.save"))))) - - (div - ("class" "card_nest") - (div - ("class" "card small flex gap_2 items_center") - (icon (text "badge-cent")) - (b - (str (text "economy:label.price")))) - (form - ("class" "card flex flex_col gap_2") - ("onsubmit" "update_price_from_form(event)") - (label - ("for" "on_sale") - ("class" "flex items_center gap_2") - (input - ("type" "checkbox") - ("id" "on_sale") - ("name" "on_sale") - ("class" "w_content") - ("checked" "{{ product.on_sale }}") - ("oninput" "event.preventDefault(); update_on_sale_from_form(event.target.checked)")) - (span - (str (text "economy:label.on_sale")))) - (label - ("for" "single_use") - ("class" "flex items_center gap_2") - (input - ("type" "checkbox") - ("id" "single_use") - ("name" "single_use") - ("class" "w_content") - ("checked" "{{ product.single_use }}") - ("oninput" "event.preventDefault(); update_single_use_from_form(event.target.checked)")) - (span - (str (text "economy:label.single_use")))) - (div - ("class" "flex flex_col gap_1") - (label - ("for" "price") - (str (text "economy:label.price"))) - (input - ("type" "number") - ("name" "price") - ("id" "price") - ("placeholder" "price") - ("required" "") - ("min" "0") - ("max" "1000000") - ("value" "{{ product.price }}"))) - (button (str (text "general:action.save"))))) - - (div - ("class" "card_nest") - (div - ("class" "card small flex gap_2 items_center") - (icon (text "weight")) - (b - (str (text "economy:label.stock")))) - (form - ("class" "card flex flex_col gap_2") - ("onsubmit" "update_stock_from_form(event)") - (label - ("for" "unlimited") - ("class" "flex items_center gap_2") - (input - ("type" "checkbox") - ("id" "unlimited") - ("name" "unlimited") - ("class" "w_content") - ("checked" "{{ product.stock == -1 }}") - ("oninput" "event.preventDefault(); event.target.checked ? document.getElementById('stock').value = -1 : document.getElementById('stock').value = 0")) - (span - (str (text "economy:label.unlimited")))) - (div - ("class" "flex flex_col gap_1") - (label - ("for" "stock") - (str (text "economy:label.stock"))) - (input - ("type" "number") - ("name" "stock") - ("id" "stock") - ("placeholder" "stock") - ("required" "") - ("min" "-1") - ("max" "1000000") - ("value" "{{ product.stock }}"))) - (button (str (text "general:action.save"))))) - - (div - ("class" "card_nest") - (div - ("class" "card small flex gap_2 items_center") - (icon (text "package-check")) - (b - (str (text "economy:label.fulfillment_style")))) - (div - ("class" "card flex flex_col gap_2") - (select - ("id" "fulfillment_style_select") - ("onchange" "mirror_fulfillment_style_select(true)") - (option ("value" "mail") (text "Mail") ("selected" "{{ not product.method == \"ProfileStyle\" }}")) - (option ("value" "snippet") (text "CSS Snippet") ("selected" "{{ product.method == \"ProfileStyle\" }}"))) - (form - ("class" "flex flex_col gap_2 hidden") - ("id" "mail_fulfillment") - ("onsubmit" "update_method_from_form(event)") - (p (text "If you choose to send an automated mail letter upon purchase, users will automatically receive the message you supply below.")) - (p (text "If you disable automail, you'll be required to manually mail users who have purchased your product before the transfer is finalized.")) - (text "{% set is_automail = product.method != \"ManualMail\" and product.method != \"ProfileStyle\" %}") - - (label - ("for" "use_automail") - ("class" "flex items_center gap_2") - (input - ("type" "checkbox") - ("id" "use_automail") - ("name" "use_automail") - ("class" "w_content") - ("oninput" "mirror_use_automail()") - ("checked" "{% if is_automail -%} true {%- else -%} false {%- endif %}")) - (span - (str (text "economy:label.use_automail")))) - (div - ("class" "flex flex_col gap_1") - (label - ("for" "automail_message") - (str (text "economy:label.automail_message"))) - (textarea - ("name" "automail_message") - ("id" "automail_message") - ("placeholder" "automail_message") - (text "{% if is_automail -%} {{ product.method.AutoMail }} {%- endif %}"))) - (button (str (text "general:action.save")))) - (form - ("class" "flex flex_col gap_2 hidden") - ("id" "snippet_fulfillment") - ("onsubmit" "update_data_from_form(event)") - (text "{{ components::supporter_ad(body=\"Become a supporter to create snippets!\") }}") - (div - ("class" "flex flex_col gap_1") - (label - ("for" "data") - (str (text "economy:label.snippet_data"))) - (textarea - ("name" "data") - ("id" "data") - ("placeholder" "data") - (text "{{ product.data }}"))) - (button (str (text "general:action.save")))))) - - (div - ("class" "flex gap_2") - (a - ("class" "button secondary") - ("href" "/product/{{ product.id }}") - (icon (text "arrow-left")) - (str (text "general:action.back"))) - - (button - ("class" "lowered red") - ("onclick" "delete_product()") - (icon (text "trash")) - (str (text "general:action.delete"))))) - -(script - (text "async function add_thumbnail() { - await trigger(\"atto::debounce\", [\"products::update\"]); - - const picker = document.createElement(\"input\"); - picker.type = \"file\"; - picker.accept = \"image/*\"; - document.body.appendChild(picker); - picker.click(); - - picker.addEventListener(\"change\", () => { - // create body - const body = new FormData(); - - for (const file of picker.files) { - body.append(file.name, file); - } - - body.append( - \"body\", - JSON.stringify({ - target: \"Thumbnails\" - }), - ); - - // ... - picker.remove(); - fetch(\"/api/v1/products/{{ product.id }}/uploads\", { - method: \"POST\", - body, - }) - .then((res) => res.json()) - .then(async (res) => { - trigger(\"atto::toast\", [ - res.ok ? \"success\" : \"error\", - res.message, - ]); - - if (res.ok) { - setTimeout(() => { - window.location.reload(); - }, 100); - } - }); - }); - } - - async function remove_thumbnail(target) { - await trigger(\"atto::debounce\", [\"products::update\"]); - - if ( - !(await trigger(\"atto::confirm\", [ - \"Are you sure you would like to do this?\", - ])) - ) { - return; - } - - fetch(\"/api/v1/products/{{ product.id }}/uploads/thumbnails\", { - method: \"DELETE\", - headers: { - \"Content-Type\": \"application/json\", - }, - body: JSON.stringify({ - idx: Array.from(target.parentElement.children).findIndex((x) => x.getAttribute(\"data-upload-id\") === target.getAttribute(\"data-upload-id\")), - }), - }) - .then((res) => res.json()) - .then(async (res) => { - trigger(\"atto::toast\", [ - res.ok ? \"success\" : \"error\", - res.message, - ]); - - if (res.ok) { - setTimeout(() => { - window.location.reload(); - }, 100); - } - }); - } - - async function update_title_from_form(e) { - e.preventDefault(); - await trigger(\"atto::debounce\", [\"products::update\"]); - - fetch(\"/api/v1/products/{{ product.id }}/title\", { - method: \"POST\", - headers: { - \"Content-Type\": \"application/json\", - }, - body: JSON.stringify({ - title: e.target.title.value, - }), - }) - .then((res) => res.json()) - .then((res) => { - trigger(\"atto::toast\", [ - res.ok ? \"success\" : \"error\", - res.message, - ]); - }); - } - - async function update_description_from_form(e) { - e.preventDefault(); - await trigger(\"atto::debounce\", [\"products::update\"]); - - fetch(\"/api/v1/products/{{ product.id }}/description\", { - method: \"POST\", - headers: { - \"Content-Type\": \"application/json\", - }, - body: JSON.stringify({ - description: e.target.description.value, - }), - }) - .then((res) => res.json()) - .then((res) => { - trigger(\"atto::toast\", [ - res.ok ? \"success\" : \"error\", - res.message, - ]); - }); - } - - async function update_on_sale_from_form(on_sale) { - await trigger(\"atto::debounce\", [\"products::update\"]); - - fetch(\"/api/v1/products/{{ product.id }}/on_sale\", { - method: \"POST\", - headers: { - \"Content-Type\": \"application/json\", - }, - body: JSON.stringify({ - on_sale, - }), - }) - .then((res) => res.json()) - .then((res) => { - trigger(\"atto::toast\", [ - res.ok ? \"success\" : \"error\", - res.message, - ]); - }); - } - - async function update_single_use_from_form(single_use) { - await trigger(\"atto::debounce\", [\"products::update\"]); - - fetch(\"/api/v1/products/{{ product.id }}/single_use\", { - method: \"POST\", - headers: { - \"Content-Type\": \"application/json\", - }, - body: JSON.stringify({ - single_use, - }), - }) - .then((res) => res.json()) - .then((res) => { - trigger(\"atto::toast\", [ - res.ok ? \"success\" : \"error\", - res.message, - ]); - }); - } - - async function update_price_from_form(e) { - e.preventDefault(); - await trigger(\"atto::debounce\", [\"products::update\"]); - - fetch(\"/api/v1/products/{{ product.id }}/price\", { - method: \"POST\", - headers: { - \"Content-Type\": \"application/json\", - }, - body: JSON.stringify({ - price: e.target.price.valueAsNumber, - }), - }) - .then((res) => res.json()) - .then((res) => { - trigger(\"atto::toast\", [ - res.ok ? \"success\" : \"error\", - res.message, - ]); - }); - } - - async function update_stock_from_form(e) { - e.preventDefault(); - await trigger(\"atto::debounce\", [\"products::update\"]); - - fetch(\"/api/v1/products/{{ product.id }}/stock\", { - method: \"POST\", - headers: { - \"Content-Type\": \"application/json\", - }, - body: JSON.stringify({ - stock: e.target.stock.valueAsNumber, - }), - }) - .then((res) => res.json()) - .then((res) => { - trigger(\"atto::toast\", [ - res.ok ? \"success\" : \"error\", - res.message, - ]); - }); - } - - async function update_method_from_form(e) { - e.preventDefault(); - await trigger(\"atto::debounce\", [\"products::update\"]); - - fetch(\"/api/v1/products/{{ product.id }}/method\", { - method: \"POST\", - headers: { - \"Content-Type\": \"application/json\", - }, - body: JSON.stringify({ - method: e.target.use_automail.checked ? { AutoMail: e.target.automail_message.value } : \"ManualMail\", - }), - }) - .then((res) => res.json()) - .then((res) => { - trigger(\"atto::toast\", [ - res.ok ? \"success\" : \"error\", - res.message, - ]); - }); - } - - async function update_data_from_form(e) { - e.preventDefault(); - await trigger(\"atto::debounce\", [\"products::update\"]); - - fetch(\"/api/v1/products/{{ product.id }}/data\", { - method: \"POST\", - headers: { - \"Content-Type\": \"application/json\", - }, - body: JSON.stringify({ - data: e.target.data.value, - }), - }) - .then((res) => res.json()) - .then((res) => { - trigger(\"atto::toast\", [ - res.ok ? \"success\" : \"error\", - res.message, - ]); - }); - } - - async function delete_product() { - if ( - !(await trigger(\"atto::confirm\", [ - \"Are you sure you would like to do this?\", - ])) - ) { - return; - } - - fetch(\"/api/v1/products/{{ product.id }}\", { - method: \"DELETE\", - }) - .then((res) => res.json()) - .then((res) => { - trigger(\"atto::toast\", [ - res.ok ? \"success\" : \"error\", - res.message, - ]); - }); - }; - - globalThis.mirror_use_automail = () => { - const use_automail = document.getElementById(\"use_automail\").checked; - - if (use_automail) { - document.getElementById(\"automail_message\").removeAttribute(\"disabled\"); - } else { - document.getElementById(\"automail_message\").setAttribute(\"disabled\", \"true\"); - } - } - - globalThis.mirror_fulfillment_style_select = (send = false) => { - const selected = document.getElementById(\"fulfillment_style_select\").selectedOptions[0].value; - - if (selected === \"mail\") { - document.getElementById(\"mail_fulfillment\").classList.remove(\"hidden\"); - document.getElementById(\"snippet_fulfillment\").classList.add(\"hidden\"); - - if (send) { - update_method_from_form({ - preventDefault: () => {}, - target: document.getElementById(\"mail_fulfillment\"), - }); - } - } else { - document.getElementById(\"mail_fulfillment\").classList.add(\"hidden\"); - document.getElementById(\"snippet_fulfillment\").classList.remove(\"hidden\"); - - if (send) { - fetch(\"/api/v1/products/{{ product.id }}/method\", { - method: \"POST\", - headers: { - \"Content-Type\": \"application/json\", - }, - body: JSON.stringify({ - method: \"ProfileStyle\", - }), - }) - .then((res) => res.json()) - .then((res) => { - trigger(\"atto::toast\", [ - res.ok ? \"success\" : \"error\", - res.message, - ]); - }); - } - } - } - - setTimeout(() => { - mirror_use_automail(); - mirror_fulfillment_style_select(); - }, 150);")) -(text "{% endblock %}") diff --git a/crates/app/src/public/html/economy/edit_ad.lisp b/crates/app/src/public/html/economy/edit_ad.lisp deleted file mode 100644 index 088a91a..0000000 --- a/crates/app/src/public/html/economy/edit_ad.lisp +++ /dev/null @@ -1,97 +0,0 @@ -(text "{% extends \"root.html\" %} {% block head %}") -(title - (text "Manage advertisement - {{ config.name }}")) -(text "{% endblock %} {% block body %} {{ macros::nav(selected=\"\") }}") -(main - ("class" "flex flex_col gap_2") - (div - ("class" "card_nest") - (div - ("class" "card small flex gap_2 items_center") - (icon (text "link")) - (b - (text "{{ ad.target }}"))) - (form - ("class" "card flex flex_col gap_2") - ("onsubmit" "event.preventDefault(); update_is_running_from_form(event.target.is_running.checked)") - (object ("class" "tetratto_ad") ("data-ad-size" "{{ ad.size }}") ("data-noclick" "true") ("data-ad-id" "{{ ad.id }}")) - (ul - (li - (text "{% if ad.last_charge_time != 0 -%}") - (text "Last charge: ") (span ("class" "date") (text "{{ ad.last_charge_time }}")) - (text "{% else %}") - (text "No previous charges") - (text "{%- endif %}"))) - (div ("class" "squig")) - (p (text "Each day your ad is viewed, you'll be charged 25 coins. This charge only applies to the very first view of the day.")) - (p (text "Additionally, you'll be charged 2 coins per click on your ad. This fee will be paid to the user which hosts the site your ad was shown on.")) - (p (text "Each of these transfers will be shown in your wallet's transfer table as either \"AdClick\" or \"AdCharge\".")) - (label - ("for" "is_running") - ("class" "flex items_center gap_2") - (input - ("type" "checkbox") - ("id" "is_running") - ("name" "is_running") - ("class" "w_content") - ("checked" "{{ ad.is_running }}")) - (span - (str (text "economy:label.running")))) - (button (str (text "general:action.save"))))) - - (div - ("class" "flex gap_2") - (a - ("class" "button secondary") - ("href" "/products") - (icon (text "arrow-left")) - (str (text "general:action.back"))) - - (button - ("class" "lowered red") - ("onclick" "delete_ad()") - (icon (text "trash")) - (str (text "general:action.delete"))))) - -(script - (text "async function update_is_running_from_form(is_running) { - await trigger(\"atto::debounce\", [\"products::update\"]); - fetch(\"/api/v1/ads/{{ ad.id }}/running\", { - method: \"POST\", - headers: { - \"Content-Type\": \"application/json\", - }, - body: JSON.stringify({ - is_running, - }), - }) - .then((res) => res.json()) - .then((res) => { - trigger(\"atto::toast\", [ - res.ok ? \"success\" : \"error\", - res.message, - ]); - }); - } - - async function delete_ad() { - if ( - !(await trigger(\"atto::confirm\", [ - \"Are you sure you would like to do this?\", - ])) - ) { - return; - } - - fetch(\"/api/v1/ads/{{ ad.id }}\", { - method: \"DELETE\", - }) - .then((res) => res.json()) - .then((res) => { - trigger(\"atto::toast\", [ - res.ok ? \"success\" : \"error\", - res.message, - ]); - }); - };")) -(text "{% endblock %}") diff --git a/crates/app/src/public/html/economy/product.lisp b/crates/app/src/public/html/economy/product.lisp deleted file mode 100644 index b59e4fb..0000000 --- a/crates/app/src/public/html/economy/product.lisp +++ /dev/null @@ -1,146 +0,0 @@ -(text "{% extends \"root.html\" %} {% block head %}") -(title - (text "{{ product.title }} - {{ config.name }}")) -(text "{% endblock %} {% block body %} {{ macros::nav(selected=\"\") }}") -(main - ("class" "flex flex_col gap_2") - (text "{{ components::post_media(upload_ids=product.uploads.thumbnails) }}") - (div - ("class" "card flex flex_col gap_2") - (h3 - ("style" "height: 32px") - (text "{{ product.title }}")) - (text "{{ components::full_username(user=owner) }}") - - (text "{% if product.stock >= 0 -%}") - (span ("class" "red") (text "{{ product.stock }} remaining")) - (text "{%- endif %}") - - (div - ("class" "card lowered w_full no_p_margin") - (text "{{ product.description|markdown|safe }}")) - - (text "{% if already_purchased -%}") - (span - ("class" "green flex items_center gap_2") - (icon (text "circle-check")) - (str (text "economy:label.already_purchased"))) - (text "{%- endif %}") - - (div - ("class" "flex gap_2 items_center") - (text "{% if user.id != product.owner -%}") - (text "{% if not already_purchased -%}") - ; price - (a - ("class" "button camo lowered") - ("href" "/wallet") - ("target" "_blank") - (icon (text "badge-cent")) - (text "{{ product.price }}")) - ; buy button - (button - ("onclick" "purchase()") - ("disabled" "{{ product.stock == 0 }}") - (icon (text "piggy-bank")) - (str (text "economy:action.buy"))) - (text "{% else %}") - ; profile style snippets - (text "{% if product.method == \"ProfileStyle\" -%} {% if not product.id in applied_configurations_mapped -%}") - (button - ("onclick" "apply()") - (icon (text "check")) - (str (text "economy:action.apply"))) - (text "{% else %}") - (button - ("onclick" "remove()") - (icon (text "x")) - (str (text "economy:action.unapply"))) - (text "{%- endif %} {%- endif %}") - ; ... - (text "{%- endif %}") - (text "{% else %}") - (a - ("class" "button") - ("href" "/product/{{ product.id }}/edit") - (icon (text "settings")) - (str (text "general:label.edit"))) - (text "{%- endif %}")))) - -(script - (text "async function purchase() { - await trigger(\"atto::debounce\", [\"products::buy\"]); - - if ( - !(await trigger(\"atto::confirm\", [ - \"Are you sure you would like to do this? Your new balance will be {{ user.coins - product.price }} coins.\", - ])) - ) { - return; - } - - fetch(\"/api/v1/products/{{ product.id }}/buy\", { - method: \"POST\", - }) - .then((res) => res.json()) - .then((res) => { - trigger(\"atto::toast\", [ - res.ok ? \"success\" : \"error\", - res.message, - ]); - - if (res.ok) { - window.location.reload(); - } - }); - } - - async function apply() { - await trigger(\"atto::debounce\", [\"user::update\"]); - fetch(\"/api/v1/auth/user/{{ user.id }}/applied_configuration\", { - method: \"POST\", - headers: { - \"Content-Type\": \"application/json\", - }, - body: JSON.stringify({ - \"type\": \"StyleSnippet\", - \"id\": \"{{ product.id }}\", - }), - }) - .then((res) => res.json()) - .then((res) => { - trigger(\"atto::toast\", [ - res.ok ? \"success\" : \"error\", - res.message, - ]); - - if (res.ok) { - window.location.reload(); - } - }); - } - - async function remove() { - await trigger(\"atto::debounce\", [\"user::update\"]); - fetch(\"/api/v1/auth/user/{{ user.id }}/applied_configuration\", { - method: \"DELETE\", - headers: { - \"Content-Type\": \"application/json\", - }, - body: JSON.stringify({ - \"id\": \"{{ product.id }}\", - }), - }) - .then((res) => res.json()) - .then((res) => { - trigger(\"atto::toast\", [ - res.ok ? \"success\" : \"error\", - res.message, - ]); - - if (res.ok) { - window.location.reload(); - } - }); - }")) -(text "{% endblock %}") diff --git a/crates/app/src/public/html/economy/products.lisp b/crates/app/src/public/html/economy/products.lisp deleted file mode 100644 index fcd69f0..0000000 --- a/crates/app/src/public/html/economy/products.lisp +++ /dev/null @@ -1,227 +0,0 @@ -(text "{% extends \"root.html\" %} {% block head %}") -(title - (text "My products - {{ config.name }}")) - -(text "{% endblock %} {% block body %} {{ macros::nav(selected=\"products\") }}") -(main - ("class" "flex flex_col gap_2") - ; create new - (text "{{ components::supporter_ad(body=\"Become a supporter to create unlimited products!\") }}") - - (div - ("class" "card_nest") - (div - ("class" "card small") - (b - (str (text "economy:label.create_new")))) - (form - ("class" "card flex flex_col gap_2") - ("onsubmit" "create_product_from_form(event)") - (div - ("class" "flex flex_col gap_1") - (label - ("for" "title") - (str (text "economy:label.title"))) - (input - ("type" "text") - ("name" "title") - ("id" "title") - ("placeholder" "title") - ("required" "") - ("minlength" "2") - ("maxlength" "128"))) - (div - ("class" "flex flex_col gap_1") - (label - ("for" "description") - (str (text "economy:label.description"))) - (textarea - ("name" "description") - ("id" "description") - ("placeholder" "description") - ("required" "") - ("minlength" "2") - ("maxlength" "1024"))) - (button - (str (text "communities:action.create"))))) - - ; product listing - (div - ("class" "card_nest") - (div - ("class" "card small flex items_center gap_2") - (icon (text "store")) - (str (text "economy:label.my_products"))) - - (div - ("class" "card flex flex_col gap_2") - (text "{% for item in list %} {{ components::product_listing_card(product=item, edit=true) }} {% endfor %}") - ; selective pagination - (text "{% if page_set_id == 0 -%}") - (text "{{ components::pagination(page=page, items=list|length) }}") - (text "{% else %}") - (text "{{ components::pagination(page=0, items=list|length) }}") - (text "{%- endif %}"))) - - (text "{% if config.enable_user_ads -%}") - (div ("class" "squig") ("style" "--background: var(--color-surface)")) - - ; create new ad - (div - ("class" "card_nest") - (div - ("class" "card small") - (b - (str (text "economy:label.create_new_ad")))) - (form - ("class" "card flex flex_col gap_2") - ("onsubmit" "create_ad_from_form(event)") - (div - ("class" "flex flex_col gap_1") - (label - ("for" "target") - (str (text "economy:label.target"))) - (input - ("type" "url") - ("name" "target") - ("id" "target") - ("placeholder" "target url") - ("required" "") - ("minlength" "2") - ("maxlength" "128"))) - (div - ("class" "flex flex_col gap_1") - (label - ("for" "file") - (str (text "economy:label.image"))) - (input - ("id" "file") - ("name" "file") - ("type" "file") - ("accept" "image/png,image/jpeg,image/avif,image/webp,image/gif") - ("required" "") - ("class" "w_content"))) - (div - ("class" "flex flex_col gap_1") - (label - ("for" "size_base") - (str (text "economy:label.size_base"))) - (select - ("id" "size_base") - ("name" "size_base") - (option ("value" "Leaderboard") (text "Leaderboard (720x90)")) - (option ("value" "Billboard") (text "Billboard (970x250)")) - (option ("value" "Skyscraper") (text "Skyscraper (160x600)")) - (option ("value" "MediumRectangle") (text "Medium rectangle (300x250)")) - (option ("value" "MobileLeaderboard") (text "Mobile leaderboard (320x50, mobile only)")))) - (button - (str (text "communities:action.create"))))) - - ; ad listing - (div - ("class" "card_nest") - (div - ("class" "card small flex items_center gap_2") - (icon (text "images")) - (str (text "economy:label.my_ads"))) - - (div - ("class" "card flex flex_col gap_2") - (text "{% for item in ads_list %} {{ components::ad_listing_card(ad=item) }} {% endfor %}") - ; selective pagination - (text "{% if page_set_id == 1 -%}") - (text "{{ components::pagination(page=page, items=ads_list|length, key=\"&page_set_id=1\") }}") - (text "{% else %}") - (text "{{ components::pagination(page=0, items=ads_list|length, key=\"&page_set_id=1\") }}") - (text "{%- endif %}"))) - - (div - ("class" "card_nest") - (div - ("class" "card small flex items_center gap_2") - (icon (text "code")) - (str (text "economy:label.embed_ads_on_my_site"))) - - (div - ("class" "card flex flex_col gap_2") - (p (text "You can embed the advertising network into your site to earn a (coin) commission from clicks.")) - (p (text "Place the following into your site's HTML:")) - (pre (code (text "<script src=\"{{ config.host }}\"/js/ads.js\"></script> -<script>TetrattoAds.init(); TetrattoAds.render_ads(\"{{ user.id }}\", \"{{ config.host }}\")</script>"))) - (p (text "After you've done that, you can place your ads like so:")) - (pre (code (text "<object class=\"tetratto_ad\" data-ad-size=\"$size$\"></object>"))) - (p - (text "In the above example, replace \"$size$\" with a size from ") - (a ("href" "https://tetratto.com/reference/tetratto/model/economy/enum.UserAdSize.html") (text "here")) - (text " keep in mind that the name of a size must be in title case. That means it's \"Leaderboard\", not \"leaderboard\".")))) - (text "{%- endif %}")) - -(script - (text "async function create_product_from_form(e) { - e.preventDefault(); - await trigger(\"atto::debounce\", [\"products::create\"]); - - fetch(\"/api/v1/products\", { - method: \"POST\", - headers: { - \"Content-Type\": \"application/json\", - }, - body: JSON.stringify({ - title: e.target.title.value, - description: e.target.description.value, - }), - }) - .then((res) => res.json()) - .then((res) => { - trigger(\"atto::toast\", [ - res.ok ? \"success\" : \"error\", - res.message, - ]); - - if (res.ok) { - e.target.reset(); - setTimeout(() => { - window.location.href = `/product/${res.payload}/edit`; - }, 100); - } - }); - } - - async function create_ad_from_form(e) { - e.preventDefault(); - await trigger(\"atto::debounce\", [\"products::create\"]); - - // create body - const body = new FormData(); - - for (const file of e.target.file.files) { - body.append(file.name, file); - } - - body.append( - \"body\", - JSON.stringify({ - target: e.target.target.value, - size: e.target.size_base.selectedOptions[0].value, - }), - ); - - // ... - fetch(\"/api/v1/ads\", { - method: \"POST\", - body, - }) - .then((res) => res.json()) - .then((res) => { - trigger(\"atto::toast\", [ - res.ok ? \"success\" : \"error\", - res.message, - ]); - - if (res.ok) { - e.target.reset(); - window.location.reload(); - } - }); - }")) -(text "{% endblock %}") diff --git a/crates/app/src/public/html/economy/wallet.lisp b/crates/app/src/public/html/economy/wallet.lisp deleted file mode 100644 index 0981f09..0000000 --- a/crates/app/src/public/html/economy/wallet.lisp +++ /dev/null @@ -1,153 +0,0 @@ -(text "{% extends \"root.html\" %} {% block head %}") -(title - (text "Wallet - {{ config.name }}")) -(text "{% endblock %} {% block body %} {{ macros::nav(selected=\"wallet\") }}") -(main - ("class" "flex flex_col gap_2") - (div - ("class" "card_nest") - (div - ("class" "card small flex items_center justify_between gap_2") - (span - ("class" "flex items_center gap_2") - (icon (text "piggy-bank")) - (span (str (text "general:link.wallet")))) - - (button - ("class" "lowered small square tiny big_icon") - ("onclick" "document.getElementById('buy_dialog').showModal()") - ("title" "Buy coins") - (icon (text "plus")))) - (div - ("class" "card lowered flex flex_col gap_4") - (button - ("class" "card button raised") - ("onclick" "document.getElementById('buy_dialog').showModal()") - (b (text "Coin balance")) - (h3 - ("class" "flex gap_2 items_center") - ("style" "height: 24px") - (icon (text "badge-cent")) - (text "{{ user.coins }}"))))) - (div - ("class" "card_nest") - (div - ("class" "card small flex items_center justify_between gap_2") - (span - ("class" "flex items_center gap_2") - (icon (text "clock")) - (span (str (text "economy:label.recent_transfers"))))) - (div - ("class" "card flex flex_col gap_4") - (div - ("class" "w_full") - ("style" "overflow: auto") - (table - ("class" "w_full") - (thead - (th (text "Created")) - (th (text "Sender")) - (th (text "Receiver")) - (th (text "Amount")) - (th (text "Product")) - (th (text "Source")) - (th (text "Actions"))) - (tbody - (text "{% for transfer in list -%}") - (tr - (td (span ("class" "date short") (text "{{ transfer[3].created }}"))) - (td ("class" "w_content") (text "{{ components::full_username(user=transfer[0], wrap=false) }}")) - (td ("class" "w_content") (text "{{ components::full_username(user=transfer[1], wrap=false) }}")) - (td - ("class" "flex items_center gap_1") - (text "{{ transfer[3].amount }}") - (text "{% if transfer[3].is_pending -%}") - (span ("class" "flex items_center gap_1") ("title" "Pending") (icon (text "clock"))) - (text "{%- endif %}")) - (td - (text "{% if transfer[2] -%}") - (a - ("href" "/product/{{ transfer[2].id }}") - (icon (text "external-link"))) - (text "{%- endif %}")) - (td (text "{{ transfer[3].source }}")) - (td - (text "{% if user.id == transfer[1].id and transfer[3].source == '\"Sale\"' -%}") - ; we're the receiver - (button - ("class" "small tiny square raised camo big_icon") - ("onclick" "issue_refund('{{ transfer[3].id }}')") - ("title" "Issue refund") - (icon (text "undo"))) - (text "{%- endif %}"))) - (text "{%- endfor %}")))) - (text "{{ components::pagination(page=page, items=list|length) }}")))) - -(dialog - ("id" "buy_dialog") - (div - ("class" "inner flex flex_col gap_2") - (p (text "All coin purchases are one-time and will not recur.")) - (p (text "If you do not receive your coins within a minute of purchase, please contact support.")) - - (button - ("class" "lowered w_full justify_start") - ("onclick" "checkout('Coins100')") - (text "100 coins ({{ config.stripe.price_texts.coins_100 }})")) - - (button - ("class" "w_full justify_start") - ("onclick" "checkout('Coins400')") - (text "400 coins ({{ config.stripe.price_texts.coins_400 }})")) - - (hr ("class" "margin")) - (div - ("class" "flex gap_2 justify_between") - (div null?) - (button - ("class" "lowered red") - ("type" "button") - ("onclick", "document.getElementById('buy_dialog').close()") - (icon (text "x")) - (str (text "dialog:action.cancel")))))) - -(script - (text "globalThis.checkout = (product) => { - document.getElementById('buy_dialog').close(); - fetch(\"/api/v1/service_hooks/stripe/checkout\", { - method: \"POST\", - headers: { - \"Content-Type\": \"application/json\", - }, - body: JSON.stringify({ - product, - }), - }) - .then((res) => res.json()) - .then((res) => { - trigger(\"atto::toast\", [res.ok ? \"success\" : \"error\", res.message]); - - if (res.ok) { - window.location.href = res.payload; - } - }); - } - - globalThis.issue_refund = async (transfer) => { - if ( - !(await trigger(\"atto::confirm\", [ - \"Are you sure you would like to do this?\", - ])) - ) { - return; - } - - fetch(`/api/v1/transfers/${transfer}/refund`, { - method: \"POST\", - }) - .then((res) => res.json()) - .then((res) => { - trigger(\"atto::toast\", [res.ok ? \"success\" : \"error\", res.message]); - }); - }")) -(text "{% endblock %}") diff --git a/crates/app/src/public/html/forge/home.lisp b/crates/app/src/public/html/forge/home.lisp index 56f1d01..a25cf5d 100644 --- a/crates/app/src/public/html/forge/home.lisp +++ b/crates/app/src/public/html/forge/home.lisp @@ -30,7 +30,7 @@ ("minlength" "2") ("maxlength" "32"))) (button - (str (text "communities:action.create"))))) + (text "{{ text \"communities:action.create\" }}")))) (text "{% else %}") (text "{{ components::developer_pass_ad(body=\"Get a developer pass to create forges!\") }}") (text "{%- endif %}") diff --git a/crates/app/src/public/html/journals/app.lisp b/crates/app/src/public/html/journals/app.lisp index 48e9e12..246e930 100644 --- a/crates/app/src/public/html/journals/app.lisp +++ b/crates/app/src/public/html/journals/app.lisp @@ -121,7 +121,7 @@ (div ("class" "flex flex_col gap_2 w_full") (button - ("class" "lowered justify_start w_full") + ("class" "lowered justify-start w_full") ("onclick" "create_journal()") (icon (text "plus")) (str (text "journals:action.create_journal"))) @@ -207,7 +207,7 @@ (details ("class" "w_full") (summary - ("class" "button lowered w_full justify_start") + ("class" "button lowered w_full justify-start") (icon (text "settings")) (str (text "general:action.manage"))) @@ -261,7 +261,7 @@ (details ("class" "w_full") (summary - ("class" "button lowered w_full justify_start") + ("class" "button lowered w_full justify-start") (icon (text "folders")) (str (text "journals:label.directories"))) diff --git a/crates/app/src/public/html/littleweb/domains.lisp b/crates/app/src/public/html/littleweb/domains.lisp index c0a3779..b39c716 100644 --- a/crates/app/src/public/html/littleweb/domains.lisp +++ b/crates/app/src/public/html/littleweb/domains.lisp @@ -59,7 +59,7 @@ (option ("value" "{{ tld }}") (text ".{{ tld|lower }}")) (text "{%- endfor %}"))) (button - (str (text "communities:action.create"))) + (text "{{ text \"communities:action.create\" }}")) (details (summary diff --git a/crates/app/src/public/html/littleweb/services.lisp b/crates/app/src/public/html/littleweb/services.lisp index 1325780..1b7eea0 100644 --- a/crates/app/src/public/html/littleweb/services.lisp +++ b/crates/app/src/public/html/littleweb/services.lisp @@ -45,7 +45,7 @@ ("minlength" "2") ("maxlength" "32"))) (button - (str (text "communities:action.create"))))) + (text "{{ text \"communities:action.create\" }}")))) (text "{%- endif %}") (div ("class" "card_nest w_full") diff --git a/crates/app/src/public/html/macros.lisp b/crates/app/src/public/html/macros.lisp index cadeeba..2a49ecf 100644 --- a/crates/app/src/public/html/macros.lisp +++ b/crates/app/src/public/html/macros.lisp @@ -73,22 +73,14 @@ ("class" "inner") (a ("href" "/chats/0/0") + ("title" "Chats") (icon (text "message-circle")) (str (text "communities:label.chats"))) (a ("href" "/mail") + ("title" "Mail") (icon (text "mail")) (str (text "general:link.mail"))) - (text "{% if config.stripe -%}") - (a - ("href" "/wallet") - (icon (text "piggy-bank")) - (str (text "economy:label.my_wallet"))) - (a - ("href" "/products") - (icon (text "store")) - (str (text "economy:label.my_products"))) - (text "{%- endif %}") (a ("href" "/journals/0/0") (icon (text "notebook")) @@ -173,7 +165,7 @@ (text "{%- endif %}"))) (text "{%- endmacro %}") -(text "{% macro timelines_nav(selected=\"\", posts=\"\", questions=\"\", secondary_selected=\"posts\", forum_posts=\"\") -%}") +(text "{% macro timelines_nav(selected=\"\", posts=\"\", questions=\"\", secondary_selected=\"posts\") -%}") (div ("class" "mobile_nav mobile") ; primary nav @@ -192,7 +184,7 @@ (text "{% if posts and questions -%}") ; secondary nav - (text "{{ macros::timelines_secondary_nav(posts=posts, questions=questions, selected=secondary_selected, forum_posts=forum_posts) }}") + (text "{{ macros::timelines_secondary_nav(posts=posts, questions=questions, selected=secondary_selected) }}") (text "{%- endif %}")) (div @@ -202,7 +194,7 @@ ; secondary nav desktop only (text "{% if posts and questions -%}") - (text "{{ macros::timelines_secondary_nav(posts=posts, questions=questions, selected=secondary_selected, forum_posts=forum_posts) }}") + (text "{{ macros::timelines_secondary_nav(posts=posts, questions=questions, selected=secondary_selected) }}") (text "{%- endif %}")) (text "{%- endmacro %}") @@ -260,7 +252,7 @@ (text "{%- endif %}"))) (text "{%- endmacro %}") -(text "{% macro timelines_secondary_nav(posts=\"\", questions=\"\", selected=\"posts\", forum_posts=\"\") -%} {% if user -%}") +(text "{% macro timelines_secondary_nav(posts=\"\", questions=\"\", selected=\"posts\") -%} {% if user -%}") (div ("class" "pillmenu w_full") (a @@ -269,14 +261,6 @@ (icon (text "newspaper")) (span (str (text "communities:label.posts")))) - (text "{% if forum_posts|length > 0 -%}") - (a - ("href" "{{ forum_posts }}") - ("class" "{% if selected == 'forum_posts' -%}active{%- endif %}") - (icon (text "list-tree")) - (span (str (text "communities:label.forum_posts")))) - (text "{%- endif %}") - (a ("href" "{{ questions }}") ("class" "{% if selected == 'questions' -%}active{%- endif %}") @@ -326,13 +310,6 @@ ("class" "{% if selected == 'media' -%}active{%- endif %}") (str (text "auth:label.media"))) - (text "{% if user and profile.settings.enable_shop -%}") - (a - ("href" "/@{{ profile.username }}/shop") - ("class" "{% if selected == 'shop' -%}active{%- endif %}") - (str (text "auth:label.shop"))) - (text "{%- endif %}") - (text "{% if is_self or is_helper -%}") (a ("href" "/@{{ profile.username }}/outbox") @@ -391,3 +368,17 @@ (span (text "{{ text \"settings:tab.connections\" }}"))) (text "{%- endmacro %}") + +(text "{% macro seller_settings_nav_options() -%}") +(a + ("data-tab-button" "account") + ("class" "active") + ("href" "#/account") + (icon (text "smile")) + (span (str (text "settings:tab.account")))) +(a + ("data-tab-button" "products") + ("href" "#/products") + (icon (text "package")) + (span (str (text "marketplace:label.products")))) +(text "{%- endmacro %}") diff --git a/crates/app/src/public/html/mail/compose.lisp b/crates/app/src/public/html/mail/compose.lisp index 430a8ff..5b9f401 100644 --- a/crates/app/src/public/html/mail/compose.lisp +++ b/crates/app/src/public/html/mail/compose.lisp @@ -112,7 +112,6 @@ subject: e.target.subject.value.trim(), receivers: RECEIVERS, replying_to: SEARCH_PARAMS.get(\"replying_to\") || \"0\", - transfer_id: SEARCH_PARAMS.get(\"transfer_id\") || \"0\", }), }) .then((res) => res.json()) diff --git a/crates/app/src/public/html/marketplace/seller.lisp b/crates/app/src/public/html/marketplace/seller.lisp new file mode 100644 index 0000000..c16bb70 --- /dev/null +++ b/crates/app/src/public/html/marketplace/seller.lisp @@ -0,0 +1,79 @@ +(text "{% extends \"root.html\" %} {% block head %}") +(title + (text "Seller settings - {{ config.name }}")) +(text "{% endblock %} {% block body %} {{ macros::nav() }}") +(main + ("class" "flex flex_col gap_2") + + ; nav + (div + ("class" "mobile_nav mobile") + ; primary nav + (div + ("class" "dropdown") + ("style" "width: max-content") + (button + ("class" "raised small") + ("onclick" "trigger('atto::hooks::dropdown', [event])") + ("exclude" "dropdown") + (icon (text "sliders-horizontal")) + (span ("class" "current_tab_text") (text "account"))) + (div + ("class" "inner left") + (text "{{ macros::seller_settings_nav_options() }}")))) + + ; nav desktop + (div + ("class" "desktop pillmenu") + (text "{{ macros::seller_settings_nav_options() }}")) + + ; ... + (div + ("class" "card w_full lowered flex flex_col gap_2") + ("data-tab" "account") + (div + ("class" "card_nest w_full") + (div + ("class" "card small flex items_center gap_2") + (div + ("class" "notification") + ("style" "width: 46px") + (icon (text "stripe"))) + + (b (str (text "marketplace:label.status")))) + + (div + ("class" "card") + (text "{% if user.seller_data.account_id -%}") + (text "{% if user.seller_data.completed_onboarding -%}") + ; completed onboarding + has stripe account linked + (button + ("onclick" "trigger('seller::login')") + (icon (text "arrow-right")) + (str (text "marketplace:action.open_seller_dashboard"))) + (text "{% else %}") + ; not completed onboarding + (p (text "You've not finished setting up your Stripe account.")) + (p (text "Please complete onboarding to accept payments.")) + + (button + ("onclick" "trigger('seller::onboarding')") + (icon (text "arrow-right")) + (str (text "marketplace:action.finsh_setting_up_account"))) + (text "{%- endif %}") + (text "{% else %}") + ; doesn't have a stripe account linked + (button + ("onclick" "trigger('seller::register')") + (icon (text "arrow-right")) + (str (text "marketplace:action.get_started"))) + (text "{%- endif %}")))) + + (div + ("class" "card w_full lowered hidden flex flex_col gap_2") + ("data-tab" "products") + (div + ("class" "card w_full flex flex_wrap gap_2") + ))) + +(text "{% endblock %}") diff --git a/crates/app/src/public/html/misc/requests.lisp b/crates/app/src/public/html/misc/requests.lisp index 73d03ef..2735e0e 100644 --- a/crates/app/src/public/html/misc/requests.lisp +++ b/crates/app/src/public/html/misc/requests.lisp @@ -92,37 +92,6 @@ (text "{{ icon \"trash\" }}") (span (text "{{ text \"general:action.delete\" }}")))))) - (text "{% elif request.action_type == \"Transfer\" %}") - (div - ("class" "card_nest") - (div - ("class" "card small flex items_center gap_2") - (icon (text "piggy-bank")) - (span - (str (text "requests:label.coin_transfer_request")))) - (div - ("class" "card flex flex_col gap_2") - (span (a ("href" "/api/v1/auth/user/find/{{ request.linked_asset }}") (text "Somebody")) (text " is asking for a transfer of ") (b (text "{{ request.data.Int32 }} coins")) (text ".")) - (div - ("class" "card flex flex_wrap w_full secondary gap_2") - (a - ("href" "/api/v1/auth/user/find/{{ request.linked_asset }}") - ("class" "button") - (text "{{ icon \"external-link\" }}") - (span - (text "{{ text \"requests:action.view_profile\" }}"))) - (button - ("class" "lowered green") - ("onclick" "accept_transfer_request(event, '{{ request.id }}', '{{ request.linked_asset }}', {{ request.data.Int32 }})") - (text "{{ icon \"check\" }}") - (span - (text "{{ text \"general:action.accept\" }}"))) - (button - ("class" "lowered red") - ("onclick" "remove_request('{{ request.id }}', '{{ request.linked_asset }}')") - (text "{{ icon \"trash\" }}") - (span - (text "{{ text \"general:action.delete\" }}")))))) (text "{%- endif %} {% endfor %} {% for question in questions %}") (div ("class" "card_nest") @@ -169,15 +138,13 @@ (text "{{ components::pagination(page=page, items=requests|length, key=\"&id=\", value=profile.id) }}")) (script - (text "async function remove_request(id, linked_asset, confirm = true) { - if (confirm) { - if ( - !(await trigger(\"atto::confirm\", [ - \"Are you sure you want to do this?\", - ])) - ) { - return; - } + (text "async function remove_request(id, linked_asset) { + if ( + !(await trigger(\"atto::confirm\", [ + \"Are you sure you want to do this?\", + ])) + ) { + return; } fetch(`/api/v1/requests/${id}/${linked_asset}`, { @@ -308,41 +275,6 @@ } } }); - }; - - globalThis.accept_transfer_request = async (e, id, receiver, amount) => { - await trigger(\"atto::debounce\", [\"economy::transfer\"]); - - if ( - !(await trigger(\"atto::confirm\", [ - \"Are you sure you would like to do this?\", - ])) - ) { - return; - } - - fetch(`/api/v1/transfers`, { - method: \"POST\", - headers: { - \"Content-Type\": \"application/json\", - }, - body: JSON.stringify({ - receiver, - amount, - }), - }) - .then((res) => res.json()) - .then(async (res) => { - trigger(\"atto::toast\", [ - res.ok ? \"success\" : \"error\", - res.message, - ]); - - if (res.ok) { - e.target.parentElement.parentElement.parentElement.parentElement.remove(); - remove_request(id, receiver, false); - } - }); };")) (text "{% endblock %}") diff --git a/crates/app/src/public/html/mod/file_report.lisp b/crates/app/src/public/html/mod/file_report.lisp index 154583f..f1748c0 100644 --- a/crates/app/src/public/html/mod/file_report.lisp +++ b/crates/app/src/public/html/mod/file_report.lisp @@ -28,7 +28,7 @@ ("required" "") ("minlength" "16"))) (button - (str (text "communities:action.create")))))) + (text "{{ text \"communities:action.create\" }}"))))) (script (text "function create_report_from_form(e) { diff --git a/crates/app/src/public/html/mod/ip_bans.lisp b/crates/app/src/public/html/mod/ip_bans.lisp index d48b3cf..c612cf9 100644 --- a/crates/app/src/public/html/mod/ip_bans.lisp +++ b/crates/app/src/public/html/mod/ip_bans.lisp @@ -19,7 +19,7 @@ ("class" "lowered small") (text "{{ icon \"plus\" }}") (span - (str (text "communities:action.create"))))) + (text "{{ text \"communities:action.create\" }}")))) (div ("class" "card flex flex_col gap_2") (text "{% for item in items %}") diff --git a/crates/app/src/public/html/mod/profile.lisp b/crates/app/src/public/html/mod/profile.lisp index 7e12f8c..3201178 100644 --- a/crates/app/src/public/html/mod/profile.lisp +++ b/crates/app/src/public/html/mod/profile.lisp @@ -84,7 +84,7 @@ const ui = await ns(\"ui\"); const element = document.getElementById(\"mod_options\"); - globalThis.profile_request = async (do_confirm, path, body = null, headers = { \"Content-Type\": \"application/json\" }, method = \"POST\") => { + globalThis.profile_request = async (do_confirm, path, body) => { if (do_confirm) { if ( !(await trigger(\"atto::confirm\", [ @@ -96,9 +96,11 @@ } fetch(`/api/v1/auth/user/{{ profile.id }}/${path}`, { - method, - headers: headers != null ? headers : undefined, - body: body != null ? JSON.stringify(body) : undefined, + method: \"POST\", + headers: { + \"Content-Type\": \"application/json\", + }, + body: JSON.stringify(body), }) .then((res) => res.json()) .then((res) => { @@ -263,15 +265,9 @@ (span (text "{{ text \"mod_panel:label.associations\" }}")))) (div - ("class" "card flex flex_wrap gap_4 flex_collapse") + ("class" "card lowered flex flex_wrap gap_2") (text "{% for user in associations -%}") - (div - ("class" "flex flex_row gap_2 items_center card small secondary") - (text "{{ components::user_plate(user=user, show_menu=false, secondary=true, full=true) }}") - (button - ("class" "small square red lowered") - ("onclick" "profile_request(true, 'associations/{{ user.id }}', null, null, 'DELETE')") - (icon (text "x")))) + (text "{{ components::user_plate(user=user, show_menu=false) }}") (text "{%- endfor %}"))) (text "{% if invite -%}") (div @@ -302,7 +298,7 @@ (div ("class" "flex flex_col gap_1") (label - ("for" "reason") + ("for" "title") (str (text "mod_panel:label.ban_reason"))) (textarea ("type" "text") @@ -313,37 +309,6 @@ (text "{{ profile.ban_reason|remove_script_tags|safe }}"))) (button (str (text "general:action.save"))))) - (div - ("class" "card_nest w_full") - (div - ("class" "card small flex items_center justify_between gap_2") - (div - ("class" "flex items_center gap_2") - (icon (text "scale")) - (span - (str (text "mod_panel:label.ban_expiration"))))) - (form - ("class" "card flex flex_col gap_2") - ("onsubmit" "event.preventDefault(); profile_request(false, 'ban_expire', { expire: new Date(event.target.expire.value).getTime() || 0 })") - (div - ("class" "flex flex_col gap_1") - (label - ("for" "expire") - (str (text "mod_panel:label.ban_expiration"))) - (input - ("type" "datetime-local") - ("name" "expire") - ("id" "expire") - ("value" "{{ profile.ban_expire }}"))) - (div - ("class" "flex gap_2") - (button - (str (text "general:action.save"))) - (button - ("type" "button") - ("class" "lowered red") - ("onclick" "profile_request(false, 'ban_expire', { expire: 0 })") - (str (text "notifs:action.clear")))))) (div ("class" "card_nest w_full") (div diff --git a/crates/app/src/public/html/mod/warnings.lisp b/crates/app/src/public/html/mod/warnings.lisp index d84ab53..c5b783a 100644 --- a/crates/app/src/public/html/mod/warnings.lisp +++ b/crates/app/src/public/html/mod/warnings.lisp @@ -37,7 +37,7 @@ ("minlength" "2") ("maxlength" "4096"))) (button - (str (text "communities:action.create"))))) + (text "{{ text \"communities:action.create\" }}")))) (div ("class" "card_nest") (div diff --git a/crates/app/src/public/html/post/forum_quick_replies.lisp b/crates/app/src/public/html/post/forum_quick_replies.lisp deleted file mode 100644 index 383d5ba..0000000 --- a/crates/app/src/public/html/post/forum_quick_replies.lisp +++ /dev/null @@ -1,24 +0,0 @@ -(text "{%- import \"components.html\" as components -%} {%- import \"macros.html\" as macros -%}") - -(div - ("class" "flex flex_col gap_2") - ("id" "replies_{{ post.id }}_{{ page }}") - ; replies - (text "{% for post in replies -%}") - (div - ("style" "display: contents") - (text "{{ components::forum_post(post=post[0], owner=post[1], community=community, can_manage_post=can_manage_posts, poll=post[4]) }}")) - (text "{%- endfor %}") - - ; load more button - (text "{% set len = replies|length %}") - (text "{% if len != 0 and (page * 12) + len != post.comment_count -%}") - (div - (button - ("class" "lowered") - ("onclick" "globalThis.continue_thread(event.target, '{{ post.id }}', 'replies_{{ post.id }}', {{ page + 1 }})") - (icon (text "chevron-down")) - (str (text "general:action.load_more")))) - (text "{% else %}") - (div ("class" "squig")) - (text "{%- endif %}")) diff --git a/crates/app/src/public/html/post/post.lisp b/crates/app/src/public/html/post/post.lisp index e53ca2e..c645ae0 100644 --- a/crates/app/src/public/html/post/post.lisp +++ b/crates/app/src/public/html/post/post.lisp @@ -56,7 +56,7 @@ (text "{% else %}") (div ("style" "display: contents") - (text "{{ components::forum_post(post=post, owner=owner, community=community, can_manage_post=can_manage_posts, poll=poll, show_show_thread=false) }}")) + (text "{{ components::forum_post(post=post, owner=owner, community=community, can_manage_post=can_manage_posts, poll=poll) }}")) (text "{%- endif %}") ; ... (text "{% if user and post.context.comments_enabled -%}") @@ -88,7 +88,7 @@ ("class" "flex gap_2") (text "{{ components::emoji_picker(element_id=\"content\", render_dialog=true) }} {% if is_supporter -%} {{ components::file_picker(files_list_id=\"files_list\") }} {% endif %}") (button - (str (text "communities:action.create")))))) + (text "{{ text \"communities:action.create\" }}"))))) (text "{%- endif %}") (div ("class" "pillmenu") @@ -332,24 +332,7 @@ (text "{%- endif %} {% endfor %} {{ components::pagination(page=page, items=replies|length) }}")))) (script - (text "globalThis.continue_thread = async (target, post_id, id, page = 0) => { - const btn_id = `tmp_${window.crypto.randomUUID()}`; - target.setAttribute(\"disabled\", \"true\"); - target.id = btn_id; - - document.getElementById(id).innerHTML += - await (await fetch(`/post/${post_id}/_quick_replies?page=${page}`)).text(); - document.getElementById(id).classList.remove(\"hidden\"); - - await trigger(\"atto::clean_date_codes\"); - await trigger(\"atto::link_filter\"); - await trigger(\"atto::hooks::check_reactions\"); - await trigger(\"atto::hooks::online_indicator\"); - - document.getElementById(btn_id).parentElement.remove(); - } - - async function create_reply_from_form(e) { + (text "async function create_reply_from_form(e) { e.preventDefault(); await trigger(\"atto::debounce\", [\"posts::create\"]); diff --git a/crates/app/src/public/html/profile/base.lisp b/crates/app/src/public/html/profile/base.lisp index 1fde607..a7e1cd3 100644 --- a/crates/app/src/public/html/profile/base.lisp +++ b/crates/app/src/public/html/profile/base.lisp @@ -64,7 +64,7 @@ ("id" "username") ("class" "username flex items_center gap_2 flex_wrap w_full") (span - ("class" "name") + ("class" "name shorter") (text "{{ components::username(user=profile) }}")) (text "{% if profile.is_verified -%}") (span @@ -84,12 +84,6 @@ ("style" "color: var(--color-primary);") ("class" "flex items_center") (text "{{ icon \"id-card-lanyard\" }}")) - (text "{%- endif %} {% if profile.checkouts|length > 0 -%}") - (span - ("title" "Donator") - ("style" "color: var(--color-primary);") - ("class" "flex items_center") - (text "{{ icon \"hand-heart\" }}")) (text "{%- endif %} {% if profile.permissions|has_staff_badge -%}") (span ("title" "Staff") @@ -176,6 +170,16 @@ (text "Posts")) (span (text "{{ profile.post_count }}"))) + (text "{% if gpa and gpa > 0 and (not user.settings.disable_gpa_fun or is_helper) -%}") + (div + ("class" "w_full flex justify_between items_center") + ("title" "great post average (limited time fun)") + (span + ("class" "notification chip") + (text "GPA")) + (span + (text "{{ gpa|round(method=\"floor\", precision=2) }}"))) + (text "{%- endif %}") (text "{% if not profile.settings.private_last_seen or is_self or is_helper %}") (div ("class" "w_full flex justify_between items_center") @@ -262,13 +266,6 @@ (icon (text "mail-plus")) (span (str (text "mail:action.send_mail")))) - (text "{%- endif %} {% if not profile.settings.no_transfers -%}") - (button - ("onclick" "request_transfer()") - ("class" "lowered") - (icon (text "badge-cent")) - (span - (str (text "economy:action.request")))) (text "{%- endif %} {% if is_helper -%}") (a ("href" "/mod_panel/profile/{{ profile.id }}") @@ -302,41 +299,6 @@ }); }; - globalThis.request_transfer = async () => { - await trigger(\"atto::debounce\", [\"economy::transfer\"]); - const amount = Number.parseInt((await trigger(\"atto::prompt\", [\"Request amount:\"])) || \"0\"); - - if (amount === 0) { - return; - } - - if ( - !(await trigger(\"atto::confirm\", [ - `Are you sure you would like to request ${amount} coins from {{ profile.username }}?`, - ])) - ) { - return; - } - - fetch(`/api/v1/transfers/ask`, { - method: \"POST\", - headers: { - \"Content-Type\": \"application/json\", - }, - body: JSON.stringify({ - receiver: \"{{ profile.id }}\", - amount, - }), - }) - .then((res) => res.json()) - .then(async (res) => { - trigger(\"atto::toast\", [ - res.ok ? \"success\" : \"error\", - res.message, - ]); - }); - }; - globalThis.toggle_follow_user = async (e) => { await trigger(\"atto::debounce\", [ \"users::follow\", @@ -468,12 +430,6 @@ ("class" "rhs w_full flex flex_col gap_4") (text "{% block content %}{% endblock %}"))))) -(text "{% if not use_user_theme -%}") -(text "{% for cnf in applied_configurations -%}") -(text "{{ cnf|safe }}") -(text "{%- endfor %}") -(text "{%- endif %}") - (text "{% if not is_self and profile.settings.warning -%}") (script (text "setTimeout(() => { diff --git a/crates/app/src/public/html/profile/posts.lisp b/crates/app/src/public/html/profile/posts.lisp index e01660b..ab33a08 100644 --- a/crates/app/src/public/html/profile/posts.lisp +++ b/crates/app/src/public/html/profile/posts.lisp @@ -3,8 +3,19 @@ ("style" "display: contents") (text "{{ components::create_question_form(receiver=profile.id, header=profile.settings.motivational_header, drawing_enabled=profile.settings.enable_drawings, allow_anonymous=profile.settings.allow_anonymous_questions) }}")) -(text "{%- endif %}") -(text "{{ macros::profile_nav(selected=\"posts\") }}") +(text "{%- endif %} {% if not tag and pinned|length != 0 -%}") +(div + ("class" "card_nest") + (div + ("class" "card small flex gap_2 items_center") + (text "{{ icon \"pin\" }}") + (span + (text "{{ text \"communities:label.pinned\" }}"))) + (div + ("class" "card flex flex_col gap_4") + (text "{% for post in pinned %} {% if post[2].read_access == \"Everybody\" -%} {% if post[0].context.repost and post[0].context.repost.reposting -%} {{ components::repost(repost=post[3], post=post[0], owner=post[1], secondary=true, community=post[2], show_community=true, can_manage_post=is_self) }} {% else %} {{ components::post(post=post[0], owner=post[1], question=post[4], secondary=true, community=post[2], can_manage_post=is_self, poll=post[5]) }} {%- endif %} {%- endif %} {% endfor %}"))) + +(text "{%- endif %} {{ macros::profile_nav(selected=\"posts\") }}") (div ("class" "card_nest") (div @@ -31,12 +42,6 @@ (div ("class" "card w_full flex flex_col gap_2") ("ui_ident" "io_data_load") - ; pinned - (text "{% if pinned and pinned|length > 0 -%}") - (text "{% for post in pinned %} {% if post[2].read_access == \"Everybody\" -%} {% if post[0].context.repost and post[0].context.repost.reposting -%} {{ components::repost(repost=post[3], post=post[0], owner=post[1], secondary=true, community=post[2], show_community=true, can_manage_post=is_self) }} {% else %} {{ components::post(post=post[0], owner=post[1], question=post[4], secondary=true, community=post[2], can_manage_post=is_self, poll=post[5]) }} {%- endif %} {%- endif %} {% endfor %}") - (div ("class" "squig")) - (text "{%- endif %}") - ; ... (div ("ui_ident" "io_data_marker")))) (text "{% set paged = user and user.settings.paged_timelines %}") diff --git a/crates/app/src/public/html/profile/responses.lisp b/crates/app/src/public/html/profile/responses.lisp index 925d271..93c605e 100644 --- a/crates/app/src/public/html/profile/responses.lisp +++ b/crates/app/src/public/html/profile/responses.lisp @@ -3,8 +3,19 @@ ("style" "display: contents") (text "{{ components::create_question_form(receiver=profile.id, header=profile.settings.motivational_header, drawing_enabled=profile.settings.enable_drawings, allow_anonymous=profile.settings.allow_anonymous_questions) }}")) -(text "{%- endif %}") -(text "{{ macros::profile_nav(selected=\"responses\") }}") +(text "{%- endif %} {% if not tag and pinned|length != 0 -%}") +(div + ("class" "card_nest") + (div + ("class" "card small flex gap_2 items_center") + (text "{{ icon \"pin\" }}") + (span + (text "{{ text \"communities:label.pinned\" }}"))) + (div + ("class" "card flex flex_col gap_4") + (text "{% for post in pinned %} {% if post[2].read_access == \"Everybody\" -%} {% if post[0].context.repost and post[0].context.repost.reposting -%} {{ components::repost(repost=post[3], post=post[0], owner=post[1], secondary=true, community=post[2], show_community=true, can_manage_post=is_self) }} {% else %} {{ components::post(post=post[0], owner=post[1], question=post[4], secondary=true, community=post[2], can_manage_post=is_self, poll=post[5]) }} {%- endif %} {%- endif %} {% endfor %}"))) + +(text "{%- endif %} {{ macros::profile_nav(selected=\"responses\") }}") (div ("class" "card_nest") (div @@ -31,12 +42,6 @@ (div ("class" "card w_full flex flex_col gap_2") ("ui_ident" "io_data_load") - ; pinned - (text "{% if pinned and pinned|length > 0 -%}") - (text "{% for post in pinned %} {% if post[2].read_access == \"Everybody\" -%} {% if post[0].context.repost and post[0].context.repost.reposting -%} {{ components::repost(repost=post[3], post=post[0], owner=post[1], secondary=true, community=post[2], show_community=true, can_manage_post=is_self) }} {% else %} {{ components::post(post=post[0], owner=post[1], question=post[4], secondary=true, community=post[2], can_manage_post=is_self, poll=post[5]) }} {%- endif %} {%- endif %} {% endfor %}") - (div ("class" "squig")) - (text "{%- endif %}") - ; ... (div ("ui_ident" "io_data_marker")))) (text "{% set paged = user and user.settings.paged_timelines %}") diff --git a/crates/app/src/public/html/profile/settings.lisp b/crates/app/src/public/html/profile/settings.lisp index 8bda6c2..52d41d8 100644 --- a/crates/app/src/public/html/profile/settings.lisp +++ b/crates/app/src/public/html/profile/settings.lisp @@ -1162,26 +1162,6 @@ ("class" "fade") (text "This represents the site theme shown to users viewing your profile."))))) - (text "{% if profile.applied_configurations|length > 0 -%}") - (div - ("class" "card_nest") - ("ui_ident" "applied_configurations") - (div - ("class" "card small flex items_center gap_2") - (icon (text "cog")) - (str (text "setttings:label.applied_configurations"))) - (div - ("class" "card") - (p (text "Products that you have purchased and applied to your profile are displayed below. Snippets are always synced to the product, meaning the owner could update it at any time.")) - (ul - (text "{% for cnf in profile.applied_configurations -%}") - (li - (text "{{ cnf[0] }} ") - (a - ("href" "/product/{{ cnf[1] }}") - (text "{{ cnf[1] }}"))) - (text "{%- endfor %}")))) - (text "{%- endif %}") (button ("onclick" "save_settings()") ("id" "save_button") @@ -1762,7 +1742,6 @@ \"import_export\", \"theme_preference\", \"profile_theme\", - \"applied_configurations\", ]); ui.generate_settings_ui( @@ -1927,14 +1906,6 @@ \"{{ profile.settings.hide_social_follows }}\", \"checkbox\", ], - [ - [ - \"hide_username_badges\", - \"Hide badges from your username (outside of your profile)\", - ], - \"{{ profile.settings.hide_username_badges }}\", - \"checkbox\", - ], [[], \"Questions\", \"title\"], [ [ @@ -1983,27 +1954,10 @@ \"textarea\", ], [ - [\"forum_signature\", \"Forum signature\"], + [\"forum_signature\", \"Forum signature (coming soon)\"], settings.forum_signature, \"textarea\", ], - [[], \"Economy\", \"title\"], - [ - [ - \"enable_shop\", - \"Show shop tab on my profile\", - ], - \"{{ profile.settings.enable_shop }}\", - \"checkbox\", - ], - [ - [ - \"no_transfers\", - \"Disable transfer requests\", - ], - \"{{ profile.settings.no_transfers }}\", - \"checkbox\", - ], [[], \"Misc\", \"title\"], [ [\"hide_dislikes\", \"Hide post dislikes\"], @@ -2016,6 +1970,11 @@ \"text\", ], [[], \"Fun\", \"title\"], + [ + [\"disable_gpa_fun\", \"Disable GPA\"], + \"{{ profile.settings.disable_gpa_fun }}\", + \"checkbox\", + ], [ [\"disable_achievements\", \"Disable achievements\"], \"{{ profile.settings.disable_achievements }}\", diff --git a/crates/app/src/public/html/profile/shop.lisp b/crates/app/src/public/html/profile/shop.lisp deleted file mode 100644 index 744d2f1..0000000 --- a/crates/app/src/public/html/profile/shop.lisp +++ /dev/null @@ -1,17 +0,0 @@ -(text "{% extends \"profile/base.html\" %} {% block content %} {% if profile.settings.enable_questions and (user or profile.settings.allow_anonymous_questions) %}") -(div - ("style" "display: contents") - (text "{{ components::create_question_form(receiver=profile.id, header=profile.settings.motivational_header, drawing_enabled=profile.settings.enable_drawings, allow_anonymous=profile.settings.allow_anonymous_questions) }}")) -(text "{%- endif %}") -(text "{{ macros::profile_nav(selected=\"shop\") }}") -(div - ("class" "card_nest") - (div - ("class" "card small flex gap_2 items_center") - (icon (text "store")) - (str (text "auth:label.shop"))) - (div - ("class" "card w_full flex flex_col gap_2") - (text "{% for item in list %} {{ components::product_listing_card(product=item) }} {% endfor %}") - (text "{{ components::pagination(page=page, items=list|length) }}"))) -(text "{% endblock %}") diff --git a/crates/app/src/public/html/root.lisp b/crates/app/src/public/html/root.lisp index 4fc5b81..76b38d9 100644 --- a/crates/app/src/public/html/root.lisp +++ b/crates/app/src/public/html/root.lisp @@ -76,17 +76,7 @@ (span ("class" "fade") (text "The following reason was provided by a moderator:")) (div ("class" "card lowered w_full") - (text "{{ user.ban_reason|markdown|safe }}")) - (text "{% if user.ban_expire != 0 -%}") - (hr) - (span - (text "Your ban will expire on: ") - (span ("id" "ban_expire"))) - (script - (text "document.getElementById(\"ban_expire\").innerText = new Date({{ user.ban_expire }}).toLocaleString();")) - (text "{% else %}") - (span (text "This ban is marked as permanent.")) - (text "{%- endif %}"))))) + (text "{{ user.ban_reason|markdown|safe }}")))))) ; if we aren't banned, just show the page body (text "{% elif user and user.awaiting_purchase %}") ; account waiting for payment message @@ -151,53 +141,7 @@ } }); }")))))) - (text "{% elif user and renew_policy_consent -%}") - ; renew policy consent - (article - (main - (div - ("class" "card_nest") - (div - ("class" "card small flex items_center gap_2") - (icon (text "scroll-text")) - (text "Our policies have been updated!")) - - (div - ("class" "card flex flex_col gap_2 no_p_margin") - (p (text "Your consent is needed for the updated versions of our Terms of Service and Privacy Policy. Please reread them and click \"Accept\" if you agree to these updated terms.")) - (ul - (li - (a - ("href" "{{ config.policies.terms_of_service }}") - (text "Terms of service"))) - (li - (a - ("href" "{{ config.policies.privacy }}") - (text "Privacy policy")))) - (hr ("class" "margin")) - (button - ("onclick" "update_policy_consent()") - (icon (text "check")) - (str (text "general:action.accept"))))))) - - (script - (text "globalThis.update_policy_consent = async () => { - fetch(\"/api/v1/auth/user/me/policy_consent\", { - method: \"POST\", - }) - .then((res) => res.json()) - .then((res) => { - trigger(\"atto::toast\", [ - res.ok ? \"success\" : \"error\", - res.message, - ]); - - if (res.ok) { - window.location.reload(); - } - }); - };")) - (text "{% elif user and user.is_deactivated -%}") + (text "{% elif user.is_deactivated -%}") ; account deactivated message (article (main diff --git a/crates/app/src/public/html/stacks/add_user.lisp b/crates/app/src/public/html/stacks/add_user.lisp index 5ae6f90..7318cfc 100644 --- a/crates/app/src/public/html/stacks/add_user.lisp +++ b/crates/app/src/public/html/stacks/add_user.lisp @@ -16,7 +16,7 @@ (span (text "Select a stack to add this user to:")) (text "{% for stack in stacks %}") (button - ("class" "justify_start lowered w_full") + ("class" "justify-start lowered w_full") ("onclick" "choose_stack('{{ stack.id }}')") (icon (text "layers")) (text "{{ stack.name }}")) diff --git a/crates/app/src/public/html/stacks/list.lisp b/crates/app/src/public/html/stacks/list.lisp index 27714ce..dbcf944 100644 --- a/crates/app/src/public/html/stacks/list.lisp +++ b/crates/app/src/public/html/stacks/list.lisp @@ -29,7 +29,7 @@ ("minlength" "2") ("maxlength" "32"))) (button - (str (text "communities:action.create"))))) + (text "{{ text \"communities:action.create\" }}")))) (text "{%- endif %}") (div ("class" "card_nest w_full") diff --git a/crates/app/src/public/html/timelines/all.lisp b/crates/app/src/public/html/timelines/all.lisp index abf3ede..4609e25 100644 --- a/crates/app/src/public/html/timelines/all.lisp +++ b/crates/app/src/public/html/timelines/all.lisp @@ -1,12 +1,11 @@ (text "{% extends \"root.html\" %} {% block head %}") (title (text "Latest posts - {{ config.name }}")) + (text "{% endblock %} {% block body %} {{ macros::nav() }}") (main ("class" "flex flex_col gap_2") - (text "{{ macros::timelines_nav(selected=\"all\", posts=\"/all\", questions=\"/all/questions\", forum_posts=\"/all/forum_posts\") }}") - (text "{{ components::advertisement(size=\"Leaderboard\") }}") - (text "{% if not user -%}") + (text "{{ macros::timelines_nav(selected=\"all\", posts=\"/all\", questions=\"/all/questions\") }} {% if not user -%}") (div ("class" "card_nest") (div @@ -33,9 +32,11 @@ ("class" "card w_full flex flex_col gap_2") ("ui_ident" "io_data_load") (div ("ui_ident" "io_data_marker")))) + (text "{% set paged = user and user.settings.paged_timelines %}") (script (text "setTimeout(() => { trigger(\"ui::io_data_load\", [\"/_swiss_army_timeline?tl=AllPosts&before=$1$&page=\", Number.parseInt(\"{{ page }}\") - 1, \"{{ paged }}\" === \"true\"]); });")) + (text "{% endblock %}") diff --git a/crates/app/src/public/html/timelines/all_forum_posts.lisp b/crates/app/src/public/html/timelines/all_forum_posts.lisp deleted file mode 100644 index 7a171fb..0000000 --- a/crates/app/src/public/html/timelines/all_forum_posts.lisp +++ /dev/null @@ -1,34 +0,0 @@ -(text "{% extends \"root.html\" %} {% block head %}") -(title - (text "Latest forum posts - {{ config.name }}")) -(text "{% endblock %} {% block body %} {{ macros::nav() }}") -(main - ("class" "flex flex_col gap_2") - (text "{{ macros::timelines_nav(selected=\"all\", posts=\"/all\", questions=\"/all/questions\", secondary_selected=\"forum_posts\", forum_posts=\"/all/forum_posts\") }}") - (div - ("class" "card w_full flex flex_col gap_2") - (text "{% if config.town_square_forum != 0 -%}") - (a - ("href" "/communities/intents/post?community={{ config.town_square_forum }}&topic={{ config.town_square_forum_topic }}&sig=true&topics=true") - ("class" "button small lowered") - ("data-turbo" "false") - (icon (text "plus")) - (span - (str (text "general:action.post")))) - (text "{%- endif %}") - - (div - ("class" "w_full") - ("style" "overflow: auto") - (table - ("class" "w_full") - (thead - (th (text "In")) - (th (text "Title")) - (th (text "Replies")) - (th (text "Score")) - (th (text "Created"))) - (tbody - (text "{% for post in feed %} {{ components::topic_post_display(post=post[0], owner=post[1], community=post[2]) }} {% endfor %}")))) - (text "{{ components::pagination(page=page, items=feed|length) }}"))) -(text "{% endblock %}") diff --git a/crates/app/src/public/html/timelines/all_questions.lisp b/crates/app/src/public/html/timelines/all_questions.lisp index 00626de..70243ee 100644 --- a/crates/app/src/public/html/timelines/all_questions.lisp +++ b/crates/app/src/public/html/timelines/all_questions.lisp @@ -1,11 +1,13 @@ (text "{% extends \"root.html\" %} {% block head %}") (title (text "Latest questions - {{ config.name }}")) + (text "{% endblock %} {% block body %} {{ macros::nav() }}") (main ("class" "flex flex_col gap_2") - (text "{{ macros::timelines_nav(selected=\"all\", posts=\"/all\", questions=\"/all/questions\", secondary_selected=\"questions\", forum_posts=\"/all/forum_posts\") }}") + (text "{{ macros::timelines_nav(selected=\"all\", posts=\"/all\", questions=\"/all/questions\", secondary_selected=\"questions\") }}") (div ("class" "card w_full flex flex_col gap_2") (text "{% for question in list %} {{ components::global_question(question=question, can_manage_questions=false, secondary=true) }} {% endfor %} {{ components::pagination(page=page, items=list|length) }}"))) + (text "{% endblock %}") diff --git a/crates/app/src/public/js/ads.js b/crates/app/src/public/js/ads.js deleted file mode 100644 index 654ae72..0000000 --- a/crates/app/src/public/js/ads.js +++ /dev/null @@ -1,65 +0,0 @@ -globalThis.TetrattoAds = { - AD_SIZES: { - Billboard: [970, 250], - Leaderboard: [720, 90], - Skyscraper: [160, 600], - MediumRectangle: [300, 250], - MobileLeaderboard: [320, 50], - }, - IS_MOBILE: window.innerWidth <= 900 && window.innerHeight <= 900, -}; - -globalThis.TetrattoAds.init = () => { - const styles = document.createElement("style"); - styles.id = "tetratto_ads_css"; - styles.setAttribute("data-turbo-permanent", "true"); - - styles.innerHTML = `.tetratto_ad { - width: 100%; - display: grid; - place-items: center; - } - - .tetratto_ad, - .tetratto_ad iframe { - max-width: 100%; - background: transparent; - }`; - - document.head.appendChild(styles); -}; - -globalThis.TetrattoAds.render_ads = ( - host_id = 0, - tetratto = "https://tetratto.com", -) => { - for (const element of Array.from( - document.querySelectorAll(".tetratto_ad"), - )) { - if (element.children.length > 0) { - continue; - } - - const iframe = document.createElement("iframe"); - let size = element.getAttribute("data-ad-size") || "MediumRectangle"; - - if (size === "Leaderboard" && TetrattoAds.IS_MOBILE) { - size = "MobileLeaderboard"; - } - - const size_px = TetrattoAds.AD_SIZES[size]; - - const noclick = - element.getAttribute("data-noclick") === "true" || false; - const ad_id = element.getAttribute("data-ad-id"); - - iframe.src = `${tetratto}/adn/${ad_id ? ad_id : "random"}?size=${size}&host=${host_id}&noclick=${noclick}`; - iframe.setAttribute("frameborder", "0"); - iframe.loading = "lazy"; - - iframe.style.width = `${size_px[0]}px`; - iframe.style.height = `${size_px[1]}px`; - - element.appendChild(iframe); - } -}; diff --git a/crates/app/src/public/js/atto.js b/crates/app/src/public/js/atto.js index ac6dda8..8791aeb 100644 --- a/crates/app/src/public/js/atto.js +++ b/crates/app/src/public/js/atto.js @@ -85,10 +85,6 @@ media_theme_pref(); element.removeAttribute("checked"); } - for (const element of document.querySelectorAll('[disabled="false"]')) { - element.removeAttribute("disabled"); - } - for (const element of document.querySelectorAll('[selected="true"]')) { element.parentElement.value = element.value; } diff --git a/crates/app/src/public/js/me.js b/crates/app/src/public/js/me.js index 708baf4..9b8ad1d 100644 --- a/crates/app/src/public/js/me.js +++ b/crates/app/src/public/js/me.js @@ -726,7 +726,7 @@ element.innerHTML = ""; for (const token of Object.entries($.LOGIN_ACCOUNT_TOKENS)) { element.innerHTML += `
-