Skip to content

Commit

Permalink
feat: extensão de ícones
Browse files Browse the repository at this point in the history
  • Loading branch information
salomaosnff committed Dec 19, 2024
1 parent 35d6287 commit 7800e76
Show file tree
Hide file tree
Showing 20 changed files with 575 additions and 0 deletions.
24 changes: 24 additions & 0 deletions extensions/icons/frontend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
1 change: 1 addition & 0 deletions extensions/icons/frontend/.node-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v20.17.0
3 changes: 3 additions & 0 deletions extensions/icons/frontend/.vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"recommendations": ["Vue.volar"]
}
5 changes: 5 additions & 0 deletions extensions/icons/frontend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Vue 3 + TypeScript + Vite

This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.

Learn more about the recommended Project Setup and IDE Support in the [Vue Docs TypeScript Guide](https://vuejs.org/guide/typescript/overview.html#project-setup).
35 changes: 35 additions & 0 deletions extensions/icons/frontend/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Vue + TS</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html,body {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
background-color: #f0f0f0;
width: 100%;
height: 100%;
display: flex;

& > * {
flex: 1;
}
}
</style>
</head>
<body>
<div id="app">

</div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
24 changes: 24 additions & 0 deletions extensions/icons/frontend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "frontend",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"vue": "^3.5.12",
"@mdi/js": "7.4.47"
},
"devDependencies": {
"@lenz-design/types": "workspace:*",
"@lenz-design/vite-plugin": "workspace:*",
"@vitejs/plugin-vue": "^5.1.2",
"typescript": "^5.6.3",
"unocss": "^0.63.4",
"vite": "^5.4.8",
"vue-tsc": "^2.0.29"
}
}
1 change: 1 addition & 0 deletions extensions/icons/frontend/public/vite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
112 changes: 112 additions & 0 deletions extensions/icons/frontend/src/App.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<script setup lang="ts">
import * as allIcons from "@mdi/js";
import { computed, onBeforeUnmount, ref, watch } from "vue";
import * as LenzReactivity from "lenz:reactivity";
import CssNumberInput from "./components/CssNumberInput.vue";
const props = defineProps<{
onInsert(icon: string): void;
}>();
const icons = Object.entries(allIcons).map(([name, path]) => ({
// Unprefix the icon name and remove pascal case
name: name
.replace("mdi", "")
.replace(/([A-Z])/g, " $1")
.trim()
.toLowerCase(),
path,
}));
const search = ref("");
const filteredIcons = computed(() => {
if (!search.value) return icons;
return new Set(
icons.filter((icon) =>
icon.name.toLowerCase().includes(search.value.toLowerCase())
)
);
});
const selectedIcon = ref<{
name: string;
path: string;
}>();
const code = computed(() => {
return (
selectedIcon.value &&
[
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" width="1.2em" height="1.2em">',
` <path d="${selectedIcon.value?.path}" />`,
"</svg>",
].join("\n")
);
});
</script>

<template>
<div class="flex" style="height: 100%; width: 100%">
<form @submit.prevent class="widget-icons-form flex-1">
<fieldset>
<legend>Material Design Icons</legend>
<label>
<p>Pesquisar</p>
<input
type="text"
v-model="search"
name="font-family"
placeholder="Ex: home"
/>
</label>
<div class="icon-list">
<ul class="icons-widget-icon-grid">
<li
v-for="icon in filteredIcons"
:key="icon.name"
@click="selectedIcon = icon"
:class="{ selected: icon === selectedIcon }"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
width="40px"
height="40px"
>
<path :d="icon.path" />
</svg>

<p>{{ icon.name }}</p>
</li>
</ul>
</div>
</fieldset>
</form>
<div class="preview" style="padding: 14px">
<fieldset>
<legend>Código SVG</legend>
<pre>{{ code }}</pre>
</fieldset>
<p>
Aprenda mais sobre SVG em
<a
href="https://developer.mozilla.org/pt-BR/docs/Web/SVG"
target="_blank"
>MDN Web Docs</a
>
</p>

<button
v-if="selectedIcon"
@click.prevent="onInsert(selectedIcon.path)"
style="float: right; margin-top: 1rem"
>
Inserir
</button>
</div>
</div>
</template>
53 changes: 53 additions & 0 deletions extensions/icons/frontend/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import "./style.scss";

import { LenzDisposer } from "lenz:types";
import { createApp } from "vue";

import App from "./App.vue";

if (import.meta.env.DEV) {
const app = createApp(App, {
onInsert(d: string) {
console.log("insert", d);
},
});

app.mount(document.body);
}

let countInjects = 0;

const link = document.createElement("link");

const styleUrl = import.meta.url.replace(/[^/]+$/g, "style.css");

link.rel = "stylesheet";
link.href = styleUrl;
link.id = "widget-layout-style";

function injectStyle(): LenzDisposer {
if (countInjects++ === 0) {
document.head.appendChild(link);
}

return () => {
if (--countInjects === 0) {
link.remove();
}
};
}

export default function (parent: HTMLElement, data: any) {
const app = createApp(App, {
onInsert: data.onInsert,
});

const disposeStyle = injectStyle();

app.mount(parent);

return () => {
app.unmount();
disposeStyle();
};
}
111 changes: 111 additions & 0 deletions extensions/icons/frontend/src/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
.flex {
display: flex;
}
.flex-1 {
flex: 1;
}
.preview {
display: flex;
flex-direction: column;

& pre {
width: 280px;
height: 100%;
font-size: 12px;
word-break: normal;
white-space: pre-wrap;
overflow: auto;
padding: 8px;
max-height: 90%;
flex: 1;
}

& fieldset {
flex: 1;
overflow: hidden;
}

& > p {
margin-top: 1rem;
}
}
.widget-icons-form {
padding: 1rem;
gap: 1rem;

& summary {
cursor: pointer;
}

& .full-width {
min-width: 100%;
flex: 1;
}

& .flex {
display: flex;
gap: 1rem;
flex-wrap: wrap;
min-width: 270px;

& > * {
flex-basis: 128px;
flex-grow: 1;
}
}

& label {
display: block;
width: 100%;
}

& input,
& select {
width: 100%;
}

& pre {
overflow: auto;
}

& > fieldset {
height: 100%;
display: flex;
flex-direction: column;
}

& .m-0 {
margin: 0;
}

& .icon-list {
overflow-y: auto;
flex: 1;
}

& .icons-widget-icon-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
gap: 1rem;
list-style: none;
text-align: center;
gap: 2px;
padding: 0;

& > * {
padding: 4px;
overflow: hidden;
font-size: 12px;
cursor: pointer;

&:hover {
background: #0001;
}

& > svg {
display: block;
margin: 0 auto;
}
}
}
}
1 change: 1 addition & 0 deletions extensions/icons/frontend/src/vite-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="vite/client" />
Loading

0 comments on commit 7800e76

Please sign in to comment.