Skip to content
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
2 changes: 2 additions & 0 deletions components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ declare module '@vue/runtime-core' {
DockerRunToDockerComposeConverter: typeof import('./src/tools/docker-run-to-docker-compose-converter/docker-run-to-docker-compose-converter.vue')['default']
DynamicValues: typeof import('./src/tools/benchmark-builder/dynamic-values.vue')['default']
Editor: typeof import('./src/tools/html-wysiwyg-editor/editor/editor.vue')['default']
EmojiCard: typeof import('./src/tools/emoji-picker/emoji-card.vue')['default']
EmojiPicker: typeof import('./src/tools/emoji-picker/emoji-picker.vue')['default']
Encryption: typeof import('./src/tools/encryption/encryption.vue')['default']
EtaCalculator: typeof import('./src/tools/eta-calculator/eta-calculator.vue')['default']
FavoriteButton: typeof import('./src/components/FavoriteButton.vue')['default']
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"cronstrue": "^2.26.0",
"crypto-js": "^4.1.1",
"date-fns": "^2.29.3",
"emojilib": "^3.0.10",
"figue": "^1.2.0",
"fuse.js": "^6.6.2",
"highlight.js": "^11.7.0",
Expand All @@ -74,6 +75,7 @@
"sql-formatter": "^8.2.0",
"ts-pattern": "^4.2.2",
"ua-parser-js": "^1.0.35",
"unicode-emoji-json": "^0.4.0",
"unplugin-auto-import": "^0.16.4",
"uuid": "^8.3.2",
"vue": "^3.3.4",
Expand Down
21 changes: 21 additions & 0 deletions pnpm-lock.yaml

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

8 changes: 4 additions & 4 deletions src/composable/copy.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { type MaybeRef, get, useClipboard } from '@vueuse/core';
import { useMessage } from 'naive-ui';

export function useCopy({ source, text = 'Copied to the clipboard' }: { source: MaybeRef<unknown>; text?: string }) {
const { copy } = useClipboard({ source: computed(() => String(get(source))) });
export function useCopy({ source, text = 'Copied to the clipboard' }: { source?: MaybeRef<unknown>; text?: string } = {}) {
const { copy } = useClipboard(source ? { source: computed(() => String(get(source))) } : {});
const message = useMessage();

return {
async copy() {
async copy(content?: string, { notificationMessage }: { notificationMessage?: string } = {}) {
await copy();
message.success(text);
message.success(notificationMessage ?? text);
},
};
}
42 changes: 42 additions & 0 deletions src/tools/emoji-picker/emoji-card.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<script setup lang="ts">
import type { EmojiInfo } from './emoji.types';
import { useCopy } from '@/composable/copy';

const props = (defineProps<{ emojiInfo: EmojiInfo }>());
const { emojiInfo } = toRefs(props);

const { copy } = useCopy();
</script>

<template>
<c-card flex items-center gap-3 important:py-8px important:pl-10px important:pr-5px>
<div cursor-pointer text-30px @click="copy(emojiInfo.emoji, { notificationMessage: `Emoji ${emojiInfo.emoji} copied to the clipboard` })">
{{ emojiInfo.emoji }}
</div>

<div min-w-0 flex-1>
<div truncate font-bold>
{{ emojiInfo.title }}
</div>

<!-- <div>
<c-link>
{{ emojiInfo.codePoints }}
</c-link>
</div>
<div />
<div rounded op-70>
Unicode: <span border="1px solid current op-30" b-rd-xl px-12px py-4px>{{ emojiInfo.unicode }}</span>
</div> -->

<div flex gap-2 font-mono text-xs op-70>
<span cursor-pointer transition hover:text-primary @click="copy(emojiInfo.codePoints, { notificationMessage: `Code points '${emojiInfo.codePoints}' copied to the clipboard` })">
{{ emojiInfo.codePoints }}
</span>
<span cursor-pointer truncate transition hover:text-primary @click="copy(emojiInfo.unicode, { notificationMessage: `Unicode '${emojiInfo.unicode}' copied to the clipboard` })">
{{ emojiInfo.unicode }}
</span>
</div>
</div>
</c-card>
</template>
96 changes: 96 additions & 0 deletions src/tools/emoji-picker/emoji-picker.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<script setup lang="ts">
import emojiUnicodeData from 'unicode-emoji-json';
import emojiKeywords from 'emojilib';
import _ from 'lodash';
import type { EmojiInfo } from './emoji.types';
import { useFuzzySearch } from '@/composable/fuzzySearch';

const escapeUnicode = ({ emoji }: { emoji: string }) => emoji.split('').map(unit => `\\u${unit.charCodeAt(0).toString(16).padStart(4, '0')}`).join('');
const getEmojiCodePoints = ({ emoji }: { emoji: string }) => emoji.codePointAt(0) ? `0x${emoji.codePointAt(0)?.toString(16)}` : undefined;

const emojis = _.map(emojiUnicodeData, (emojiInfo, emoji) => ({
...emojiInfo,
emoji,
title: _.capitalize(emojiInfo.name),
keywords: emojiKeywords[emoji as keyof typeof emojiKeywords],
codePoints: getEmojiCodePoints({ emoji }),
unicode: escapeUnicode({ emoji }),
}));

const emojisGroups: { emojiInfos: EmojiInfo[]; group: string }[] = _
.chain(emojis)
.groupBy('group')
.map((emojiInfos, group) => ({ group, emojiInfos }))
.value();

const searchQuery = ref('');

const { searchResult } = useFuzzySearch({
search: searchQuery,
data: emojis,
options: {
keys: ['group', { name: 'name', weight: 3 }, 'keywords', 'unicode', 'codePoints', 'emoji'],
threshold: 0.3,
useExtendedSearch: true,
isCaseSensitive: false,
},
});
</script>

<template>
<div mx-auto max-w-2400px important:flex-1>
<div flex items-center gap-3>
<c-input-text
v-model:value="searchQuery"
placeholder="Search emojis (e.g. 'smile')..."
mx-auto max-w-600px
>
<template #prefix>
<icon-mdi-search mr-6px color-black op-70 dark:color-white />
</template>
</c-input-text>
</div>

<div v-if="searchQuery">
<div
v-if="searchResult.length === 0"
mt-4
text-20px
font-bold
>
No results
</div>

<div v-else>
<div mt-4 text-20px font-bold>
Search result
</div>

<div grid grid-cols-6 gap-2>
<emoji-card
v-for="emojiInfo in searchResult"
:key="emojiInfo.name"
:emoji-info="emojiInfo"
flex
items-center
gap-3
/>
</div>
</div>
</div>

<div
v-for="{ group, emojiInfos } in emojisGroups"
v-else
:key="group"
>
<div mt-4 text-20px font-bold>
{{ group }}
</div>

<div grid grid-cols-1 gap-2 lg:grid-cols-4 md:grid-cols-3 sm:grid-cols-2 xl:grid-cols-6>
<emoji-card v-for="emojiInfo in emojiInfos" :key="emojiInfo.name" :emoji-info="emojiInfo" flex items-center gap-3 />
</div>
</div>
</div>
</template>
8 changes: 8 additions & 0 deletions src/tools/emoji-picker/emoji.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type emojiUnicodeData from 'unicode-emoji-json';

export type EmojiInfo = {
title: string
emoji: string
codePoints: string | undefined
unicode: string
} & typeof emojiUnicodeData['\uD83E\uDD10'];
12 changes: 12 additions & 0 deletions src/tools/emoji-picker/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { MoodSmile } from '@vicons/tabler';
import { defineTool } from '../tool';

export const tool = defineTool({
name: 'Emoji picker',
path: '/emoji-picker',
description: 'Copy and paste emojis easily and get the unicode and code points value of each emoji.',
keywords: ['emoji', 'picker', 'unicode', 'copy', 'paste'],
component: () => import('./emoji-picker.vue'),
icon: MoodSmile,
createdAt: new Date('2023-08-07'),
});
3 changes: 2 additions & 1 deletion src/tools/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { tool as base64FileConverter } from './base64-file-converter';
import { tool as base64StringConverter } from './base64-string-converter';
import { tool as basicAuthGenerator } from './basic-auth-generator';
import { tool as emojiPicker } from './emoji-picker';
import { tool as passwordStrengthAnalyser } from './password-strength-analyser';
import { tool as yamlToToml } from './yaml-to-toml';
import { tool as jsonToToml } from './json-to-toml';
Expand Down Expand Up @@ -144,7 +145,7 @@ export const toolsByCategory: ToolCategory[] = [
},
{
name: 'Text',
components: [loremIpsumGenerator, textStatistics],
components: [loremIpsumGenerator, textStatistics, emojiPicker],
},
{
name: 'Data',
Expand Down
2 changes: 1 addition & 1 deletion src/tools/json-diff/diff-viewer/diff-viewer.models.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ function Value({ value, status }: { value: unknown; status: string }) {
const { copy } = useCopy({ source: formatedValue });

return (
<span class={['value', status]} onClick={copy}>
<span class={['value', status]} onClick={() => copy()}>
{formatedValue}
</span>
);
Expand Down