Merge branch 'tasiaiso-wiki-improvements'
This commit is contained in:
		| @@ -2,8 +2,9 @@ | ||||
| <html> | ||||
| 	<head> | ||||
| 		<base target="_top" /> | ||||
| 		<link rel="stylesheet" href="tildefriends.css" /> | ||||
| 	</head> | ||||
| 	<body style="color: #fff"> | ||||
| 	<body> | ||||
| 		<tf-collections-app></tf-collections-app> | ||||
| 		<script> | ||||
| 			window.litDisableBundleWarning = true; | ||||
|   | ||||
| @@ -5,6 +5,7 @@ class TfCollectionElement extends LitElement { | ||||
| 	static get properties() { | ||||
| 		return { | ||||
| 			whoami: {type: String}, | ||||
| 			category: {type: String}, | ||||
| 			collection: {type: Object}, | ||||
| 			selected_id: {type: String}, | ||||
| 			is_creating: {type: Boolean}, | ||||
| @@ -75,9 +76,10 @@ class TfCollectionElement extends LitElement { | ||||
| 	render() { | ||||
| 		let self = this; | ||||
| 		return html` | ||||
| 			<span style="display: inline-flex; flex-direction: row"> | ||||
| 			<link rel="stylesheet" href="tildefriends.css"/> | ||||
| 			<span class="inline-flex-row"> | ||||
| 				<select @change=${this.on_selected} id="select" value=${this.selected_id}> | ||||
| 					<option value="" ?selected=${this.selected_id === ''} disabled hidden>(select)</option> | ||||
| 					<option value="" ?selected=${this.selected_id === ''} disabled hidden>(select ${this.category})</option> | ||||
| 					${Object.values(this.collection ?? {}) | ||||
| 						.sort((x, y) => x.name.localeCompare(y.name)) | ||||
| 						.map( | ||||
| @@ -91,22 +93,22 @@ class TfCollectionElement extends LitElement { | ||||
| 						)} | ||||
| 				</select> | ||||
| 				<span ?hidden=${!this.is_renaming || !this.whoami}> | ||||
| 					<span style="display: inline-flex; flex-direction: row; margin-left: 8px; margin-right: 8px"> | ||||
| 					<span class="inline-flex-row" style="margin-left: 8px; margin-right: 8px"> | ||||
| 						<label for="rename_name">🏷Rename to:</label> | ||||
| 						<input type="text" id="rename_name"></input> | ||||
| 						<button @click=${this.on_rename}>Rename ${this.type}</button> | ||||
| 						<button @click=${() => (self.is_renaming = false)}>x</button> | ||||
| 					</span> | ||||
| 				</span> | ||||
| 				<button @click=${() => (self.is_renaming = true)} ?disabled=${this.is_renaming || !this.selected_id} ?hidden=${!this.whoami}>🏷</button> | ||||
| 				<button @click=${self.on_tombstone} ?disabled=${!this.selected_id} ?hidden=${!this.whoami}>🪦</button> | ||||
| 				<button class="yellow" @click=${() => (self.is_renaming = true)} ?disabled=${this.is_renaming || !this.selected_id} ?hidden=${!this.whoami}>🏷</button> | ||||
| 				<button class="red" @click=${self.on_tombstone} ?disabled=${!this.selected_id} ?hidden=${!this.whoami}>🪦</button> | ||||
| 				<span ?hidden=${!this.is_creating || !this.whoami}> | ||||
| 					<label for="create_name">New ${this.type} name:</label> | ||||
| 					<input type="text" id="create_name"></input> | ||||
| 					<button @click=${this.on_create}>Create ${this.type}</button> | ||||
| 					<button @click=${() => (self.is_creating = false)}>x</button> | ||||
| 				</span> | ||||
| 				<button @click=${() => (self.is_creating = true)} ?hidden=${this.is_creating || !this.whoami}>+</button> | ||||
| 				<button class="green" @click=${() => (self.is_creating = true)} ?hidden=${this.is_creating || !this.whoami}>+</button> | ||||
| 			</span> | ||||
| 		`; | ||||
| 	} | ||||
|   | ||||
| @@ -28,6 +28,7 @@ class TfIdentityPickerElement extends LitElement { | ||||
|  | ||||
| 	render() { | ||||
| 		return html` | ||||
| 			<link rel="stylesheet" href="tildefriends.css" /> | ||||
| 			<select @change=${this.changed} style="max-width: 100%"> | ||||
| 				${(this.ids ?? []).map( | ||||
| 					(id) => | ||||
|   | ||||
| @@ -255,12 +255,22 @@ class TfCollectionsAppElement extends LitElement { | ||||
| 	render() { | ||||
| 		let self = this; | ||||
| 		return html` | ||||
| 			<link rel="stylesheet" href="tildefriends.css"/> | ||||
| 			<style> | ||||
| 				.toc:hover { | ||||
| 				.toc-item { | ||||
| 					white-space: nowrap; | ||||
| 					cursor: pointer; | ||||
| 				} | ||||
| 				.toc-item:hover { | ||||
| 					background-color: #0cc; | ||||
| 				} | ||||
| 				.toc.selected { | ||||
| 				.toc-item.selected { | ||||
| 					background-color: #088; | ||||
| 					font-weight: bold; | ||||
| 				} | ||||
| 				.table-of-contents { | ||||
| 					flex: 0 0; | ||||
| 					margin-right: 16px; | ||||
| 				} | ||||
| 			</style> | ||||
| 			<div> | ||||
| @@ -272,6 +282,7 @@ class TfCollectionsAppElement extends LitElement { | ||||
| 					html`<tf-collection | ||||
| 						.collection=${this.wikis} | ||||
| 						whoami=${this.whoami} | ||||
| 						category="wiki" | ||||
| 						selected_id=${this.wiki?.id} | ||||
| 						@create=${this.on_wiki_create} | ||||
| 						@rename=${this.on_wiki_rename} | ||||
| @@ -284,6 +295,7 @@ class TfCollectionsAppElement extends LitElement { | ||||
| 					html`<tf-collection | ||||
| 						.collection=${this.wiki_docs} | ||||
| 						whoami=${this.whoami} | ||||
| 						category="document" | ||||
| 						selected_id=${this.wiki_doc && | ||||
| 						this.wiki_doc?.parent == this.wiki?.id | ||||
| 							? this.wiki_doc?.id | ||||
| @@ -298,9 +310,9 @@ class TfCollectionsAppElement extends LitElement { | ||||
| 				<div ?hidden=${!this.wiki?.editors || !this.expand_editors}> | ||||
| 					<div> | ||||
| 						<ul> | ||||
| 							${this.wiki?.editors.map((id) => html`<li><button ?hidden=${id == this.whoami} @click=${() => self.on_remove_editor(id)}>x</button> ${id}</li>`)} | ||||
| 							${this.wiki?.editors.map((id) => html`<li><button class="red" ?hidden=${id == this.whoami} @click=${() => self.on_remove_editor(id)}>x</button> ${id}</li>`)} | ||||
| 							<li> | ||||
| 								<button @click=${() => (self.adding_editor = true)} ?hidden=${this.wiki?.editors?.indexOf(this.whoami) == -1 || this.adding_editor}>+</button> | ||||
| 								<button class="green" @click=${() => (self.adding_editor = true)} ?hidden=${this.wiki?.editors?.indexOf(this.whoami) == -1 || this.adding_editor}>+</button> | ||||
| 								<div ?hidden=${!this.adding_editor}> | ||||
| 									<label for="add_editor">Add Editor:</label> | ||||
| 									<input type="text" id="add_editor"></input> | ||||
| @@ -312,18 +324,19 @@ class TfCollectionsAppElement extends LitElement { | ||||
| 					</div> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 			<div style="display: flex; flex-direction: row"> | ||||
| 				<div style="flex: 0 0"> | ||||
| 			<div class="flex-row"> | ||||
| 				<div class="box table-of-contents"> | ||||
| 					${Object.values(this.wikis || {}) | ||||
| 						.sort((x, y) => x.name.localeCompare(y.name)) | ||||
| 						.map( | ||||
| 							(wiki) => html` | ||||
| 								<div | ||||
| 									class="toc ${self.wiki?.id === wiki.id ? 'selected' : ''}" | ||||
| 									style="white-space: nowrap; cursor: pointer" | ||||
| 									class="toc-item ${self.wiki?.id === wiki.id | ||||
| 										? 'selected' | ||||
| 										: ''}" | ||||
| 									@click=${() => self.on_wiki_changed({detail: {value: wiki}})} | ||||
| 								> | ||||
| 									${wiki.name} | ||||
| 									${self.wiki?.id === wiki.id ? '' : '>'} ${wiki.name} | ||||
| 								</div> | ||||
| 								<ul> | ||||
| 									${Object.values(self.wiki_docs || {}) | ||||
| @@ -332,10 +345,10 @@ class TfCollectionsAppElement extends LitElement { | ||||
| 										.map( | ||||
| 											(doc) => html` | ||||
| 												<li | ||||
| 													class="toc ${self.wiki_doc?.id === doc.id | ||||
| 													class="toc-item ${self.wiki_doc?.id === doc.id | ||||
| 														? 'selected' | ||||
| 														: ''}" | ||||
| 													style="white-space: nowrap; cursor: pointer; list-style: none; text-indent: -1rem" | ||||
| 													style="list-style: none; text-indent: -1rem" | ||||
| 													@click=${() => | ||||
| 														self.on_wiki_doc_changed({detail: {value: doc}})} | ||||
| 												> | ||||
|   | ||||
| @@ -84,7 +84,11 @@ class TfWikiDocElement extends LitElement { | ||||
|  | ||||
| 	async load_blob() { | ||||
| 		let blob = await tfrpc.rpc.get_blob(this.value?.blob); | ||||
| 		if (blob.endsWith('.box')) { | ||||
| 		if (!blob) { | ||||
| 			console.warn( | ||||
| 				"no blob found, we're going to assume the document is empty (load_blob())" | ||||
| 			); | ||||
| 		} else if (blob.endsWith('.box')) { | ||||
| 			let d = await tfrpc.rpc.try_decrypt(this.whoami, blob); | ||||
| 			if (d) { | ||||
| 				blob = d; | ||||
| @@ -253,85 +257,43 @@ class TfWikiDocElement extends LitElement { | ||||
| 		let self = this; | ||||
| 		let thumbnail_ref = this.thumbnail(this.blob); | ||||
| 		return html` | ||||
| 			<link rel="stylesheet" href="tildefriends.css"/> | ||||
| 			<style> | ||||
| 				a:link { | ||||
| 					color: #268bd2; | ||||
| 				} | ||||
| 				a:visited { | ||||
| 					color: #6c71c4; | ||||
| 				} | ||||
| 				a:hover { | ||||
| 					color: #859900; | ||||
| 				} | ||||
| 				a:active { | ||||
| 					color: #2aa198; | ||||
| 				} | ||||
| 				a:link { color: #268bd2 } | ||||
| 				a:visited { color: #6c71c4 } | ||||
| 				a:hover { color: #859900 } | ||||
| 				a:active { color: #2aa198 } | ||||
|  | ||||
| 				#editor-text-area { | ||||
| 					background-color: #00000040; | ||||
| 					color: white; | ||||
| 					style="flex: 1 1; | ||||
| 					min-height: 10em; | ||||
| 					font-size: larger; | ||||
| 					${this.value?.private ? 'border: 4px solid #800' : ''} | ||||
| 			</style> | ||||
| 			<div style="display: inline-flex; flex-direction: row"> | ||||
| 				<button | ||||
| 					?disabled=${!this.whoami || this.is_editing} | ||||
| 					@click=${() => (self.is_editing = true)} | ||||
| 				> | ||||
| 					Edit | ||||
| 				</button> | ||||
| 				<button | ||||
| 					?disabled=${this.blob == this.blob_original} | ||||
| 					@click=${this.on_save_draft} | ||||
| 				> | ||||
| 					Save Draft | ||||
| 				</button> | ||||
| 				<button | ||||
| 					?disabled=${this.blob == this.blob_original && !this.value?.draft} | ||||
| 					@click=${this.on_publish} | ||||
| 				> | ||||
| 					Publish | ||||
| 				</button> | ||||
| 				<button ?disabled=${!this.is_editing} @click=${this.on_discard}> | ||||
| 					Discard | ||||
| 				</button> | ||||
| 				<button | ||||
| 					?disabled=${!this.is_editing} | ||||
| 					@click=${() => | ||||
| 						(self.value = Object.assign({}, self.value, { | ||||
| 							private: !self.value.private, | ||||
| 						}))} | ||||
| 				> | ||||
| 					${this.value?.private ? 'Make Public' : 'Make Private'} | ||||
| 				</button> | ||||
| 				<button ?disabled=${!this.is_editing} @click=${this.on_blog_publish}> | ||||
| 					Publish Blog | ||||
| 				</button> | ||||
| 			<div class="inline-flex-row"> | ||||
| 				<button ?disabled=${!this.whoami || this.is_editing} @click=${() => (self.is_editing = true)}>Edit</button> | ||||
| 				<button ?disabled=${this.blob == this.blob_original} @click=${this.on_save_draft}>Save Draft</button> | ||||
| 				<button ?disabled=${this.blob == this.blob_original && !this.value?.draft} @click=${this.on_publish}>Publish</button> | ||||
| 				<button ?disabled=${!this.is_editing} @click=${this.on_discard}>Discard</button> | ||||
| 				<button ?disabled=${!this.is_editing} @click=${() => (self.value = Object.assign({}, self.value, {private: !self.value.private}))}>${this.value?.private ? 'Make Public' : 'Make Private'}</button> | ||||
| 				<button ?disabled=${!this.is_editing} @click=${this.on_blog_publish}>Publish Blog</button> | ||||
| 			</div> | ||||
| 			<div ?hidden=${!this.value?.private} style="color: #800"> | ||||
| 				🔒 document is private | ||||
| 			</div> | ||||
| 			<div | ||||
| 				style="display: flex; flex-direction: row; ${this.value?.private | ||||
| 					? 'border-top: 4px solid #800' | ||||
| 					: ''}" | ||||
| 			> | ||||
| 			<div ?hidden=${!this.value?.private} style="color: #800">🔒 document is private</div> | ||||
| 			<div class="flex-column" ${this.value?.private ? 'border-top: 4px solid #800' : ''}"> | ||||
| 				<textarea | ||||
| 					rows="25" | ||||
| 					?hidden=${!this.is_editing} | ||||
| 					style="flex: 1 1; min-height: 10em; ${this.value?.private | ||||
| 						? 'border: 4px solid #800' | ||||
| 						: ''}" | ||||
| 					id="editor-text-area" | ||||
| 					@input=${this.on_edit} | ||||
| 					@paste=${this.paste} | ||||
| 					.value=${this.blob ?? ''} | ||||
| 				></textarea> | ||||
| 				<div style="flex: 1 1"> | ||||
| 					<div | ||||
| 						?hidden=${!this.is_editing} | ||||
| 						style="border: 1px solid #fff; border-radius: 1em; padding: 0.5em" | ||||
| 					> | ||||
| 						<img | ||||
| 							?hidden=${!thumbnail_ref} | ||||
| 							style="max-width: 128px; max-height: 128px; float: right" | ||||
| 							src="/${thumbnail_ref}/view" | ||||
| 						/> | ||||
| 						<h1 ?hidden=${!this.title(this.blob)}> | ||||
| 							${unsafeHTML(this.markdown(this.title(this.blob)))} | ||||
| 						</h1> | ||||
| 					.value=${this.blob ?? ''}></textarea> | ||||
| 				<div style="flex: 1 1; margin-top: 16px"> | ||||
| 					<div ?hidden=${!this.is_editing} class="box"> | ||||
| 						Summary | ||||
| 						<img ?hidden=${!thumbnail_ref} style="max-width: 128px; max-height: 128px; float: right" src="/${thumbnail_ref}/view"> | ||||
| 						<h1 ?hidden=${!this.title(this.blob)}>${unsafeHTML(this.markdown(this.title(this.blob)))}</h1> | ||||
| 						${unsafeHTML(this.markdown(this.summary(this.blob)))} | ||||
| 					</div> | ||||
| 					${unsafeHTML(this.markdown(this.blob))} | ||||
|   | ||||
							
								
								
									
										115
									
								
								apps/wiki/tildefriends.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								apps/wiki/tildefriends.css
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,115 @@ | ||||
| /* | ||||
|  * Tilde Friends core stylesheet | ||||
|  * This is a prototype; things may change based on feedback. | ||||
|  * | ||||
|  * This Software is an external library that is part of | ||||
|  * Tilde Friends and is shared under the MIT license. | ||||
|  * | ||||
|  * Inject this file in your app at tildefriends.css | ||||
|  * and use this tag to import it: | ||||
|  * <link rel="stylesheet" href="tildefriends.css"/> | ||||
|  * | ||||
|  * Revision 0 / 2024 M02 19 | ||||
|  */ | ||||
|  | ||||
| body { | ||||
| 	color: white; | ||||
| 	font-family: sans-serif; | ||||
| } | ||||
|  | ||||
| button, | ||||
| .button, | ||||
| input[type='button'], | ||||
| input[type='submit'], | ||||
| select { | ||||
| 	border: none; | ||||
| 	border-radius: 8px; | ||||
| 	padding: 8px 12px; | ||||
| 	text-align: center; | ||||
| 	text-decoration: none; | ||||
| 	display: inline-block; | ||||
| 	margin: 4px; | ||||
|  | ||||
| 	&.red { | ||||
| 		background-color: #bd1e24; | ||||
| 		color: white; | ||||
| 	} | ||||
|  | ||||
| 	&.green { | ||||
| 		background-color: #18922d; | ||||
| 		color: white; | ||||
| 	} | ||||
|  | ||||
| 	&.blue { | ||||
| 		background-color: #0067a7; | ||||
| 		color: white; | ||||
| 	} | ||||
|  | ||||
| 	&.yellow { | ||||
| 		background-color: #ee9600; | ||||
| 		color: black; | ||||
| 	} | ||||
|  | ||||
| 	&:hover { | ||||
| 		filter: brightness(0.75); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| a:link { | ||||
| 	color: #268bd2; | ||||
| } | ||||
|  | ||||
| a:visited { | ||||
| 	color: #6c71c4; | ||||
| } | ||||
|  | ||||
| a:hover { | ||||
| 	color: #859900; | ||||
| } | ||||
|  | ||||
| a:active { | ||||
| 	color: #2aa198; | ||||
| } | ||||
|  | ||||
| table { | ||||
| 	border-collapse: collapse; | ||||
| 	width: 100%; | ||||
| } | ||||
|  | ||||
| td, | ||||
| th { | ||||
| 	border: 1px solid #ffffff40; | ||||
| 	text-align: left; | ||||
| 	padding: 8px; | ||||
| } | ||||
|  | ||||
| tr:nth-child(even) { | ||||
| 	background-color: #ffffff20; | ||||
| } | ||||
|  | ||||
| .flex { | ||||
| 	display: flex; | ||||
| } | ||||
|  | ||||
| .flex-column { | ||||
| 	display: flex; | ||||
| 	flex-direction: column; | ||||
| } | ||||
|  | ||||
| .flex-row { | ||||
| 	display: flex; | ||||
| 	flex-direction: row; | ||||
| } | ||||
|  | ||||
| .inline-flex-row { | ||||
| 	display: inline-flex; | ||||
| 	flex-direction: row; | ||||
| } | ||||
|  | ||||
| .box { | ||||
| 	background-color: #00000020; | ||||
| 	border: 1px solid grey; | ||||
| 	border-radius: 8px; | ||||
| 	padding: 16px; | ||||
| 	margin: 4px; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user