Skip to content

Commit

Permalink
Update for 1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
dimitrov-adrian committed Dec 9, 2021
1 parent fd9a2fe commit bccab95
Show file tree
Hide file tree
Showing 8 changed files with 823 additions and 629 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
node_modules
dist
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
> ### This extension is in development and most probably will have file structure change when Directus 9 official releases. Meanwhile breaking changes are possible in anytime.
# WP Slug Interface

WordPress alike slug/permalink interface

![](https://raw.githubusercontent.com/dimitrov-adrian/directus-extension-wpslug-interface/main/screenshot.png)

## Installation

In your Directus installation root

```bash
npm install dimitrov-adrian/directus-extension-wpslug-interface
npm install directus-extension-wpslug-interface
```

Restart directus


## How to use

1. Create new standard field with String type
2. For interface select **Slug**

## FAQ

### Does this works when performing changes throught the API

No, this is just an interface. It works only on Directus App
10 changes: 0 additions & 10 deletions dist/index.js

This file was deleted.

1,150 changes: 686 additions & 464 deletions package-lock.json

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "directus-extension-wpslug-interface",
"version": "1.0.0-beta.3",
"version": "1.0.0",
"author": {
"email": "[email protected]",
"name": "Adrian Dimitrov"
Expand Down Expand Up @@ -28,11 +28,11 @@
"build": "directus-extension build"
},
"devDependencies": {
"@directus/extensions-sdk": "^9.0.0-rc.98",
"@directus/extensions-sdk": "^9.2.1",
"@sindresorhus/slugify": "^2.1.0",
"eslint-config-prettier": "8.3.0",
"eslint-plugin-prettier": "4.0.0",
"eslint-plugin-vue": "7.19.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.2.0",
"micromustache": "^8.0.3",
"prettier": "^2.4.1",
"stylelint-config-prettier": "^8.0.2",
Expand Down
99 changes: 93 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,100 @@
import { defineInterface } from '@directus/shared/utils';
import { InterfaceConfig } from '@directus/shared/types';
import InterfaceSlug from './slug.vue';
import Options from './options.vue';

export default defineInterface({
id: 'directus-extension-wpslug-interface',
export default {
id: 'extension-wpslug',
name: 'Slug',
description: 'WordPress alike slug/permalink interface',
icon: 'link',
component: InterfaceSlug,
types: ['string'],
options: Options,
});
group: 'standard',
options: ({ collection }) => {
return [
{
field: 'placeholder',
name: '$t:placeholder',
meta: {
width: 'full',
interface: 'input',
options: {
placeholder: '$t:enter_a_placeholder',
},
},
},
{
field: 'template',
type: 'string',
name: '$t:template',
meta: {
width: 'full',
interface: 'system-display-template',
required: true,
options: {
collectionName: collection,
font: 'monospace',
placeholder: '{{ title }}-{{ id }}',
},
},
},
{
field: 'iconLeft',
name: '$t:icon_left',
type: 'string',
meta: {
width: 'half',
interface: 'select-icon',
},
},
{
field: 'prefix',
type: 'string',
name: '$t:prefix',
meta: {
width: 'full',
interface: 'system-display-template',
required: true,
options: {
collectionName: collection,
font: 'monospace',
placeholder: 'http://example.com/',
},
},
},
{
field: 'suffix',
type: 'string',
name: '$t:suffix',
meta: {
width: 'full',
interface: 'system-display-template',
required: true,
options: {
collectionName: collection,
font: 'monospace',
placeholder: '/',
},
},
},
{
field: 'update',
name: '$t:update',
type: 'json',
meta: {
width: 'half',
interface: 'select-multiple-checkbox',
default_value: 'normal',
options: {
choices: [
{ text: '$t:on_create', value: 'create' },
{ text: '$t:on_update', value: 'update' },
],
},
},
schema: {
default_value: '[]',
},
},
];
},
} as InterfaceConfig;
127 changes: 0 additions & 127 deletions src/options.vue

This file was deleted.

43 changes: 30 additions & 13 deletions src/slug.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,21 @@
<div v-else class="link-preview-mode">
<v-icon v-if="iconLeft" :name="iconLeft" />

<a v-if="value && prefix" target="_blank" class="link" :href="finalLink">{{ finalLink }}</a>
<span v-else class="link" @click="!disabled && (isEditing = true)">{{ finalLink }}</span>
<a v-if="value && prefix" target="_blank" class="link" :href="presentedLink">{{ presentedLink }}</a>
<span v-else class="link" @click="!disabled && (isEditing = true)">{{ presentedLink }}</span>

<v-button v-if="!disabled" v-tooltip="t('edit')" x-small secondary icon @click="isEditing = true">
<v-icon name="edit" />
</v-button>

<v-button v-if="haveChange" v-tooltip="t('auto_generate')" x-small secondary icon @click="setByCurrentState">
<v-icon name="auto_fix_high" />
</v-button>
</div>
</template>

<script lang="ts">
import { defineComponent, ref, inject, watch, computed } from 'vue';
import { defineComponent, ref, inject, watch, computed, PropType } from 'vue';
import { render } from 'micromustache';
import slugify from '@sindresorhus/slugify';
import { useI18n } from 'vue-i18n';
Expand Down Expand Up @@ -87,7 +91,7 @@ export default defineComponent({
default: false,
},
update: {
type: Array,
type: Array as PropType<string[]>,
default: () => [],
},
},
Expand All @@ -98,6 +102,11 @@ export default defineComponent({
const isEditing = ref<Boolean>(props.autofocus);
const isTouched = ref<Boolean>(false);
const prefix = computed(() => render(props.prefix || '', values.value));
const suffix = computed(() => render(props.suffix || '', values.value));
const presentedLink = computed(() => `${prefix.value}${props.value || props.placeholder || ''}${suffix.value}`);
const haveChange = computed(() => props.value && transform(render(props.template, values.value)) !== props.value);
watch(values, (values: Record<string, any>) => {
// Reject manual touching.
if (isEditing.value || isTouched.value) return;
Expand All @@ -108,22 +117,17 @@ export default defineComponent({
// Avoid self update.
if (values[props.field] && values[props.field] !== props.value) return;
const newValue = transform(render(props.template, values));
if (newValue !== props.value) {
emit('input', newValue);
}
emitter(values);
});
const prefix = computed(() => render(props.prefix || '', values.value))
const suffix = computed(() => render(props.suffix || '', values.value))
const finalLink = computed(() => `${prefix.value}${props.value || props.placeholder || ''}${suffix.value}`)
return {
t,
suffix,
prefix,
finalLink,
presentedLink,
isEditing,
haveChange,
setByCurrentState,
onChange,
onKeyPress,
};
Expand All @@ -140,13 +144,26 @@ export default defineComponent({
function onChange(value: string) {
if (props.disabled) return;
if (props.value === value) return;
isTouched.value = Boolean(value && value.trim());
emit('input', transform(value || ''));
}
function transform(value: string) {
return slugify(value, { separator: '-', preserveTrailingDash: true }).slice(0, props.length);
}
function setByCurrentState() {
emitter(values.value);
}
function emitter(values: Record<string, any>) {
const newValue = transform(render(props.template, values));
if (newValue === props.value) return;
emit('input', newValue);
}
},
});
</script>
Expand Down

0 comments on commit bccab95

Please sign in to comment.