forked from open-webui/open-webui
		
	refac: styling
This commit is contained in:
		
							parent
							
								
									ebc6a269d3
								
							
						
					
					
						commit
						b7fcf14f6e
					
				
					 13 changed files with 259 additions and 33 deletions
				
			
		|  | @ -89,6 +89,10 @@ class SignupForm(BaseModel): | ||||||
|     profile_image_url: Optional[str] = "/user.png" |     profile_image_url: Optional[str] = "/user.png" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | class AddUserForm(SignupForm): | ||||||
|  |     role: str = "pending" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| class AuthsTable: | class AuthsTable: | ||||||
|     def __init__(self, db): |     def __init__(self, db): | ||||||
|         self.db = db |         self.db = db | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ import uuid | ||||||
| from apps.web.models.auths import ( | from apps.web.models.auths import ( | ||||||
|     SigninForm, |     SigninForm, | ||||||
|     SignupForm, |     SignupForm, | ||||||
|  |     AddUserForm, | ||||||
|     UpdateProfileForm, |     UpdateProfileForm, | ||||||
|     UpdatePasswordForm, |     UpdatePasswordForm, | ||||||
|     UserResponse, |     UserResponse, | ||||||
|  | @ -205,6 +206,50 @@ async def signup(request: Request, form_data: SignupForm): | ||||||
|         raise HTTPException(500, detail=ERROR_MESSAGES.DEFAULT(err)) |         raise HTTPException(500, detail=ERROR_MESSAGES.DEFAULT(err)) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | ############################ | ||||||
|  | # AddUser | ||||||
|  | ############################ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @router.post("/add", response_model=SigninResponse) | ||||||
|  | async def signup(form_data: AddUserForm, user=Depends(get_admin_user)): | ||||||
|  | 
 | ||||||
|  |     if not validate_email_format(form_data.email.lower()): | ||||||
|  |         raise HTTPException( | ||||||
|  |             status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.INVALID_EMAIL_FORMAT | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |     if Users.get_user_by_email(form_data.email.lower()): | ||||||
|  |         raise HTTPException(400, detail=ERROR_MESSAGES.EMAIL_TAKEN) | ||||||
|  | 
 | ||||||
|  |     try: | ||||||
|  |         role = form_data.role | ||||||
|  |         hashed = get_password_hash(form_data.password) | ||||||
|  |         user = Auths.insert_new_auth( | ||||||
|  |             form_data.email.lower(), | ||||||
|  |             hashed, | ||||||
|  |             form_data.name, | ||||||
|  |             form_data.profile_image_url, | ||||||
|  |             role, | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |         if user: | ||||||
|  |             token = create_token(data={"id": user.id}) | ||||||
|  |             return { | ||||||
|  |                 "token": token, | ||||||
|  |                 "token_type": "Bearer", | ||||||
|  |                 "id": user.id, | ||||||
|  |                 "email": user.email, | ||||||
|  |                 "name": user.name, | ||||||
|  |                 "role": user.role, | ||||||
|  |                 "profile_image_url": user.profile_image_url, | ||||||
|  |             } | ||||||
|  |         else: | ||||||
|  |             raise HTTPException(500, detail=ERROR_MESSAGES.CREATE_USER_ERROR) | ||||||
|  |     except Exception as err: | ||||||
|  |         raise HTTPException(500, detail=ERROR_MESSAGES.DEFAULT(err)) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| ############################ | ############################ | ||||||
| # ToggleSignUp | # ToggleSignUp | ||||||
| ############################ | ############################ | ||||||
|  |  | ||||||
|  | @ -95,6 +95,44 @@ export const userSignUp = async ( | ||||||
| 	return res; | 	return res; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | export const addUser = async ( | ||||||
|  | 	token: string, | ||||||
|  | 	name: string, | ||||||
|  | 	email: string, | ||||||
|  | 	password: string, | ||||||
|  | 	role: string | ||||||
|  | ) => { | ||||||
|  | 	let error = null; | ||||||
|  | 
 | ||||||
|  | 	const res = await fetch(`${WEBUI_API_BASE_URL}/auths/add`, { | ||||||
|  | 		method: 'POST', | ||||||
|  | 		headers: { | ||||||
|  | 			'Content-Type': 'application/json' | ||||||
|  | 		}, | ||||||
|  | 		body: JSON.stringify({ | ||||||
|  | 			name: name, | ||||||
|  | 			email: email, | ||||||
|  | 			password: password, | ||||||
|  | 			role: role | ||||||
|  | 		}) | ||||||
|  | 	}) | ||||||
|  | 		.then(async (res) => { | ||||||
|  | 			if (!res.ok) throw await res.json(); | ||||||
|  | 			return res.json(); | ||||||
|  | 		}) | ||||||
|  | 		.catch((err) => { | ||||||
|  | 			console.log(err); | ||||||
|  | 			error = err.detail; | ||||||
|  | 			return null; | ||||||
|  | 		}); | ||||||
|  | 
 | ||||||
|  | 	if (error) { | ||||||
|  | 		throw error; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return res; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| export const updateUserProfile = async (token: string, name: string, profileImageUrl: string) => { | export const updateUserProfile = async (token: string, name: string, profileImageUrl: string) => { | ||||||
| 	let error = null; | 	let error = null; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,152 @@ | ||||||
|  | <script lang="ts"> | ||||||
|  | 	import { toast } from 'svelte-sonner'; | ||||||
|  | 	import { createEventDispatcher } from 'svelte'; | ||||||
|  | 	import { onMount, getContext } from 'svelte'; | ||||||
|  | 	import { addUser } from '$lib/apis/auths'; | ||||||
|  | 
 | ||||||
|  | 	import Modal from '../common/Modal.svelte'; | ||||||
|  | 
 | ||||||
|  | 	const i18n = getContext('i18n'); | ||||||
|  | 	const dispatch = createEventDispatcher(); | ||||||
|  | 
 | ||||||
|  | 	export let show = false; | ||||||
|  | 
 | ||||||
|  | 	let _user = { | ||||||
|  | 		name: '', | ||||||
|  | 		email: '', | ||||||
|  | 		password: '', | ||||||
|  | 		role: '' | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	const submitHandler = async () => { | ||||||
|  | 		const res = await addUser( | ||||||
|  | 			localStorage.token, | ||||||
|  | 			_user.name, | ||||||
|  | 			_user.email, | ||||||
|  | 			_user.password, | ||||||
|  | 			_user.role | ||||||
|  | 		).catch((error) => { | ||||||
|  | 			toast.error(error); | ||||||
|  | 		}); | ||||||
|  | 
 | ||||||
|  | 		if (res) { | ||||||
|  | 			dispatch('save'); | ||||||
|  | 			show = false; | ||||||
|  | 		} | ||||||
|  | 	}; | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <Modal size="sm" bind:show> | ||||||
|  | 	<div> | ||||||
|  | 		<div class=" flex justify-between dark:text-gray-300 px-5 pt-4 pb-3"> | ||||||
|  | 			<div class=" text-lg font-medium self-center">{$i18n.t('Add User')}</div> | ||||||
|  | 			<button | ||||||
|  | 				class="self-center" | ||||||
|  | 				on:click={() => { | ||||||
|  | 					show = false; | ||||||
|  | 				}} | ||||||
|  | 			> | ||||||
|  | 				<svg | ||||||
|  | 					xmlns="http://www.w3.org/2000/svg" | ||||||
|  | 					viewBox="0 0 20 20" | ||||||
|  | 					fill="currentColor" | ||||||
|  | 					class="w-5 h-5" | ||||||
|  | 				> | ||||||
|  | 					<path | ||||||
|  | 						d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" | ||||||
|  | 					/> | ||||||
|  | 				</svg> | ||||||
|  | 			</button> | ||||||
|  | 		</div> | ||||||
|  | 
 | ||||||
|  | 		<div class="flex flex-col md:flex-row w-full px-5 pb-4 md:space-x-4 dark:text-gray-200"> | ||||||
|  | 			<div class=" flex flex-col w-full sm:flex-row sm:justify-center sm:space-x-6"> | ||||||
|  | 				<form | ||||||
|  | 					class="flex flex-col w-full" | ||||||
|  | 					on:submit|preventDefault={() => { | ||||||
|  | 						submitHandler(); | ||||||
|  | 					}} | ||||||
|  | 				> | ||||||
|  | 					<div class=" "> | ||||||
|  | 						<div class="flex flex-col w-full"> | ||||||
|  | 							<div class=" mb-1 text-xs text-gray-500">{$i18n.t('Name')}</div> | ||||||
|  | 
 | ||||||
|  | 							<div class="flex-1"> | ||||||
|  | 								<input | ||||||
|  | 									class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 disabled:text-gray-500 dark:disabled:text-gray-500 outline-none" | ||||||
|  | 									type="text" | ||||||
|  | 									bind:value={_user.name} | ||||||
|  | 									placeholder={$i18n.t('Enter Your Full Name')} | ||||||
|  | 									autocomplete="off" | ||||||
|  | 									required | ||||||
|  | 								/> | ||||||
|  | 							</div> | ||||||
|  | 						</div> | ||||||
|  | 
 | ||||||
|  | 						<hr class=" dark:border-gray-800 my-3 w-full" /> | ||||||
|  | 
 | ||||||
|  | 						<div class="flex flex-col w-full"> | ||||||
|  | 							<div class=" mb-1 text-xs text-gray-500">{$i18n.t('Email')}</div> | ||||||
|  | 
 | ||||||
|  | 							<div class="flex-1"> | ||||||
|  | 								<input | ||||||
|  | 									class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 disabled:text-gray-500 dark:disabled:text-gray-500 outline-none" | ||||||
|  | 									type="email" | ||||||
|  | 									bind:value={_user.email} | ||||||
|  | 									placeholder={$i18n.t('Enter Your Email')} | ||||||
|  | 									autocomplete="off" | ||||||
|  | 									required | ||||||
|  | 								/> | ||||||
|  | 							</div> | ||||||
|  | 						</div> | ||||||
|  | 
 | ||||||
|  | 						<div class="flex flex-col w-full mt-2"> | ||||||
|  | 							<div class=" mb-1 text-xs text-gray-500">{$i18n.t('Password')}</div> | ||||||
|  | 
 | ||||||
|  | 							<div class="flex-1"> | ||||||
|  | 								<input | ||||||
|  | 									class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 disabled:text-gray-500 dark:disabled:text-gray-500 outline-none" | ||||||
|  | 									type="password" | ||||||
|  | 									bind:value={_user.password} | ||||||
|  | 									placeholder={$i18n.t('Enter Your Password')} | ||||||
|  | 									autocomplete="off" | ||||||
|  | 								/> | ||||||
|  | 							</div> | ||||||
|  | 						</div> | ||||||
|  | 					</div> | ||||||
|  | 
 | ||||||
|  | 					<div class="flex justify-end pt-3 text-sm font-medium"> | ||||||
|  | 						<button | ||||||
|  | 							class=" px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg" | ||||||
|  | 							type="submit" | ||||||
|  | 						> | ||||||
|  | 							{$i18n.t('Submit')} | ||||||
|  | 						</button> | ||||||
|  | 					</div> | ||||||
|  | 				</form> | ||||||
|  | 			</div> | ||||||
|  | 		</div> | ||||||
|  | 	</div> | ||||||
|  | </Modal> | ||||||
|  | 
 | ||||||
|  | <style> | ||||||
|  | 	input::-webkit-outer-spin-button, | ||||||
|  | 	input::-webkit-inner-spin-button { | ||||||
|  | 		/* display: none; <- Crashes Chrome on hover */ | ||||||
|  | 		-webkit-appearance: none; | ||||||
|  | 		margin: 0; /* <-- Apparently some margin are still there even though it's hidden */ | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	.tabs::-webkit-scrollbar { | ||||||
|  | 		display: none; /* for Chrome, Safari and Opera */ | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	.tabs { | ||||||
|  | 		-ms-overflow-style: none; /* IE and Edge */ | ||||||
|  | 		scrollbar-width: none; /* Firefox */ | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	input[type='number'] { | ||||||
|  | 		-moz-appearance: textfield; /* Firefox */ | ||||||
|  | 	} | ||||||
|  | </style> | ||||||
|  | @ -15,7 +15,7 @@ | ||||||
| 
 | 
 | ||||||
| <Modal bind:show> | <Modal bind:show> | ||||||
| 	<div> | 	<div> | ||||||
| 		<div class=" flex justify-between dark:text-gray-300 px-5 py-4"> | 		<div class=" flex justify-between dark:text-gray-300 px-5 pt-4 pb-2"> | ||||||
| 			<div class=" text-lg font-medium self-center">{$i18n.t('Admin Settings')}</div> | 			<div class=" text-lg font-medium self-center">{$i18n.t('Admin Settings')}</div> | ||||||
| 			<button | 			<button | ||||||
| 				class="self-center" | 				class="self-center" | ||||||
|  | @ -35,7 +35,6 @@ | ||||||
| 				</svg> | 				</svg> | ||||||
| 			</button> | 			</button> | ||||||
| 		</div> | 		</div> | ||||||
| 		<hr class=" dark:border-gray-800" /> |  | ||||||
| 
 | 
 | ||||||
| 		<div class="flex flex-col md:flex-row w-full p-4 md:space-x-4"> | 		<div class="flex flex-col md:flex-row w-full p-4 md:space-x-4"> | ||||||
| 			<div | 			<div | ||||||
|  |  | ||||||
|  | @ -36,7 +36,7 @@ | ||||||
| 
 | 
 | ||||||
| <Modal bind:show> | <Modal bind:show> | ||||||
| 	<div> | 	<div> | ||||||
| 		<div class=" flex justify-between dark:text-gray-300 px-5 py-4"> | 		<div class=" flex justify-between dark:text-gray-300 px-5 pt-4 pb-1"> | ||||||
| 			<div class=" text-lg font-medium self-center">{$i18n.t('Settings')}</div> | 			<div class=" text-lg font-medium self-center">{$i18n.t('Settings')}</div> | ||||||
| 			<button | 			<button | ||||||
| 				class="self-center" | 				class="self-center" | ||||||
|  | @ -56,7 +56,6 @@ | ||||||
| 				</svg> | 				</svg> | ||||||
| 			</button> | 			</button> | ||||||
| 		</div> | 		</div> | ||||||
| 		<hr class=" dark:border-gray-800" /> |  | ||||||
| 
 | 
 | ||||||
| 		<div class="flex flex-col md:flex-row w-full p-4 md:space-x-4"> | 		<div class="flex flex-col md:flex-row w-full p-4 md:space-x-4"> | ||||||
| 			<div | 			<div | ||||||
|  |  | ||||||
|  | @ -71,7 +71,7 @@ | ||||||
| 
 | 
 | ||||||
| <Modal bind:show size="sm"> | <Modal bind:show size="sm"> | ||||||
| 	<div> | 	<div> | ||||||
| 		<div class=" flex justify-between dark:text-gray-300 px-5 py-4"> | 		<div class=" flex justify-between dark:text-gray-300 px-5 pt-4 pb-0.5"> | ||||||
| 			<div class=" text-lg font-medium self-center">{$i18n.t('Share Chat')}</div> | 			<div class=" text-lg font-medium self-center">{$i18n.t('Share Chat')}</div> | ||||||
| 			<button | 			<button | ||||||
| 				class="self-center" | 				class="self-center" | ||||||
|  | @ -91,10 +91,9 @@ | ||||||
| 				</svg> | 				</svg> | ||||||
| 			</button> | 			</button> | ||||||
| 		</div> | 		</div> | ||||||
| 		<hr class=" dark:border-gray-800" /> |  | ||||||
| 
 | 
 | ||||||
| 		{#if chat} | 		{#if chat} | ||||||
| 			<div class="px-4 pt-4 pb-5 w-full flex flex-col justify-center"> | 			<div class="px-5 pt-4 pb-5 w-full flex flex-col justify-center"> | ||||||
| 				<div class=" text-sm dark:text-gray-300 mb-1"> | 				<div class=" text-sm dark:text-gray-300 mb-1"> | ||||||
| 					{#if chat.share_id} | 					{#if chat.share_id} | ||||||
| 						<a href="/s/{chat.share_id}" target="_blank" | 						<a href="/s/{chat.share_id}" target="_blank" | ||||||
|  |  | ||||||
|  | @ -9,7 +9,7 @@ | ||||||
| 
 | 
 | ||||||
| <Modal bind:show> | <Modal bind:show> | ||||||
| 	<div> | 	<div> | ||||||
| 		<div class=" flex justify-between dark:text-gray-300 px-5 py-4"> | 		<div class=" flex justify-between dark:text-gray-300 px-5 pt-4"> | ||||||
| 			<div class=" text-lg font-medium self-center">{$i18n.t('Keyboard shortcuts')}</div> | 			<div class=" text-lg font-medium self-center">{$i18n.t('Keyboard shortcuts')}</div> | ||||||
| 			<button | 			<button | ||||||
| 				class="self-center" | 				class="self-center" | ||||||
|  | @ -29,7 +29,6 @@ | ||||||
| 				</svg> | 				</svg> | ||||||
| 			</button> | 			</button> | ||||||
| 		</div> | 		</div> | ||||||
| 		<hr class=" dark:border-gray-800" /> |  | ||||||
| 
 | 
 | ||||||
| 		<div class="flex flex-col md:flex-row w-full p-5 md:space-x-4 dark:text-gray-200"> | 		<div class="flex flex-col md:flex-row w-full p-5 md:space-x-4 dark:text-gray-200"> | ||||||
| 			<div class=" flex flex-col w-full sm:flex-row sm:justify-center sm:space-x-6"> | 			<div class=" flex flex-col w-full sm:flex-row sm:justify-center sm:space-x-6"> | ||||||
|  |  | ||||||
|  | @ -96,7 +96,7 @@ | ||||||
| 
 | 
 | ||||||
| <Modal size="sm" bind:show> | <Modal size="sm" bind:show> | ||||||
| 	<div> | 	<div> | ||||||
| 		<div class=" flex justify-between dark:text-gray-300 px-5 py-4"> | 		<div class=" flex justify-between dark:text-gray-300 px-5 pt-4"> | ||||||
| 			<div class=" text-lg font-medium self-center">{$i18n.t('Add Docs')}</div> | 			<div class=" text-lg font-medium self-center">{$i18n.t('Add Docs')}</div> | ||||||
| 			<button | 			<button | ||||||
| 				class="self-center" | 				class="self-center" | ||||||
|  | @ -116,8 +116,6 @@ | ||||||
| 				</svg> | 				</svg> | ||||||
| 			</button> | 			</button> | ||||||
| 		</div> | 		</div> | ||||||
| 		<hr class=" dark:border-gray-800" /> |  | ||||||
| 
 |  | ||||||
| 		<div class="flex flex-col md:flex-row w-full px-5 py-4 md:space-x-4 dark:text-gray-200"> | 		<div class="flex flex-col md:flex-row w-full px-5 py-4 md:space-x-4 dark:text-gray-200"> | ||||||
| 			<div class=" flex flex-col w-full sm:flex-row sm:justify-center sm:space-x-6"> | 			<div class=" flex flex-col w-full sm:flex-row sm:justify-center sm:space-x-6"> | ||||||
| 				<form | 				<form | ||||||
|  |  | ||||||
|  | @ -75,7 +75,7 @@ | ||||||
| 
 | 
 | ||||||
| <Modal size="sm" bind:show> | <Modal size="sm" bind:show> | ||||||
| 	<div> | 	<div> | ||||||
| 		<div class=" flex justify-between dark:text-gray-300 px-5 py-4"> | 		<div class=" flex justify-between dark:text-gray-300 px-5 pt-4"> | ||||||
| 			<div class=" text-lg font-medium self-center">{$i18n.t('Edit Doc')}</div> | 			<div class=" text-lg font-medium self-center">{$i18n.t('Edit Doc')}</div> | ||||||
| 			<button | 			<button | ||||||
| 				class="self-center" | 				class="self-center" | ||||||
|  | @ -95,8 +95,6 @@ | ||||||
| 				</svg> | 				</svg> | ||||||
| 			</button> | 			</button> | ||||||
| 		</div> | 		</div> | ||||||
| 		<hr class=" dark:border-gray-800" /> |  | ||||||
| 
 |  | ||||||
| 		<div class="flex flex-col md:flex-row w-full px-5 py-4 md:space-x-4 dark:text-gray-200"> | 		<div class="flex flex-col md:flex-row w-full px-5 py-4 md:space-x-4 dark:text-gray-200"> | ||||||
| 			<div class=" flex flex-col w-full sm:flex-row sm:justify-center sm:space-x-6"> | 			<div class=" flex flex-col w-full sm:flex-row sm:justify-center sm:space-x-6"> | ||||||
| 				<form | 				<form | ||||||
|  | @ -111,28 +109,18 @@ | ||||||
| 
 | 
 | ||||||
| 							<div class="flex flex-1"> | 							<div class="flex flex-1"> | ||||||
| 								<div | 								<div | ||||||
| 									class="bg-gray-200 dark:bg-gray-600 font-bold px-3 py-1 border border-r-0 dark:border-gray-600 rounded-l-lg flex items-center" | 									class="bg-gray-200 dark:bg-gray-800 font-bold px-3 py-0.5 border border-r-0 dark:border-gray-800 rounded-l-xl flex items-center" | ||||||
| 								> | 								> | ||||||
| 									# | 									# | ||||||
| 								</div> | 								</div> | ||||||
| 								<input | 								<input | ||||||
| 									class="w-full rounded-r-lg py-2.5 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 disabled:text-gray-500 dark:disabled:text-gray-500 outline-none" | 									class="w-full rounded-r-xl py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 disabled:text-gray-500 dark:disabled:text-gray-500 outline-none" | ||||||
| 									type="text" | 									type="text" | ||||||
| 									bind:value={doc.name} | 									bind:value={doc.name} | ||||||
| 									autocomplete="off" | 									autocomplete="off" | ||||||
| 									required | 									required | ||||||
| 								/> | 								/> | ||||||
| 							</div> | 							</div> | ||||||
| 
 |  | ||||||
| 							<!-- <div class="flex-1"> |  | ||||||
| 								<input |  | ||||||
| 									class="w-full rounded py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 disabled:text-gray-500 dark:disabled:text-gray-500 outline-none" |  | ||||||
| 									type="text" |  | ||||||
| 									bind:value={doc.name} |  | ||||||
| 									autocomplete="off" |  | ||||||
| 									required |  | ||||||
| 								/> |  | ||||||
| 							</div> --> |  | ||||||
| 						</div> | 						</div> | ||||||
| 
 | 
 | ||||||
| 						<div class="flex flex-col w-full"> | 						<div class="flex flex-col w-full"> | ||||||
|  | @ -140,7 +128,7 @@ | ||||||
| 
 | 
 | ||||||
| 							<div class="flex-1"> | 							<div class="flex-1"> | ||||||
| 								<input | 								<input | ||||||
| 									class="w-full rounded-lg py-2.5 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none" | 									class="w-full rounded-xl py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none" | ||||||
| 									type="text" | 									type="text" | ||||||
| 									bind:value={doc.title} | 									bind:value={doc.title} | ||||||
| 									autocomplete="off" | 									autocomplete="off" | ||||||
|  | @ -150,7 +138,7 @@ | ||||||
| 						</div> | 						</div> | ||||||
| 
 | 
 | ||||||
| 						<div class="flex flex-col w-full"> | 						<div class="flex flex-col w-full"> | ||||||
| 							<div class=" mb-1.5 text-xs text-gray-500">{$i18n.t('Tags')}</div> | 							<div class=" mb-2 text-xs text-gray-500">{$i18n.t('Tags')}</div> | ||||||
| 
 | 
 | ||||||
| 							<Tags {tags} addTag={addTagHandler} deleteTag={deleteTagHandler} /> | 							<Tags {tags} addTag={addTagHandler} deleteTag={deleteTagHandler} /> | ||||||
| 						</div> | 						</div> | ||||||
|  |  | ||||||
|  | @ -12,7 +12,7 @@ | ||||||
| 
 | 
 | ||||||
| <Modal bind:show> | <Modal bind:show> | ||||||
| 	<div> | 	<div> | ||||||
| 		<div class=" flex justify-between dark:text-gray-300 px-5 py-4"> | 		<div class=" flex justify-between dark:text-gray-300 px-5 pt-4"> | ||||||
| 			<div class=" text-lg font-medium self-center">{$i18n.t('Document Settings')}</div> | 			<div class=" text-lg font-medium self-center">{$i18n.t('Document Settings')}</div> | ||||||
| 			<button | 			<button | ||||||
| 				class="self-center" | 				class="self-center" | ||||||
|  | @ -32,7 +32,6 @@ | ||||||
| 				</svg> | 				</svg> | ||||||
| 			</button> | 			</button> | ||||||
| 		</div> | 		</div> | ||||||
| 		<hr class=" dark:border-gray-800" /> |  | ||||||
| 
 | 
 | ||||||
| 		<div class="flex flex-col md:flex-row w-full p-4 md:space-x-4"> | 		<div class="flex flex-col md:flex-row w-full p-4 md:space-x-4"> | ||||||
| 			<div | 			<div | ||||||
|  |  | ||||||
|  | @ -42,7 +42,7 @@ | ||||||
| 
 | 
 | ||||||
| <Modal size="lg" bind:show> | <Modal size="lg" bind:show> | ||||||
| 	<div> | 	<div> | ||||||
| 		<div class=" flex justify-between dark:text-gray-300 px-5 py-4"> | 		<div class=" flex justify-between dark:text-gray-300 px-5 pt-4"> | ||||||
| 			<div class=" text-lg font-medium self-center">{$i18n.t('Archived Chats')}</div> | 			<div class=" text-lg font-medium self-center">{$i18n.t('Archived Chats')}</div> | ||||||
| 			<button | 			<button | ||||||
| 				class="self-center" | 				class="self-center" | ||||||
|  | @ -62,7 +62,6 @@ | ||||||
| 				</svg> | 				</svg> | ||||||
| 			</button> | 			</button> | ||||||
| 		</div> | 		</div> | ||||||
| 		<hr class=" dark:border-gray-850" /> |  | ||||||
| 
 | 
 | ||||||
| 		<div class="flex flex-col md:flex-row w-full px-5 py-4 md:space-x-4 dark:text-gray-200"> | 		<div class="flex flex-col md:flex-row w-full px-5 py-4 md:space-x-4 dark:text-gray-200"> | ||||||
| 			<div class=" flex flex-col w-full sm:flex-row sm:justify-center sm:space-x-6"> | 			<div class=" flex flex-col w-full sm:flex-row sm:justify-center sm:space-x-6"> | ||||||
|  |  | ||||||
|  | @ -18,6 +18,7 @@ | ||||||
| 	import ChatBubbles from '$lib/components/icons/ChatBubbles.svelte'; | 	import ChatBubbles from '$lib/components/icons/ChatBubbles.svelte'; | ||||||
| 	import Tooltip from '$lib/components/common/Tooltip.svelte'; | 	import Tooltip from '$lib/components/common/Tooltip.svelte'; | ||||||
| 	import UserChatsModal from '$lib/components/admin/UserChatsModal.svelte'; | 	import UserChatsModal from '$lib/components/admin/UserChatsModal.svelte'; | ||||||
|  | 	import AddUserModal from '$lib/components/admin/AddUserModal.svelte'; | ||||||
| 
 | 
 | ||||||
| 	const i18n = getContext('i18n'); | 	const i18n = getContext('i18n'); | ||||||
| 
 | 
 | ||||||
|  | @ -92,6 +93,12 @@ | ||||||
| 	/> | 	/> | ||||||
| {/key} | {/key} | ||||||
| 
 | 
 | ||||||
|  | <AddUserModal | ||||||
|  | 	bind:show={showAddUserModal} | ||||||
|  | 	on:save={async () => { | ||||||
|  | 		users = await getUsers(localStorage.token); | ||||||
|  | 	}} | ||||||
|  | /> | ||||||
| <UserChatsModal bind:show={showUserChatsModal} user={selectedUser} /> | <UserChatsModal bind:show={showUserChatsModal} user={selectedUser} /> | ||||||
| <SettingsModal bind:show={showSettingsModal} /> | <SettingsModal bind:show={showSettingsModal} /> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Timothy J. Baek
						Timothy J. Baek