Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added support for custom expire option for new paste #4

Merged
merged 2 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,17 @@
- ✨ Code highlighting and line numbers (default)
- 📖 Markdown rendering (click the <a href="https://github.com/BRAVO68WEB/zer0bin"><img alt="Markdown" src="https://user-images.githubusercontent.com/44733677/161484749-fdf60750-36ae-4d0a-aaa5-cdcae54fc805.svg" height=18></a> button)
- 🔥 Single-view pastes (click the <a href="https://github.com/BRAVO68WEB/zer0bin"><img alt="Fire" src="https://user-images.githubusercontent.com/44733677/161485115-c5fccb81-fa21-4e67-88fd-9a6f9dff728e.svg" height=18></a> button)
- ‍🧑‍💻 [CLI Client](https://github.com/BRAVO68WEB/zer0)
- 🚀 Easily selfhostable
- 🔐 Password protected pastes
- 📆 Custom expiring pastes
- ‍🧑‍💻 [CLI Client](apps/cli)
- 🚀 Easily to self host
- 👀 View counter
- ⌨️ Keybinds
- <kbd>Ctrl</kbd> + <kbd>S</kbd>: save paste
- <kbd>Ctrl</kbd> + <kbd>N</kbd>: new paste
- <kbd>Ctrl</kbd> + <kbd>D</kbd>: duplicate paste
- <kbd>Ctrl</kbd> + <kbd>M</kbd>: toggle markdown mode
- <kbd>Ctrl</kbd> + <kbd>X</kbd>: copy raw url to clipboard
- 📱 Mobile-friendly UI
- 🧈 Super smooth scrolling
- 🖼️ Badge generation for stats (seen below)
Expand Down
2 changes: 2 additions & 0 deletions apps/frontend/index.pug
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ html(lang='en')
span.viewcounter.noselect#viewcounter-count(style='visibility: hidden; display: none')

.bottom-button-wrapper
input#expire-button.input(aria-label='Expire', type='date')
button#enable-expire-button.btn(aria-label='Enable expire')
button#hide-button.btn(aria-label='Hide')
button#lock-button.btn(aria-label='Lock')

Expand Down
24 changes: 23 additions & 1 deletion apps/frontend/src/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import {
FileMarkdownOutlined,
ShareAltOutlined,
VerticalLeftOutlined,
LockOutlined
LockOutlined,
CalendarFilled,
CalendarOutlined
} from "@ant-design/icons-svg"
import { renderIconDefinitionToSVGElement } from "@ant-design/icons-svg/es/helpers"
import tippy from "tippy.js"
Expand All @@ -25,6 +27,8 @@ const newButton = <HTMLButtonElement>document.getElementById("new-button")
const copyButton = <HTMLButtonElement>document.getElementById("copy-button")
const hideButton = <HTMLButtonElement>document.getElementById("hide-button")
const lockButton = <HTMLButtonElement>document.getElementById("lock-button")
const expireButton = <HTMLButtonElement>document.getElementById("expire-button")
const enableExpireButton = <HTMLButtonElement>document.getElementById("enable-expire-button")
const githubButton = <HTMLButtonElement>document.getElementById("github-button")
const shareButton = <HTMLButtonElement>document.getElementById("share-button")
const markdownButton = <HTMLButtonElement>(
Expand Down Expand Up @@ -57,6 +61,8 @@ renderIcon(singleViewButton, FireOutlined)
renderIcon(shareButton, ShareAltOutlined)
renderIcon(rawButton, VerticalLeftOutlined)
renderIcon(lockButton, LockOutlined)
renderIcon(expireButton, CalendarFilled)
renderIcon(enableExpireButton, CalendarOutlined)

tippy("#open-raw-button", {
content: "Copy raw url to clipboard<br><span class='keybind'>Ctrl + X</span>",
Expand Down Expand Up @@ -146,6 +152,22 @@ tippy("#lock-button", {
allowHTML: true,
})

tippy("#expire-button", {
content: "Set an expiration date",
placement: "top",
animation: "scale",
theme: "rosepine",
allowHTML: true,
})

tippy("#enable-expire-button", {
content: "Enable/Disable expiration date settings",
placement: "top",
animation: "scale",
theme: "rosepine",
allowHTML: true,
})

const observer = new MutationObserver(callback)

function callback() {
Expand Down
26 changes: 25 additions & 1 deletion apps/frontend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ let isMarkdown = false
let singleView = false
let locked = false
let lockPassword = ""
let expireDate = ""
let isExpireDateEnabled = false

const jsConfetti = new JSConfetti()

Expand Down Expand Up @@ -55,6 +57,8 @@ const singleViewButton = <HTMLButtonElement>(
document.getElementById("single-view-button")
)
const lockButton = <HTMLButtonElement>document.getElementById("lock-button")
const expireButton = <HTMLButtonElement>document.getElementById("expire-button")
const enableExpireButton = <HTMLButtonElement>document.getElementById("enable-expire-button")

function hide(element: HTMLElement) {
element.style.visibility = "hidden"
Expand All @@ -76,9 +80,15 @@ function enable(element: HTMLButtonElement) {

async function postPaste(content: string, callback: Function) {
const payload = { content, single_view: singleView }
if(isExpireDateEnabled){
expireDate = new Date(expireButton.value).toISOString()
payload["expires_at"] = expireDate
}

if (locked && lockPassword) {
payload["password"] = lockPassword
}

await fetch(`${API_URL}/p/n`, {
method: "POST",
headers: {
Expand Down Expand Up @@ -175,6 +185,8 @@ function newPaste() {
disable(rawButton)
enable(singleViewButton)
enable(lockButton)
enable(enableExpireButton)
hide(expireButton)

editor.value = ""
rawContent = ""
Expand Down Expand Up @@ -251,7 +263,9 @@ function viewPaste(content: string, views: string, singleView: boolean) {
viewCounter.style.display = null

viewCounter.textContent = views
disable(lockButton)
hide(lockButton)
hide(expireButton)
hide(enableExpireButton)

try {
wrapper.classList.remove("text-area-proper")
Expand Down Expand Up @@ -404,6 +418,16 @@ lockButton.addEventListener("click", function () {
show(lockButton.firstElementChild as HTMLElement)
})

enableExpireButton.addEventListener("click", function () {
if(!isExpireDateEnabled){
isExpireDateEnabled = true
show(expireButton)
} else {
isExpireDateEnabled = false
hide(expireButton)
}
})

markdownButton.addEventListener("click", function () {
toggleMarkdown()
})
Expand Down
10 changes: 10 additions & 0 deletions apps/frontend/style/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ a {
cursor: auto;
}
.bottom-button-wrapper {
display: flex;
position: fixed !important;
bottom: 0;
right: 0;
Expand All @@ -191,6 +192,15 @@ a {
color: $gold;
}
}

.input {
background-color: $bg_surface;
color: $muted;
border: none;
&:hover {
color: $gold;
}
}
}
// #share-button {
// position: fixed !important;
Expand Down
1 change: 1 addition & 0 deletions packages/backend/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub struct PartialPaste {
pub content: String,
pub single_view: bool,
pub password: Option<String>,
pub expires_at: Option<String>,
}

#[derive(Serialize)]
Expand Down
9 changes: 6 additions & 3 deletions packages/backend/src/routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use actix_web::{

use badge_maker::{BadgeBuilder, Style};

use chrono::Duration;
use chrono::{DateTime, Duration};
use nanoid::nanoid;
use sqlx::{postgres::PgRow, types::chrono::Utc, Row};
use serde::Deserialize;
Expand Down Expand Up @@ -205,13 +205,16 @@ pub async fn new_paste(

let length = state.config.pastes.id_length;
let id = nanoid!(length);

let expires_at = if state.config.pastes.days_til_expiration == -1 {

let expires_at = if Option::is_some(&data.expires_at) {
Some(DateTime::parse_from_rfc3339(&data.expires_at.clone().unwrap()).unwrap().with_timezone(&Utc))
} else if state.config.pastes.days_til_expiration == -1 {
None
} else {
Some(Utc::now() + Duration::days(state.config.pastes.days_til_expiration))
};


let content = data.content.clone();
let single_view = data.single_view;
let password = if Option::is_some(&data.password) {
Expand Down
2 changes: 2 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading