Improve Templates (#183)

* Improve Templates

* Fix test case

* Update AI GenerateTemplate

* update openai client and GPT completer

* composer.lock

* Update types and list json with script

* Template changes

* fix on draft template

* Finish opnform templates

---------

Co-authored-by: Forms Dev <chirag+new@notionforms.io>
Co-authored-by: Julien Nahum <julien@nahum.net>
This commit is contained in:
Chirag Chhatrala 2023-09-08 16:30:28 +05:30 committed by GitHub
parent d93eca7410
commit 8e47b49e9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 3130 additions and 1381 deletions

View File

@ -24,8 +24,12 @@ class GenerateTemplate extends Command
*/
protected $description = 'Generates a new form template from a prompt';
const MAX_RELATED_TEMPLATES = 8;
const FORM_STRUCTURE_PROMPT = <<<EOD
I created a form builder. Forms are represented as Json objects. Here's an example form:
You are an AI assistant for OpnForm, a form builder and your job is to build a form for our user.
Forms are represented as Json objects. Here's an example form:
```json
{
"title": "Contact Us",
@ -35,50 +39,40 @@ class GenerateTemplate extends Command
"name": "What's your name?",
"type": "text",
"hidden": false,
"prefill": null,
"required": true,
"placeholder": null
"placeholder": "Steve Jobs"
},
{
"help": null,
"help": "We will never share your email with anyone else.",
"name": "Email",
"type": "email",
"hidden": false,
"prefill": null,
"required": true,
"placeholder": null
"placeholder": "steve@apple.com"
},
{
"help": null,
"name": "How would you rate your overall experience?",
"type": "select",
"hidden": false,
"select": {
"options": [
{
"id": "Below Average",
"name": "Below Average"
},
{
"id": "Average",
"name": "Average"
},
{
"id": "Above Average",
"name": "Above Average"
}
]
},
"prefill": null,
"required": true,
"placeholder": null,
},
"help": null,
"name": "How would you rate your overall experience?",
"type": "select",
"hidden": false,
"select": {
"options": [
{"name": 1, "value": 1},
{"name": 2, "value": 2},
{"name": 3, "value": 3},
{"name": 4, "value": 4},
{"name": 5, "value": 5}
]
},
"prefill": 5,
"required": true,
"placeholder": null
},
{
"help": null,
"name": "Subject",
"type": "text",
"hidden": false,
"prefill": null,
"required": true,
"placeholder": null
},
@ -87,22 +81,19 @@ class GenerateTemplate extends Command
"name": "How can we help?",
"type": "text",
"hidden": false,
"prefill": null,
"required": true,
"multi_lines": true,
"placeholder": null,
"generates_uuid": false,
"max_char_limit": "2000",
"hide_field_name": false,
"show_char_limit": false,
"generates_auto_increment_id": false
"show_char_limit": false
},
{
"help": null,
"help": "Upload any relevant files here.",
"name": "Have any attachments?",
"type": "files",
"hidden": false,
"prefill": null,
"placeholder": null
}
],
@ -114,23 +105,34 @@ class GenerateTemplate extends Command
"uppercase_labels": false,
"submit_button_text": "Submit",
"re_fill_button_text": "Fill Again",
"color": "#3B82F6"
"color": "#64748b"
}
```
The form properties can have one of the following types: 'text', 'number', 'select', 'multi_select', 'date', 'files', 'checkbox', 'url', 'email', 'phone_number'.
The form properties can only have one of the following types: 'text', 'number', 'select', 'multi_select', 'date', 'files', 'checkbox', 'url', 'email', 'phone_number', 'signature'.
All form properties objects need to have the keys 'help', 'name', 'type', 'hidden', 'placeholder', 'prefill'.
The placeholder property is optional (can be "null") and is used to display a placeholder text in the input field.
The help property is optional (can be "null") and is used to display extra information about the field.
For the type "select" and "multi_select", the input object must have a key "select" (or "multi_select") that's mapped to an object like this one:
```json
{
"options": [
{"id":"Option 1","name":"Option 1"},
{"id":"Pption 2","name":"Option 2"}
{"name": 1, "value": 1},
{"name": 2, "value": 2},
{"name": 3, "value": 3},
{"name": 4, "value": 4}
]
}
```
For the type "number" you can set the property "is_rating" to "true" to turn it into a star rating input.
For numerical rating inputs, use a "number" type input and set the property "is_rating" to "true" to turn it into a star rating input. Ex:
```json
{
"name":"How would you rate your overall experience?",
"type":"number",
"is_rating": true
}
```
If the form is too long, you can paginate it by adding a page break block in the list of properties:
```json
@ -142,24 +144,70 @@ class GenerateTemplate extends Command
}
```
Give me the JSON code only, for the following form: "[REPLACE]"
Do not ask me for more information about required properties or types, suggest me a form structure instead.
If you need to add more context to the form, you can add text blocks:
```json
{
"name":"My Text",
"type":"nf-text",
"content": "<p>This is a text block.</p>"
}
```
Give me the valid JSON object only, representing the following form: "[REPLACE]"
Do not ask me for more information about required properties or types, only suggest me a form structure.
EOD;
const FORM_DESCRIPTION_PROMPT = <<<EOD
I own a form builder online named OpnForm. It's free to use. Give me a description for a template page for the following form: [REPLACE]. Explain what the form is about, and that it takes seconds to duplicate the template to create your own version it and to start getting some submissions.
You are an AI assistant for OpnForm, a form builder and your job is to help us build form templates for our users.
Give me some valid html code (using only h2, p, ul, li html tags) for the following form template page: "[REPLACE]".
The html code should have the following structure:
- A paragraph explaining what the template is about
- A paragraph explaining why and when to use such a form
- A paragraph explaining who is the target audience and why it's a great idea to build this form
- A paragraph explaining that OpnForm is the best tool to build this form. They can duplicate this template in a few seconds, and integrate with many other tools through our webhook or zapier integration.
Each paragraph (except for the first one) MUST start with with a h2 tag containing a title for this paragraph.
EOD;
const FORM_SHORT_DESCRIPTION_PROMPT = <<<EOD
I own a form builder online named OpnForm. It's free to use.
Give me a 1 sentence description for the following form template page: "[REPLACE]". It should be short and concise, but still explain what the form is about.
EOD;
const FORM_INDUSTRY_PROMPT = <<<EOD
You are an AI assistant for OpnForm, a form builder and your job is to help us build form templates for our users.
I am creating a form template: "[REPLACE]". You must assign the template to industries. Return a list of industries (minimum 1, maximum 3 but only if very relevant) and order them by relevance (most relevant first).
Here are the only industries you can choose from: [INDUSTRIES]
Do no make up any new type, only use the ones listed above.
Reply only with a valid JSON, being an array of string. Order assigned industries from the most relevant to the less relevant.
Ex: ["banking_forms","customer_service_forms"]
EOD;
const FORM_TYPES_PROMPT = <<<EOD
You are an AI assistant for OpnForm, a form builder and your job is to help us build form templates for our users.
I am creating a form template: "[REPLACE]". You must assign the template to one or more types. Return a list of types (minimum 1, maximum 3 but only if very accurate) and order them by relevance (most relevant first).
Here are the only types you can choose from: [TYPES]
Do no make up any new type, only use the ones listed above.
Reply only with a valid JSON, being an array of string. Order assigned types from the most relevant to the less relevant.
Ex: ["consent_forms","award_forms"]
EOD;
const FORM_QAS_PROMPT = <<<EOD
Now give me 3 to 5 question and answers to put on the form template page. The questions should be about the reasons for this template (when to use, why, target audience, goal etc.) and OpnForm's usage. Reply only with a valid JSON, being an array of object containing the keys "question" and "answer".
Now give me 4 to 6 question and answers to put on the form template page. The questions should be about the reasons for this template (when to use, why, target audience, goal etc.).
The questions should also explain why OpnForm is the best option to create this form (open-source, free to use, integrations etc).
Reply only with a valid JSON, being an array of object containing the keys "question" and "answer".
EOD;
const FORM_TITLE_PROMPT = <<<EOD
Finally give me a title for the template. It should be short and to the point, without any quotes.
Finally give me a title for the template. It must contain or end with "template". It should be short and to the point, without any quotes.
EOD;
const FORM_IMG_KEYWORDS_PROMPT = <<<EOD
I want to add an image to illustrate this form template page. Give me a releveant search query for unsplash. Reply only with a valid JSON like this:
I want to add an image to illustrate this form template page. Give me a relevant search query for unsplash. Reply only with a valid JSON like this:
```json
{
"search_query": ""
@ -174,19 +222,42 @@ class GenerateTemplate extends Command
*/
public function handle()
{
// Get form structture
// Get form structure
$completer = (new GptCompleter(config('services.openai.api_key')))
->setSystemMessage('You are a robot helping to generate forms.');
->setAiModel('gpt-3.5-turbo-16k')
->useStreaming()
->setSystemMessage('You are an assistant helping to generate forms.');
$completer->completeChat([
["role" => "user", "content" => Str::of(self::FORM_STRUCTURE_PROMPT)->replace('[REPLACE]', $this->argument('prompt'))->toString()]
], 3000);
], 6000);
$formData = $completer->getArray();
// Now get description and QAs
$formDescriptionPrompt = Str::of(self::FORM_DESCRIPTION_PROMPT)->replace('[REPLACE]', $this->argument('prompt'))->toString();
$formShortDescription = $completer->completeChat([
["role" => "user", "content" => Str::of(self::FORM_SHORT_DESCRIPTION_PROMPT)->replace('[REPLACE]', $this->argument('prompt'))->toString()]
])->getString();
// If description is between quotes, remove quotes
$formShortDescription = Str::of($formShortDescription)->replaceMatches('/^"(.*)"$/', '$1')->toString();
// Get industry & types
$industry = $this->getIndustries($completer, $this->argument('prompt'));
$types = $this->getTypes($completer, $this->argument('prompt'));
// Get Related Templates
$relatedTemplates = $this->getRelatedTemplates($industry, $types);
// Now get description and QAs
$formDescription = $completer->completeChat([
["role" => "user", "content" => $formDescriptionPrompt]
])->getString();
])->getHtml();
$formCoverKeywords = $completer->completeChat([
["role" => "user", "content" => $formDescriptionPrompt],
["role" => "assistant", "content" => $formDescription],
["role" => "user", "content" => self::FORM_IMG_KEYWORDS_PROMPT]
])->getArray();
$imageUrl = $this->getImageCoverUrl($formCoverKeywords['search_query']);
$formQAs = $completer->completeChat([
["role" => "user", "content" => $formDescriptionPrompt],
["role" => "assistant", "content" => $formDescription],
@ -198,16 +269,22 @@ class GenerateTemplate extends Command
["role" => "user", "content" => self::FORM_TITLE_PROMPT]
])->getString();
// Finally get keyworks for image cover
$formCoverKeyworks = $completer->completeChat([
["role" => "user", "content" => $formDescriptionPrompt],
["role" => "assistant", "content" => $formDescription],
["role" => "user", "content" => self::FORM_IMG_KEYWORDS_PROMPT]
])->getArray();
$imageUrl = $this->getImageCoverUrl($formCoverKeyworks['search_query']);
$template = $this->createFormTemplate($formData, $formTitle, $formDescription, $formQAs, $imageUrl);
$this->info('/templates/' . $template->slug);
$template = $this->createFormTemplate(
$formData,
$formTitle,
$formDescription,
$formShortDescription,
$formQAs,
$imageUrl,
$industry,
$types,
$relatedTemplates
);
$this->info('/form-templates/' . $template->slug);
// Set reverse related Templates
$this->setReverseRelatedTemplates($template);
return Command::SUCCESS;
}
@ -217,19 +294,81 @@ class GenerateTemplate extends Command
*/
private function getImageCoverUrl($searchQuery): ?string
{
$url = 'https://api.unsplash.com/search/photos?query=' . urlencode($searchQuery) . '&client_id=' . config('services.unslash.access_key');
$url = 'https://api.unsplash.com/search/photos?query=' . urlencode($searchQuery) . '&client_id=' . config('services.unsplash.access_key');
$response = Http::get($url)->json();
if (isset($response['results'][0]['urls']['regular'])) {
return $response['results'][0]['urls']['regular'];
$photoIndex = rand(0, max(count($response['results']) - 1, 10));
if (isset($response['results'][$photoIndex]['urls']['regular'])) {
return Str::of($response['results'][$photoIndex]['urls']['regular'])->replace('w=1080', 'w=600')->toString();
}
return null;
}
private function createFormTemplate(array $formData, string $formTitle, string $formDescription, array $formQAs, ?string $imageUrl)
private function getIndustries(GptCompleter $completer, string $formPrompt): array
{
// Add property uuids
$industriesString = Template::getAllIndustries()->pluck('slug')->join(', ');
return $completer->completeChat([
["role" => "user", "content" => Str::of(self::FORM_INDUSTRY_PROMPT)
->replace('[REPLACE]', $formPrompt)
->replace('[INDUSTRIES]', $industriesString)
->toString()]
])->getArray();
}
private function getTypes(GptCompleter $completer, string $formPrompt): array
{
$typesString = Template::getAllTypes()->pluck('slug')->join(', ');
return $completer->completeChat([
["role" => "user", "content" => Str::of(self::FORM_TYPES_PROMPT)
->replace('[REPLACE]', $formPrompt)
->replace('[TYPES]', $typesString)
->toString()]
])->getArray();
}
private function getRelatedTemplates(array $industries, array $types): array
{
$templateScore = [];
Template::chunk(100, function ($otherTemplates) use ($industries, $types, &$templateScore) {
foreach ($otherTemplates as $otherTemplate) {
$industryOverlap = count(array_intersect($industries ?? [], $otherTemplate->industry ?? []));
$typeOverlap = count(array_intersect($types ?? [], $otherTemplate->types ?? []));
$score = $industryOverlap + $typeOverlap;
if ($score > 1) {
$templateScore[$otherTemplate->slug] = $score;
}
}
});
arsort($templateScore); // Sort by Score
return array_slice(array_keys($templateScore), 0, self::MAX_RELATED_TEMPLATES);
}
private function createFormTemplate(
array $formData,
string $formTitle,
string $formDescription,
string $formShortDescription,
array $formQAs,
?string $imageUrl,
array $industry,
array $types,
array $relatedTemplates
)
{
// Add property uuids, improve form with options
foreach ($formData['properties'] as &$property) {
$property['id'] = Str::uuid()->toString();
$property['id'] = Str::uuid()->toString(); // Column ID
// Fix ratings
if ($property['type'] == 'number' && ($property['is_rating'] ?? false)) {
$property['rating_max_value'] = 5;
}
if (($property['type'] == 'select' && count($property['select']['options']) <= 4)
|| ($property['type'] == 'multi_select' && count($property['multi_select']['options']) <= 4)) {
$property['without_dropdown'] = true;
}
}
// Clean data
@ -238,9 +377,26 @@ class GenerateTemplate extends Command
return Template::create([
'name' => $formTitle,
'description' => $formDescription,
'short_description' => $formShortDescription,
'questions' => $formQAs,
'structure' => $formData,
'image_url' => $imageUrl,
'publicly_listed' => true,
'industries' => $industry,
'types' => $types,
'related_templates' => $relatedTemplates
]);
}
private function setReverseRelatedTemplates(Template $newTemplate)
{
if (!$newTemplate || count($newTemplate->related_templates) === 0) return;
$templates = Template::whereIn('slug', $newTemplate->related_templates)->get();
foreach ($templates as $template) {
if (count($template->related_templates) < self::MAX_RELATED_TEMPLATES) {
$template->update(['related_templates' => array_merge($template->related_templates, [$newTemplate->slug])]);
}
}
}
}

View File

@ -2,7 +2,6 @@
namespace App\Http\Controllers\Forms;
use App\Console\Commands\GenerateTemplate;
use App\Http\Controllers\Controller;
use App\Http\Requests\AiGenerateFormRequest;
use App\Models\Forms\AI\AiFormCompletion;

View File

@ -42,9 +42,9 @@ class SitemapController extends Controller
private function addTemplatesUrls(Sitemap $sitemap)
{
Template::chunk(100, function ($templates) use ($sitemap) {
Template::where('publicly_listed', true)->chunk(100, function ($templates) use ($sitemap) {
foreach ($templates as $template) {
$sitemap->add($this->createUrl('/templates/' . $template->slug, 0.7));
$sitemap->add($this->createUrl('/form-templates/' . $template->slug, 0.8));
}
});
}

View File

@ -3,19 +3,28 @@
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Http\Requests\Templates\CreateTemplateRequest;
use App\Http\Resources\TemplateResource;
use Illuminate\Http\Request;
use App\Http\Requests\Templates\FormTemplateRequest;
use App\Http\Resources\FormTemplateResource;
use App\Models\Template;
use Illuminate\Http\Request;
class TemplateController extends Controller
{
public function index()
public function index(Request $request)
{
return TemplateResource::collection(Template::all());
$limit = null;
if ($request->offsetExists('limit') && $request->get('limit') > 0) {
$limit = (int) $request->get('limit');
}
return FormTemplateResource::collection(
Template::where('publicly_listed', true)
->orderByDesc('created_at')
->limit($limit)
->get()
);
}
public function create(CreateTemplateRequest $request)
public function create(FormTemplateRequest $request)
{
$this->authorize('create', Template::class);
@ -24,8 +33,41 @@ class TemplateController extends Controller
$template->save();
return $this->success([
'message' => 'Template created.',
'message' => 'Template was created.',
'template_id' => $template->id
]);
}
public function update(FormTemplateRequest $request, string $id)
{
$template = Template::findOrFail($id);
$this->authorize('update', $template);
$template->update($request->all());
return $this->success([
'message' => 'Template was updated.',
'template_id' => $template->id,
'data' => new FormTemplateResource($template)
]);
}
public function destroy($id)
{
$template = Template::findOrFail($id);
$this->authorize('delete', $template);
$template->delete();
return $this->success([
'message' => 'Template was deleted.',
]);
}
public function show(string $slug)
{
return new FormTemplateResource(
Template::whereSlug($slug)->firstOrFail()
);
}
}

View File

@ -5,7 +5,7 @@ namespace App\Http\Requests\Templates;
use App\Models\Template;
use Illuminate\Foundation\Http\FormRequest;
class CreateTemplateRequest extends FormRequest
class FormTemplateRequest extends FormRequest
{
const IGNORED_KEYS = [
'id',
@ -48,12 +48,21 @@ class CreateTemplateRequest extends FormRequest
*/
public function rules()
{
$slugRule = '';
if($this->id){
$slugRule = ','.$this->id;
}
return [
'form' => 'required|array',
'publicly_listed' => 'boolean',
'name' => 'required|string|max:60',
'slug' => 'required|string|unique:templates',
'slug' => 'required|string|alpha_dash|unique:templates,slug'.$slugRule,
'short_description' => 'required|string|max:1000',
'description' => 'required|string|max:2000',
'image_url' => 'required|string',
'types' => 'nullable|array',
'industries' => 'nullable|array',
'related_templates' => 'nullable|array',
'questions' => 'array',
];
}
@ -66,12 +75,18 @@ class CreateTemplateRequest extends FormRequest
unset($structure[$key]);
}
}
return new Template([
'publicly_listed' => $this->publicly_listed,
'name' => $this->name,
'slug' => $this->slug,
'short_description' => $this->short_description,
'description' => $this->description,
'image_url' => $this->image_url,
'structure' => $structure,
'types' => $this->types ?? [],
'industries' => $this->industries ?? [],
'related_templates' => $this->related_templates ?? [],
'questions' => $this->questions ?? []
]);
}

View File

@ -2,10 +2,9 @@
namespace App\Http\Resources;
use App\Http\Requests\Templates\CreateTemplateRequest;
use Illuminate\Http\Resources\Json\JsonResource;
class TemplateResource extends JsonResource
class FormTemplateResource extends JsonResource
{
/**
* Transform the resource into an array.
@ -15,10 +14,8 @@ class TemplateResource extends JsonResource
*/
public function toArray($request)
{
$data = parent::toArray($request);
foreach (CreateTemplateRequest::IGNORED_KEYS as $key) {
unset($data[$key]);
}
return $data;
return array_merge(parent::toArray($request), [
'is_new' => $this->created_at->isAfter(now()->subDays(7))
]);
}
}

View File

@ -4,6 +4,7 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Spatie\Sluggable\HasSlug;
use Spatie\Sluggable\SlugOptions;
use Stevebauman\Purify\Facades\Purify;
@ -16,14 +17,28 @@ class Template extends Model
'name',
'slug',
'description',
'short_description',
'image_url',
'structure',
'questions',
'publicly_listed',
'industries',
'types',
'related_templates'
];
protected $casts = [
'structure' => 'array',
'questions' => 'array',
'industries' => 'array',
'types' => 'array',
'related_templates' => 'array',
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
protected $attributes = [
'publicly_listed' => false,
];
public function setDescriptionAttribute($value)
@ -32,6 +47,11 @@ class Template extends Model
$this->attributes['description'] = Purify::clean($value);
}
public function scopePubliclyListed($query)
{
return $this->where('publicly_listed', true);
}
/**
* Config/options
*/
@ -42,4 +62,40 @@ class Template extends Model
->generateSlugsFrom('name')
->saveSlugsTo('slug');
}
public function getTypes(): Collection
{
return self::getAllTypes()->filter(function ($type) {
return in_array($type['slug'], $this->types);
});
}
public function getIndustries(): Collection
{
return self::getAllIndustries()->filter(function ($type) {
return in_array($type['slug'], $this->industries);
});
}
public static function getAllTypes(): Collection
{
return collect(
array_values(
json_decode(
file_get_contents(resource_path('data/forms/templates/types.json')),
true)
)
)->values();
}
public static function getAllIndustries(): Collection
{
return collect(
array_values(
json_decode(
file_get_contents(resource_path('data/forms/templates/industries.json')),
true)
)
)->values();
}
}

View File

@ -18,6 +18,30 @@ class TemplatePolicy
*/
public function create(User $user)
{
return $user->template_editor;
return $user->admin || $user->template_editor;
}
/**
* Determine whether the user can update the model.
*
* @param \App\Models\User $user
* @param \App\Models\Template $template
* @return mixed
*/
public function update(User $user, Template $template)
{
return $user->admin || $user->template_editor;
}
/**
* Determine whether the user can delete the model.
*
* @param \App\Models\User $user
* @param \App\Models\Template $template
* @return mixed
*/
public function delete(User $user, Template $template)
{
return $user->admin || $user->template_editor;
}
}

View File

@ -14,7 +14,7 @@ use OpenAI\Exceptions\ErrorException;
*/
class GptCompleter
{
const AI_MODEL = 'gpt-3.5-turbo';
const AI_MODEL = 'gpt-4';
protected Client $openAi;
protected mixed $result;
@ -22,19 +22,32 @@ class GptCompleter
protected ?string $systemMessage;
protected int $tokenUsed = 0;
protected bool $useStreaming = false;
public function __construct(string $apiKey, protected int $retries = 2)
public function __construct(string $apiKey, protected int $retries = 2, protected string $model = self::AI_MODEL)
{
$this->openAi = \OpenAI::client($apiKey);
}
public function setAiModel(string $model)
{
$this->model = $model;
return $this;
}
public function setSystemMessage(string $systemMessage): self
{
$this->systemMessage = $systemMessage;
return $this;
}
public function completeChat(array $messages, int $maxTokens = 512, float $temperature = 0.81): self
public function useStreaming(): self
{
$this->useStreaming = true;
return $this;
}
public function completeChat(array $messages, int $maxTokens = 4096, float $temperature = 0.81): self
{
$this->computeChatCompletion($messages, $maxTokens, $temperature)
->queryCompletion();
@ -56,30 +69,40 @@ class GptCompleter
public function getArray(): array
{
$payload = Str::of($this->result)->trim();
if ($payload->contains('```json')) {
$payload = $payload->after('```json')->before('```');
} else if ($payload->contains('```')) {
$payload = $payload->after('```')->before('```');
}
$payload = $payload->toString();
$exception = null;
for ($i = 0; $i < $this->retries; $i++) {
$payload = Str::of($this->result)->trim();
if ($payload->contains('```json')) {
$payload = $payload->after('```json')->before('```');
} else if ($payload->contains('```')) {
$payload = $payload->after('```')->before('```');
}
$payload = $payload->toString();
$exception = null;
try {
$payload = (new JsonFixer)->fix($payload);
return json_decode($payload, true);
$newPayload = (new JsonFixer)->fix($payload);
return json_decode($newPayload, true);
} catch (\Aws\Exception\InvalidJsonException $e) {
$exception = $e;
Log::warning("Invalid JSON, retrying:");
Log::warning($payload);
Log::warning(json_encode($this->completionInput));
$this->queryCompletion();
}
}
throw $exception;
}
public function getHtml(): string
{
$payload = Str::of($this->result)->trim();
if ($payload->contains('```html')) {
$payload = $payload->after('```html')->before('```');
} else if ($payload->contains('```')) {
$payload = $payload->after('```')->before('```');
}
return $payload->toString();
}
public function getString(): string
{
return trim($this->result);
@ -90,7 +113,7 @@ class GptCompleter
return $this->tokenUsed;
}
protected function computeChatCompletion(array $messages, int $maxTokens = 512, float $temperature = 0.81): self
protected function computeChatCompletion(array $messages, int $maxTokens = 4096, float $temperature = 0.81): self
{
if (isset($this->systemMessage) && $messages[0]['role'] !== 'system') {
$messages = array_merge([[
@ -100,7 +123,7 @@ class GptCompleter
}
$completionInput = [
'model' => self::AI_MODEL,
'model' => $this->model,
'messages' => $messages,
'max_tokens' => $maxTokens,
'temperature' => $temperature
@ -110,7 +133,12 @@ class GptCompleter
return $this;
}
protected function queryCompletion(): self {
protected function queryCompletion(): self
{
if ($this->useStreaming) {
return $this->queryStreamedCompletion();
}
try {
Log::debug("Open AI query: " . json_encode($this->completionInput));
$response = $this->openAi->chat()->create($this->completionInput);
@ -123,4 +151,19 @@ class GptCompleter
$this->result = $response->choices[0]->message->content;
return $this;
}
protected function queryStreamedCompletion(): self
{
Log::debug("Open AI query: " . json_encode($this->completionInput));
$this->result = '';
$response = $this->openAi->chat()->createStreamed($this->completionInput);
foreach ($response as $chunk) {
$choice = $chunk->choices[0];
if (is_null($choice->delta->role)) {
$this->result .= $choice->delta->content;
}
}
return $this;
}
}

View File

@ -95,6 +95,7 @@ class JsonFixer
*/
public function fix($json)
{
$json = preg_replace('/(?<!\\\\)(?:\\\\{2})*\p{C}+/u', '', $json);
list($head, $json, $tail) = $this->trim($json);
if (empty($json) || $this->isValid($json)) {
@ -124,7 +125,7 @@ class JsonFixer
protected function isValid($json)
{
\json_decode($json);
\json_decode($json,true,512,JSON_INVALID_UTF8_SUBSTITUTE);
return \JSON_ERROR_NONE === \json_last_error();
}
@ -265,6 +266,10 @@ class JsonFixer
return $json;
}
\Log::debug('Broken json received: ', [
'json' => $json
]);
throw new InvalidJsonException(
\sprintf('Could not fix JSON (tried padding `%s`)', \substr($tmpJson, $length), $json)
);

View File

@ -34,8 +34,8 @@ class SeoMetaResolver
'privacy_policy' => '/privacy-policy',
'terms_conditions' => '/terms-conditions',
'integrations' => '/integrations',
'templates' => '/templates',
'template_show' => '/templates/{slug}',
'templates' => '/form-templates',
'templates_show' => '/form-templates/{slug}',
];
/**
@ -62,7 +62,7 @@ class SeoMetaResolver
],
'templates' => [
'title' => 'Templates',
'description' => 'Free templates to quickly create beautiful forms for free!'
'description' => 'Our collection of beautiful templates to create your own forms!'
],
];
@ -182,13 +182,13 @@ class SeoMetaResolver
return $meta;
}
private function getTemplateShowMeta(): array
private function getTemplatesShowMeta(): array
{
$template = Template::whereSlug($this->patternData['slug'])->firstOrFail();
return [
'title' => $template->name . $this->titleSuffix(),
'description' => Str::of($template->description)->limit(160),
'description' => Str::of($template->short_description)->limit(140) . ' | Customize any template and create your own form in minutes.',
'image' => $template->image_url
];
}

View File

@ -36,7 +36,7 @@
"laravel/vapor-ui": "^1.5",
"league/flysystem-aws-s3-v3": "^3.0",
"maatwebsite/excel": "^3.1",
"openai-php/client": "^0.3.5",
"openai-php/client": "^0.6.4",
"propaganistas/laravel-disposable-email": "^2.2",
"sentry/sentry-laravel": "^2.11.0",
"spatie/laravel-sitemap": "^6.0",

2047
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -52,7 +52,7 @@ return [
'api_key' => env('OPEN_AI_API_KEY'),
],
'unslash' => [
'unsplash' => [
'access_key' => env('UNSPLASH_ACCESS_KEY'),
'secret_key' => env('UNSPLASH_SECRET_KEY'),
],

View File

@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('templates', function (Blueprint $table) {
$table->boolean('publicly_listed')->default(false);
$table->jsonb('industries')->default('[]');
$table->jsonb('types')->default('[]');
$table->string('short_description')->nullable();
$table->jsonb('related_templates')->default('[]');
$table->string('image_url',500)->nullable()->change();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('templates', function (Blueprint $table) {
$table->dropColumn(['publicly_listed', 'industries', 'types', 'short_description', 'related_templates']);
});
}
};

18
package-lock.json generated
View File

@ -28,6 +28,7 @@
"vue-clickaway": "^2.2.2",
"vue-codemirror": "^4.0.6",
"vue-confetti": "^2.3.0",
"vue-country-flag": "^2.3.2",
"vue-i18n": "^8.25.0",
"vue-meta": "^2.4.0",
"vue-notion": "^0.4.0",
@ -12462,6 +12463,17 @@
"resolved": "https://registry.npmjs.org/vue-confetti/-/vue-confetti-2.3.0.tgz",
"integrity": "sha512-zmPniVzBKv0ie/BEXBR6Isi08hYSd6lS18b8VduG5BzZ2tv6bO/rlwISg+IpGY2XsqAFTXFdTC28YR+UPocnAw=="
},
"node_modules/vue-country-flag": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/vue-country-flag/-/vue-country-flag-2.3.2.tgz",
"integrity": "sha512-YhSS+GbLT9tp8tjMXxJKlqpBUd6dbhQJrttKj8ZbHtBocorIomFDMVMxraWVMs3hxaCW6SsAYaREkoYM00ORiA==",
"engines": {
"node": ">=10"
},
"peerDependencies": {
"vue": "^2.6.12"
}
},
"node_modules/vue-eslint-parser": {
"version": "7.11.0",
"resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-7.11.0.tgz",
@ -22348,6 +22360,12 @@
"resolved": "https://registry.npmjs.org/vue-confetti/-/vue-confetti-2.3.0.tgz",
"integrity": "sha512-zmPniVzBKv0ie/BEXBR6Isi08hYSd6lS18b8VduG5BzZ2tv6bO/rlwISg+IpGY2XsqAFTXFdTC28YR+UPocnAw=="
},
"vue-country-flag": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/vue-country-flag/-/vue-country-flag-2.3.2.tgz",
"integrity": "sha512-YhSS+GbLT9tp8tjMXxJKlqpBUd6dbhQJrttKj8ZbHtBocorIomFDMVMxraWVMs3hxaCW6SsAYaREkoYM00ORiA==",
"requires": {}
},
"vue-eslint-parser": {
"version": "7.11.0",
"resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-7.11.0.tgz",

View File

@ -28,6 +28,7 @@
"vue-clickaway": "^2.2.2",
"vue-codemirror": "^4.0.6",
"vue-confetti": "^2.3.0",
"vue-country-flag": "^2.3.2",
"vue-i18n": "^8.25.0",
"vue-meta": "^2.4.0",
"vue-notion": "^0.4.0",

View File

@ -0,0 +1,184 @@
{
"advertising_forms": {
"name": "Advertising Forms",
"slug": "advertising_forms",
"meta_title": "Supercharge Your Advertising Campaigns with OpnForm",
"meta_description": "Discover how OpnForm and our Advertising Form Templates can revolutionize your advertising campaigns. Customize, embed, and integrate forms to streamline data collection and improve collaboration with clients and team members.",
"description": "Attention all advertising professionals! Our Advertising Form Templates are designed to streamline your data collection process. Whether you need to gather client information, conduct market research surveys, or collect feedback from customers, OpnForm has you covered. With OpnForm, you can fully customize and brand your forms to represent your agency or brand. Embed these forms on your website or share them via email, social media, or any other online channel. Take advantage of features like email notifications for form owners and submitters, integration with Slack, Discord, and other tools via Zapier or webhooks, and the ability to protect your forms with a password. Plus, our forms support captchas to prevent spam submissions and allow you to add custom code for advanced functionality. Start optimizing your advertising workflow with OpnForm and our Advertising Form Templates today!"
},
"alumni_forms": {
"name": "Alumni Forms",
"slug": "alumni_forms",
"meta_title": "Unlock the Potential of Your Alumni Community with OpnForm",
"meta_description": "Discover how OpnForm empowers educational institutions, alumni associations, and professional networking groups to streamline alumni data collection, feedback gathering, and event organization. With our Alumni Form Templates, easily create customized forms, receive email notifications, integrate with popular tools, and enhance security measures. Start engaging with your alumni community like never before!",
"description": "Are you an educational institution, alumni association, or a professional networking group? Our Alumni Form Templates are designed to help you easily collect information from your alumni community. Whether you want to update contact details, gather feedback, or organize events, OpnForm provides a user-friendly platform to create and manage your forms. With our customizable templates, you can collect alumni data, track engagement, and improve communication effortlessly. OpnForm offers a wide range of features, including email notifications for both the form owner and submitter, fully customizable branding, the ability to host forms on a custom domain, and seamless integration with various tools such as Slack, Discord, and Zapier. Protect your forms with passwords, add captchas for enhanced security, and even allow respondents to edit their own submissions. Explore our Alumni Form Templates below and start connecting with your alumni community today!"
},
"animal_shelter_forms": {
"name": "Animal Shelter Forms",
"slug": "animal_shelter_forms",
"meta_title": "Simplify the Adoption Process | OpnForm Animal Shelter Form Templates",
"meta_description": "Are you an animal shelter or rescue organization? Streamline your adoption process with OpnForm's Animal Shelter Form Templates. Collect information from potential adopters, foster parents, and volunteers in a user-friendly manner. Customize and brand your forms, receive email notifications, integrate with popular tools, and enhance security. Discover the power of OpnForm for your animal shelter or rescue organization!",
"description": "Are you an animal shelter or rescue organization? OpnForm's Animal Shelter Form Templates are designed to streamline your workflow and help you efficiently manage the adoption process for your furry friends. With OpnForm, you can easily collect information from potential adopters, foster parents, and volunteers in a user-friendly manner. Customize and brand your forms to match your organization's identity. Our open-source form builder offers a wide range of features, including email notifications for both form owners and respondents, custom domains to host your forms, and the ability to embed forms on your website. Connect with popular tools like Slack, Discord, and more using our seamless integrations. Ensure the security of your forms with password protection and captchas. Let respondents edit their own submissions and create multi-page forms to gather comprehensive information. Get started with our Animal Shelter Form Templates today!"
},
"banking_forms": {
"name": "Banking Forms",
"slug": "banking_forms",
"meta_title": "Revolutionize Your Banking Processes with OpnForm's Banking Form Templates",
"meta_description": "Discover how OpnForm's Banking Form Templates can modernize your banking operations. Collect essential information like loan applications, account opening forms, and customer feedback with ease. Customize and brand your forms, protect them with passwords, embed them on your website, and integrate them with banking systems. Automate email notifications, enable form editing for respondents, enhance security with captchas, and add custom code. Optimize your banking processes today!",
"description": "Are you in the banking industry? Streamline your processes and enhance customer experiences with OpnForm's Banking Form Templates. Easily collect essential information from your customers, such as loan applications, account opening forms, or customer feedback. With OpnForm, you have access to a powerful open-source form builder that offers advanced features tailored for the banking industry. Customize and brand your forms, protect them with passwords, and embed them on your website or share them via a custom domain. Integrate your forms with tools like Slack, Discord, or other banking systems through Zapier or webhooks. Automate email notifications for both form owners and form submitters, and enable form editing for respondents to update their submissions. Enhance security with captchas and add custom code to meet your specific requirements. Optimize your banking operations with OpnForm and our Banking Form Templates."
},
"business_forms": {
"name": "Business Forms",
"slug": "business_forms",
"meta_title": "Supercharge Your Data Collection with OpnForm's Business Form Templates",
"meta_description": "Discover how OpnForm's open-source form builder and Business Form Templates can revolutionize your data collection processes. Collect valuable information from your customers, conduct market research, and streamline your business operations. With features like email notifications, custom branding, and integration with popular tools, OpnForm is the ultimate solution for efficient and effective data collection.",
"description": "Are you a business owner or manager looking for a better way to collect and manage information? Look no further! OpnForm's Business Form Templates are designed to streamline your data collection processes. Whether you need to gather customer feedback, conduct market research, or collect orders, OpnForm has you covered. With our open-source form builder, you can easily create customized forms that match your brand and meet your specific needs. Our templates come with powerful features, including email notifications for both the form owner and the submitter, the ability to embed forms on any website, and seamless integration with popular tools like Slack, Discord, and Zapier. Plus, you can add password protection, captchas, custom code, and pre-fill options to enhance your form's functionality. Don't miss out on the benefits of OpnForm and our Business Form Templates. Start simplifying your data collection processes today!"
},
"charity_forms": {
"name": "Charity Forms",
"slug": "charity_forms",
"meta_title": "Streamline Your Charity Organization with OpnForm",
"meta_description": "Discover how OpnForm and our Charity Form Templates can simplify data collection for your charity organization. Easily collect donations, volunteer registrations, event registrations, and more with our customizable forms. Explore powerful features such as email notifications, form customization, embedding forms on your website, integrating with popular tools, and more. Start streamlining your charity organization's processes today!",
"description": "Are you a charity organization looking for a simple and effective way to collect information from donors, volunteers, and beneficiaries? OpnForm's Charity Form Templates are designed specifically for your needs. With OpnForm, you can easily create customized forms to collect donations, volunteer registrations, event registrations, and more. Our templates are ready to use, but can also be easily customized to match your branding and requirements. With OpnForm, you have access to powerful features such as email notifications for both the form owner and the form submitter, form customization and branding, the ability to host forms on your own custom domain, and the option to embed forms on your website. Integrating with other tools is a breeze with OpnForm's integration capabilities with popular platforms like Slack, Discord, and many others via Zapier or webhooks. You can also protect your forms with a password, add captchas for added security, and even include custom code to further enhance your forms. In addition, OpnForm allows you to pre-fill forms via URL parameters, set closing dates or submission limits, and enables respondents to edit their own form submissions. Start streamlining your charity organization's data collection process today with OpnForm and our Charity Form Templates."
},
"church_forms": {
"name": "Church Forms",
"slug": "church_forms",
"meta_title": "Simplify Church Administration with OpnForm's Church Form Templates",
"meta_description": "OpnForm's Church Form Templates provide church administrators, pastors, and event organizers with an efficient way to collect information from their congregation or event attendees. With OpnForm's open-source form builder, customize your forms to match your church's branding, embed them on your website, and receive email notifications for every submission. Discover the features of OpnForm and simplify your church administration tasks today.",
"description": "Are you a church administrator, pastor, or event organizer? Our Church Form Templates are designed specifically for you. Streamline your administrative tasks and collect important information from your congregation or event attendees with ease. With OpnForm, you have access to a powerful open-source form builder that offers a wide range of features. Customize your forms to match your church's branding, embed them on your website, and receive email notifications for every submission. Integrate your forms with tools like Slack, Discord, or other apps via Zapier or webhooks. Ensure the security of your forms with password protection and add a captcha for extra security. In addition, you can pre-fill forms with url parameters, set form closure dates, and even allow respondents to edit their own submissions. Explore our Church Form Templates below and simplify your church administration tasks."
},
"customer_service_forms": {
"name": "Customer Service Forms",
"slug": "customer_service_forms",
"meta_title": "Boost Your Customer Service with OpnForm's Customer Service Form Templates",
"meta_description": "OpnForm offers a range of customizable Customer Service Form Templates that can help you streamline your customer service processes. Collect feedback, handle complaints, and gather customer information with ease. Customize your forms, integrate with Slack and other tools, and enhance security with passwords and captchas. Start using OpnForm now and enhance your customer service experience.",
"description": "Are you in the customer service industry? Our Customer Service Form Templates are designed to help you streamline your customer service processes. With OpnForm, you can easily create forms to collect valuable feedback, handle customer complaints, and gather customer information. Customize your forms with your branding and choose from a range of features like email notifications, custom domains, embedded forms, and integration with Slack and other tools via Zapier. Protect your forms with passwords and add captchas for enhanced security. With OpnForm, you have the flexibility to create forms that meet your specific customer service needs. Start using our Customer Service Form Templates now and enhance your customer service experience."
},
"ecommerce_forms": {
"name": "E-commerce Forms",
"slug": "ecommerce_forms",
"meta_title": "Supercharge Your E-commerce Business with OpnForm",
"meta_description": "Discover how OpnForm's E-commerce Form Templates can help you streamline your online sales process. Collect customer information, orders, and feedback with ease. Customize and brand your forms to match your website's design. Integrate your forms with Slack, Discord, and other tools to automate your workflow. Get email notifications for new submissions and enjoy the convenience of an open-source form builder. Boost your e-commerce business with OpnForm now!",
"description": "Attention E-commerce businesses! Boost your online sales with OpnForm's E-commerce Form Templates. Easily collect customer information, orders, and feedback with our user-friendly form builder. Customize and brand your forms to match your website's design and create a seamless customer experience. With OpnForm, you can integrate your forms with popular tools like Slack and Discord through Zapier or webhooks, streamlining your order processing and customer support workflow. Stay organized with email notifications for both you and your customers. Start optimizing your e-commerce processes with OpnForm today!"
},
"education_forms": {
"name": "Education Forms",
"slug": "education_forms",
"meta_title": "Streamline Administrative Tasks with Education Form Templates | OpnForm",
"meta_description": "Discover how OpnForm and our Education Form Templates can help educators and administrators streamline administrative tasks, gather important information, and simplify school processes. Enjoy email notifications, customization options, integration with popular tools, and more.",
"description": "Calling all educators and administrators! With OpnForm and our Education Form Templates, streamline your administrative tasks and gather important information from students, parents, and staff members. Easily create customized forms for school registrations, permission slips, surveys, and more. OpnForm is an open-source form builder that offers a wide range of features. Enjoy email notifications for both form owners and submitter, fully customizable and branded forms, the ability to host forms on your own custom domain, and the option to embed forms on any website. Integrate your forms with popular tools like Slack, Discord, and other applications via Zapier or webhooks. Protect your forms with passwords, add captchas for security, and even include custom code for advanced functionality. Pre-fill forms with URL parameters, set closing dates or submission limits, and allow respondents to edit their own submissions. Experience the power of OpnForm and our Education Form Templates today!"
},
"entertainment_forms": {
"name": "Entertainment Forms",
"slug": "entertainment_forms",
"meta_title": "Streamline Your Entertainment Workflows with OpnForm",
"meta_description": "Discover how OpnForm can revolutionize your entertainment business. Create custom forms to collect event details, booking inquiries, and attendee information. Benefit from email notifications, complete customization, form embedding, and integration with popular tools like Slack and Zapier. Experience the power of OpnForm and simplify your entertainment workflows today.",
"description": "Are you an event organizer, artist, or performer? Our Entertainment Form Templates are designed to streamline your event planning and management process. With OpnForm, you can easily create and customize forms to collect important information from clients, attendees, and participants. Whether it's booking inquiries, event registration, or feedback forms, OpnForm has got you covered. Benefit from the flexibility of our open-source form builder and enjoy features like email notifications, complete form customization, embedding forms on your website, and integrating with popular tools like Slack, Discord, or Zapier. Simplify your entertainment workflows with OpnForm and our versatile form templates below."
},
"gaming_forms": {
"name": "Gaming Forms",
"slug": "gaming_forms",
"meta_title": "Level up your data collection with OpnForm's Gaming Form Templates",
"meta_description": "Are you in the gaming industry? Discover how OpnForm's open-source form builder and Gaming Form Templates can help you streamline your data collection process. Collect feedback, registrations, and conduct surveys to improve your games. Fully customize and brand your forms, embed them on your gaming websites, and integrate them with Discord and other gaming tools. Maximize the potential of your gaming business with OpnForm!",
"description": "Are you in the gaming industry? OpnForm's Gaming Form Templates are designed specifically for game developers, esports teams, and gaming events organizers. With OpnForm, you can easily collect feedback from players, gather registration information for tournaments, and conduct surveys to improve your games. Our templates can be fully customized and branded to match your gaming brand. Host your forms on your own custom domain and embed them seamlessly on your gaming websites. OpnForm also offers integrations with popular gaming tools like Discord, allowing you to receive form submissions directly in your gaming community server. With OpnForm, you have complete control over your forms and can protect them with passwords, add captchas, or even add custom code. Start gathering valuable data and optimizing your gaming experiences with OpnForm and our Gaming Form Templates today!"
},
"healthcare_forms": {
"name": "Healthcare Forms",
"slug": "healthcare_forms",
"meta_title": "Streamline Your Healthcare Data Collection with OpnForm",
"meta_description": "OpnForm offers a range of Healthcare Form Templates to help healthcare professionals collect patient information, medical history, and appointment requests effortlessly. Customize and brand your forms, embed them on your website, and enjoy seamless integration with Slack, Discord, and other tools via Zapier. Explore OpnForm for efficient healthcare data collection.",
"description": "Are you working in the healthcare industry? Our Healthcare Form Templates are designed to streamline your data collection processes. Easily collect patient information, medical history, and appointment requests with OpnForm. As an open-source form builder, OpnForm allows you to fully customize and brand your forms to match your organization's identity. With email notifications, you'll never miss a form submission, ensuring timely responses and efficient patient care. Our templates can be embedded on your website or shared through a custom domain, making it convenient for patients to access and fill out the forms. Additionally, OpnForm integrates seamlessly with popular tools like Slack and Discord via Zapier or webhooks, enabling easy collaboration and integration with your existing workflows. Enhance your healthcare processes with OpnForm and our Healthcare Form Templates today."
},
"human_resources_forms": {
"name": "Human Resources Forms",
"slug": "human_resources_forms",
"meta_title": "Revolutionize Your HR Processes with OpnForm's Human Resources Form Templates",
"meta_description": "Discover how the Human Resources industry can benefit from OpnForm and our customizable form templates. Simplify your hiring process, employee evaluations, and feedback collection with the wide range of features offered by OpnForm. With easy integration, form protection, customization options, and more, OpnForm is the ideal tool for modern HR professionals.",
"description": "Are you in the Human Resources industry? Streamline your hiring process and employee management with OpnForm's Human Resources Form Templates. Easily collect job applications, conduct employee evaluations, and gather employee feedback using our customizable forms. With OpnForm, you have access to a wide range of features including email notifications, form customization and branding, embedding forms on your website, integration with Slack, Discord, and other tools via Zapier or webhooks, form protection with passwords, captcha support, adding custom code, pre-filling forms via URL parameters, closing forms at specific dates or after a certain number of submissions, allowing respondents to edit their own submissions, and creating forms with multiple pages. Start improving your HR processes today with OpnForm and our Human Resources Form Templates."
},
"it_forms": {
"name": "IT Forms",
"slug": "it_forms",
"meta_title": "Supercharge Your IT Data Collection with OpnForm",
"meta_description": "Discover how OpnForm and our IT form templates can revolutionize your data collection in the IT industry. With features like email notifications, customization options, integration with popular tools, and more, OpnForm is the perfect solution for IT professionals seeking efficient and streamlined data collection.",
"description": "Are you in the IT industry? Looking for a powerful and customizable form builder? Look no further! OpnForm is the perfect solution for IT professionals to streamline their data collection process. With OpnForm, you can create forms tailored to your specific needs, whether it's collecting bug reports, user feedback, or gathering customer information. Take advantage of OpnForm's open-source form builder and enjoy features like email notifications for form owners and submitters, full customization and branding options, integration with popular tools like Slack and Discord through Zapier or webhooks, and even form protection with passwords and captchas. Simplify your data collection process with OpnForm and our IT form templates today!"
},
"insurance_forms": {
"name": "Insurance Forms",
"slug": "insurance_forms",
"meta_title": "Revolutionize Your Insurance Forms with OpnForm",
"meta_description": "Discover how insurance professionals can optimize their form processes with OpnForm's Insurance Form Templates. Collect and manage data from clients, policyholders, and claimants effortlessly. Enjoy the features of an open-source form builder, customizable forms, email notifications, and seamless integration with popular tools. Enhance security with passwords and captchas. Empower respondents with edit capabilities and create intuitive multi-page forms. Get started with OpnForm today!",
"description": "Are you in the insurance industry? Streamline your form processes with OpnForm's Insurance Form Templates. Easily collect and manage information from clients, policyholders, and claimants. With OpnForm, enjoy the benefits of an open-source form builder that offers email notifications for both form owners and form submitters. Customize and brand your forms to match your insurance company's identity. Host your forms on your own custom domain or embed them seamlessly on your website. Integrate with popular tools like Slack, Discord, and more using Zapier or webhooks. Protect your forms with passwords and add captchas for enhanced security. Utilize advanced features like custom code, URL parameters for pre-filling forms, and limit form availability based on dates or submission quotas. Allow respondents to edit their own submissions or create multi-page forms for a seamless user experience."
},
"marketing_forms": {
"name": "Marketing Forms",
"slug": "marketing_forms",
"meta_title": "Supercharge Your Marketing Efforts with OpnForm's Marketing Form Templates",
"meta_description": "Discover how OpnForm's Marketing Form Templates can revolutionize your marketing campaigns. Collect valuable data, gather customer feedback, and conduct market research effortlessly. Customize and embed forms on your website, and integrate with popular tools like Slack and Discord. Take advantage of features like email notifications, password protection, and more. Start using OpnForm today!",
"description": "Calling all marketers! OpnForm's Marketing Form Templates are tailored specifically to meet the needs of marketing professionals like you. With OpnForm, you can easily create and manage forms to collect valuable data from your audience. Whether you need to gather customer feedback, conduct market research, or run promotional campaigns, OpnForm has got you covered. Enjoy the flexibility of fully customizable and branded forms that can be embedded on any website. With features like email notifications, integrations with popular tools like Slack and Discord via Zapier or webhooks, and the ability to protect forms with passwords, OpnForm offers everything you need to streamline your marketing efforts. Start using our Marketing Form Templates now and unlock the power of data-driven marketing!"
},
"photography_forms": {
"name": "Photography Forms",
"slug": "photography_forms",
"meta_title": "Simplify Photography Client Management with OpnForm",
"meta_description": "OpnForm's Photography Form Templates provide photographers and photography businesses with a simple and efficient solution to collect client information. Discover how OpnForm's open-source form builder, customizable features, and integrations with popular tools like Slack and Zapier can streamline your photography workflow.",
"description": "Are you a professional photographer or running a photography business? OpnForm's Photography Form Templates are designed to streamline your workflow and simplify the process of collecting information from clients. With OpnForm, you can easily create customized forms to gather details about client preferences, shoot requirements, and payment information. Our open-source form builder allows you to fully brand and customize your forms, ensuring a seamless experience for your clients. You can embed the forms on your website or share them via a custom domain. OpnForm also offers email notifications for both the form owner and submitter, keeping everyone informed throughout the process. Additionally, our integration with popular tools like Slack, Discord, and Zapier enables you to automate data collection and enhance collaboration. Try OpnForm's Photography Form Templates today and revolutionize your photography business."
},
"real_estate_forms": {
"name": "Real Estate Forms",
"slug": "real_estate_forms",
"meta_title": "Streamline Your Real Estate Transactions with OpnForm",
"meta_description": "Capture leads, gather property details, and streamline your real estate transactions with OpnForm's Real Estate Form Templates. Customize your forms, receive email notifications, and integrate with popular tools like Slack and Discord. Explore the possibilities of OpnForm for the real estate industry.",
"description": "Are you in the real estate industry? OpnForm's Real Estate Form Templates are designed specifically for real estate professionals. Easily collect client information, property details, and buyer preferences with our customizable forms. OpnForm is an open-source form builder that offers a range of features to streamline your workflow. With email notifications, you'll never miss a lead or inquiry. You can fully customize and brand your forms to match your agency's style. Host your forms on your own custom domain for a professional touch. Embed forms seamlessly on your website to capture leads directly. Integrate with popular tools like Slack, Discord, and more using Zapier or webhooks. Protect sensitive information with password protection and add an optional captcha for added security. Allow clients to edit their own form submissions to keep data up to date. With OpnForm, you have the flexibility to create multi-page forms to gather all the necessary information for your real estate transactions. Start using OpnForm and our Real Estate Form Templates today."
},
"seo_forms": {
"name": "SEO Forms",
"slug": "seo_forms",
"meta_title": "Optimize Your SEO Forms with OpnForm - Streamline Data Collection",
"meta_description": "Discover how OpnForm's SEO Form Templates can revolutionize your workflow in the SEO industry. Collect valuable data, streamline client communication, and optimize your website performance. With OpnForm, enjoy powerful features, easy customization, seamless integration, and enhanced security. Start using OpnForm today!",
"description": "Are you an SEO professional or agency looking to streamline your form creation process? OpnForm's SEO Form Templates are designed specifically to meet the needs of the SEO industry. Easily collect data and information from clients, track website optimization progress, and gather feedback from users. With OpnForm, you have access to powerful features such as email notifications for form owners and submitters, fully customizable and branded forms, the ability to host forms on your own custom domain, and seamless integration with popular tools like Slack and Discord via Zapier or webhooks. Protect your forms with passwords, add captchas for added security, and even incorporate custom code to meet your unique requirements. Pre-fill forms with URL parameters, set form submission limits or closing dates, and empower respondents to edit their own submissions. Take your SEO forms to the next level with OpnForm's versatile and user-friendly templates."
},
"salon_forms": {
"name": "Salon Forms",
"slug": "salon_forms",
"meta_title": "Transform Your Salon Operations with OpnForm's Salon Form Templates",
"meta_description": "Discover how salon owners, hairstylists, and beauty professionals can optimize their client intake process using OpnForm and our Salon Form Templates. Customize and brand your forms, collect important information, and integrate with popular tools. Streamline your salon operations today!",
"description": "Are you a salon owner, hairstylist, or beauty professional? Our Salon Form Templates are designed specifically for your industry. Streamline your client intake process and gather important information such as contact details, service preferences, and any allergies or sensitivities. With OpnForm, you get access to a powerful open-source form builder that allows you to customize and brand your forms to match your salon's unique style. Collect form submissions directly in OpnForm and receive email notifications for every submission. You can even integrate your forms with popular tools like Slack, Discord, or other platforms using Zapier or webhooks. Experience the convenience of online forms and simplify your salon operations with OpnForm and our Salon Form Templates."
},
"services_forms": {
"name": "Services Forms",
"slug": "services_forms",
"meta_title": "Supercharge Your Service Business with OpnForm's Services Form Templates",
"meta_description": "Discover how OpnForm's Services Form Templates can revolutionize your service-based business. Collect client information, streamline workflows, and improve customer satisfaction with our customizable forms. Integrate with popular tools like Slack, Discord, and more. Start optimizing your service business today!",
"description": "Are you a service-based business such as a cleaning company, consulting firm, or marketing agency? Our Services Form Templates are designed to streamline your client interactions and improve your workflow. With OpnForm, you can easily create and customize forms to collect information from your clients, whether it's for booking appointments, gathering project requirements, or conducting customer surveys. Take advantage of OpnForm's extensive features, such as email notifications, form customization, embedding forms on any website, and integrating with popular tools like Slack, Discord, and more via Zapier. Simplify your processes and enhance client satisfaction with our Services Form Templates below."
},
"sports_forms": {
"name": "Sports Forms",
"slug": "sports_forms",
"meta_title": "Streamline Your Sports Data Collection with OpnForm's Sports Form Templates",
"meta_description": "Easily collect player information, team registrations, and event sign-ups for your sports team or organization. OpnForm's Sports Form Templates offer a powerful and customizable solution for sports-related data collection. Discover the benefits of using OpnForm and streamline your sports data collection process today.",
"description": "Calling all sports teams, coaches, and event organizers! Sports Form Templates by OpnForm are designed to streamline your data collection process. Easily gather player information, team registrations, event sign-ups, and more with our customizable forms. With OpnForm, you have access to a powerful open-source form builder that offers features like email notifications for both form owners and submitter, fully customizable branding, and the ability to embed forms on any website. Take advantage of our integration options with popular tools like Slack, Discord, and Zapier to effortlessly connect your form submissions to your existing workflows. Plus, with features like password protection, captchas, and the ability to add custom code, you can ensure the security and functionality of your sports forms. Start using OpnForm and our Sports Form Templates today to streamline your sports-related data collection process!"
},
"summer_camps_forms": {
"name": "Summer Camps Forms",
"slug": "summer_camps_forms",
"meta_title": "Simplify Summer Camp Registration with OpnForm's Summer Camp Forms Templates",
"meta_description": "Make summer camp registration a breeze with OpnForm's open-source form builder and Summer Camp Forms Templates. Easily collect camper information, customize forms, and integrate with popular tools like Slack and Discord. Secure and streamline your registration process with password protection, captchas, and the ability for respondents to edit their own submissions. Get started today and make registration easy with OpnForm!",
"description": "Calling all summer camp organizers and administrators! Our Summer Camp Forms Templates are designed to simplify your registration and information gathering process. With OpnForm, you can easily create customized forms for camper registration, medical information, emergency contacts, activity preferences, and more. Take advantage of OpnForm's open-source form builder to tailor the templates to your specific needs. Enjoy the benefits of email notifications, fully customizable branding, and the ability to embed forms on your camp's website. Integrate with popular tools like Slack and Discord using Zapier or webhooks. Secure your forms with passwords and add captchas for enhanced security. With OpnForm, you have the flexibility to pre-fill forms via URL parameters, set form closure dates, and allow respondents to edit their own submissions. Get ready to streamline your summer camp registration process with OpnForm's Summer Camp Forms Templates!"
},
"veterinary_service_forms": {
"name": "Veterinary Service Forms",
"slug": "veterinary_service_forms",
"meta_title": "Streamline Your Veterinary Services with OpnForm",
"meta_description": "Discover how veterinary service providers can optimize their workflow using OpnForm's Veterinary Service Form Templates. Collect essential information, customize and brand your forms, integrate with tools, protect your data, and more. Start streamlining your client intake process today.",
"description": "Are you a veterinary service provider? Our Veterinary Service Form Templates are designed with you in mind. Streamline your client intake process and collect essential information about pets, medical history, and appointment preferences. OpnForm, an open-source form builder, offers a range of features to enhance your form-building experience. With email notifications, you'll never miss a form submission. Customize and brand your forms to create a professional look and feel. Host your forms on your own custom domain or embed them on your website. Integrate with tools like Slack, Discord, and more through Zapier or webhooks. Protect your forms with passwords and add captchas for added security. Pre-fill forms with URL parameters and set submission limits or close forms at specific dates. With OpnForm, you can even allow respondents to edit their own submissions and create multi-page forms. Use our Veterinary Service Form Templates below and start streamlining your workflow today."
},
"web_design_forms": {
"name": "Web Design Forms",
"slug": "web_design_forms",
"meta_title": "Supercharge Your Web Design Workflow with OpnForm",
"meta_description": "Discover the power of OpnForm for web designers and developers. Effortlessly collect project requirements, design preferences, and other essential information with our Web Design Form Templates. Customize and brand your forms, integrate them with popular tools, protect them with passwords, and much more. Explore OpnForm now!",
"description": "Are you a web designer or developer? Our Web Design Form Templates are tailored to your needs. Streamline your client onboarding process by collecting project requirements, design preferences, and other necessary information with OpnForm. As an open-source form builder, OpnForm offers a wide range of features to enhance your form building experience. Customize and brand your forms, host them on your own custom domain, and embed them seamlessly into your website. With OpnForm, you can integrate your forms with popular tools like Slack, Discord, and more using Zapier or webhooks. Protect your forms with passwords and add captchas to ensure security. Utilize the versatility of OpnForm by adding custom code and pre-filling forms via URL parameters. You can also set form closure dates or limit submissions. Additionally, OpnForm allows respondents to edit their own submissions and supports multi-page forms. Explore our collection of Web Design Form Templates below and begin optimizing your workflow today."
}
}

View File

@ -0,0 +1,324 @@
{
"order_forms": {
"name": "Order Forms",
"slug": "order_forms",
"meta_title": "Supercharge Your Order Management with OpnForm's Order Form Templates",
"meta_description": "Discover how OpnForm's Order Form Templates can streamline your order management process. Create customized order forms with ease, receive email notifications, integrate with popular tools, and more. Start simplifying your ordering process today!",
"description": "Looking to streamline your order management process? OpnForm's Order Form Templates are designed to simplify the collection of order details. With OpnForm, you can easily create customized order forms that fit your business needs. Take advantage of features like email notifications, form branding, custom domains, and integrations with popular tools like Slack and Discord. Whether you're running an online store or managing orders for a restaurant, OpnForm's Order Form Templates can help optimize your workflow and upgrade your ordering process."
},
"registration_forms": {
"name": "Registration Forms",
"slug": "registration_forms",
"meta_title": "Streamline Your Registration Process with OpnForm's Registration Form Templates",
"meta_description": "Looking for an easy way to collect attendee details for your event or workshop? Discover how OpnForm's open-source form builder and Registration Form Templates can simplify your registration process. Fully customizable forms, email notifications, integration options, and more!",
"description": "Are you organizing an event or workshop and need to collect attendee details? OpnForm's Registration Form Templates can help streamline your registration process! With our easy-to-use form builder, you can create customized registration forms to suit your specific needs. OpnForm's open-source platform allows you to fully customize and brand your forms, ensuring a seamless experience for your attendees. Additionally, our form builder provides features such as email notifications, integration with popular tools like Slack and Discord, password protection, captcha options, and the ability to add custom code. You can even pre-fill forms via URL parameters and set closing dates or submission limits. Simplify your registration process and make it a breeze with OpnForm and our Registration Form Templates!"
},
"event_registration_forms": {
"name": "Event Registration Forms",
"slug": "event_registration_forms",
"meta_title": "Streamline Event Registrations with OpnForm's Templates",
"meta_description": "Easily manage event registrations using OpnForm's Event Registration Form Templates. Customize and embed these forms on your website, streamline your registration process, and benefit from OpnForm's powerful features like email notifications, custom branding, and integrations with popular tools. Upgrade your event management with OpnForm!",
"description": "Planning an event and need to manage registrations? OpnForm offers Event Registration Form Templates that can simplify your work! With these templates, you can easily collect attendee information, streamline your registration process, and benefit from OpnForm's powerful features. Customize the form to match your event's branding, embed it on your website, and use OpnForm's integrations with tools like Slack and Discord for seamless event management. Upgrade your event registration process with OpnForm!"
},
"payment_forms": {
"name": "Payment Forms",
"slug": "payment_forms",
"meta_title": "Accept Payments Online with OpnForm's Payment Form Templates",
"meta_description": "OpnForm's Payment Form Templates make it simple for businesses and organizations to collect payments and donations. Discover how you can easily create secure and customizable payment forms, integrate with payment gateways, and accept payments online using OpnForm's open-source form builder and templates.",
"description": "Looking to collect payments online? OpnForm offers Payment Form Templates that can make it easy for you to accept payments and donations! With OpnForm, you can create secure and customizable payment forms, allowing you to sell products, collect membership fees, receive event registrations, and more. Benefit from features like email notifications, custom branding, integration with payment gateways, and the ability to embed forms on your website. Start accepting payments effortlessly with OpnForm's Payment Form Templates!"
},
"application_forms": {
"name": "Application Forms",
"slug": "application_forms",
"meta_title": "Simplify Your Application Process with OpnForm's Application Form Templates",
"meta_description": "Discover how OpnForm's Application Form Templates can help you collect and manage applications more efficiently. With our open-source form builder, you can easily create and customize application forms for job applications, scholarship applications, or membership applications. Streamline your process, receive email notifications, and integrate with tools like Slack and Discord. Start using OpnForm and our convenient application form templates today!",
"description": "Need to streamline your application process? OpnForm's Application Form Templates are designed to simplify the way you collect and manage applications. Whether you're accepting job applications, scholarship applications, or membership applications, OpnForm has you covered. With our open-source form builder, you can easily create and customize application forms to fit your specific needs. Benefit from our email notifications, branding options, embedding capabilities, and integrations with tools like Slack and Discord. Upgrade your application process today with OpnForm and our convenient application form templates!"
},
"file_upload_forms": {
"name": "File Upload Forms",
"slug": "file_upload_forms",
"meta_title": "Simplify File Uploads with OpnForm",
"meta_description": "OpnForm's File Upload Form Templates make it simple to collect files from your users. Create fully branded forms, receive email notifications, and integrate with Zapier or webhooks for seamless file management. Explore OpnForm's open-source form builder now!",
"description": "Need to collect files from your users? OpnForm's File Upload Form Templates make it easy! Whether you're running a photography contest, accepting job applications, or gathering design submissions, OpnForm has you covered. With OpnForm's open-source form builder, you can create custom file upload forms, fully branded with your own style. Allow your users to easily upload files, while you receive email notifications with the submissions. Use OpnForm's integration with Zapier or webhooks to automatically send the files to your preferred storage solution. Plus, with OpnForm's advanced features like password protection, custom code integration, and form pre-filling, you can create a secure and personalized experience for your users."
},
"booking_forms": {
"name": "Booking Forms",
"slug": "booking_forms",
"meta_title": "Streamline Your Booking Process with OpnForm's Booking Form Templates",
"meta_description": "Are you in need of a convenient and efficient way to handle bookings? Look no further! OpnForm's Booking Form Templates are the perfect solution. With OpnForm, you can easily create customized booking forms, integrate them with various tools, and simplify your booking process. Explore our templates today and see how OpnForm can revolutionize your booking experience!",
"description": "Planning an event or managing appointments? OpnForm's Booking Form Templates are designed to simplify the booking process. Whether you're a small business owner, a service provider, or an event organizer, our templates make it easy for you to collect booking details, streamline your workflow, and enhance your overall booking experience. With OpnForm, you can fully customize and brand your booking forms, integrate them with your favorite tools like Slack and Discord, and even protect them with passwords and captchas. Whether you need to schedule appointments, reserve tables, or organize events, OpnForm is here to help you make booking a breeze."
},
"survey_templates": {
"name": "Survey Templates",
"slug": "survey_templates",
"meta_title": "Create Engaging Surveys with OpnForm's Survey Template Collection",
"meta_description": "OpnForm's Survey Form Templates are built to simplify your survey creation process. Whether you are conducting customer satisfaction surveys, employee feedback surveys, or market research surveys, OpnForm provides an intuitive and customizable platform. Discover how OpnForm's open-source form builder, email notifications, custom branding, and integrations can enhance your survey experience.",
"description": "Looking to collect valuable feedback and insights? OpnForm's Survey Form Templates are designed to help you easily create and distribute surveys. Whether you need to conduct customer satisfaction surveys, employee feedback surveys, or market research surveys, OpnForm has got you covered. With our intuitive and customizable survey templates, you can streamline your data collection process, analyze responses effectively, and gain actionable insights. Take advantage of OpnForm's open-source form builder and leverage features like email notifications, custom branding, integrations with popular tools, and more to create impactful surveys."
},
"consent_forms": {
"name": "Consent Forms",
"slug": "consent_forms",
"meta_title": "Simplify Consent Forms with OpnForm",
"meta_description": "Discover how OpnForm's open-source form builder and Consent Form Templates can streamline your consent form process. Benefit from features like email notifications, customization options, form hosting on your custom domain, integrations with Slack and Discord, and more.",
"description": "Need consent forms for your business or organization? OpnForm provides a range of Consent Form Templates to simplify the process. With OpnForm's open-source form builder, you can easily create customized consent forms tailored to your specific needs. Benefit from features such as email notifications for both the form owner and submitter, full customization and branding options, the ability to host forms on your own custom domain, and easy integration with other tools like Slack and Discord via Zapier or webhooks. You can also add password protection, captcha, custom code, and pre-fill forms using URL parameters. Additionally, OpnForm allows you to set form expiration dates or submission limits, and even enables respondents to edit their own submissions. Streamline your consent form process with OpnForm today!"
},
"rsvp_forms": {
"name": "RSVP Forms",
"slug": "rsvp_forms",
"meta_title": "Simplify RSVP Management with OpnForm's RSVP Form Templates",
"meta_description": "Need to manage RSVPs for your event? OpnForm offers RSVP Form Templates that make it easy! Customize the template, embed it on your website, and enjoy features like email notifications, form customization, integrations with tools like Slack, and more. Upgrade your RSVP process with OpnForm today!",
"description": "Planning an event or gathering and need to manage RSVPs? OpnForm offers RSVP Form Templates that can simplify your work! With these form templates, you can easily collect RSVP details, streamline your RSVP process, and benefit from OpnForm's advanced features. Customize the RSVP form template to fit your event's needs, embed it on your website, and see how OpnForm can upgrade your RSVP management."
},
"appointment_forms": {
"name": "Appointment Forms",
"slug": "appointment_forms",
"meta_title": "Simplify Your Appointment Scheduling with OpnForm",
"meta_description": "Looking for a convenient way to collect appointment requests? Discover OpnForm's Appointment Form Templates and streamline your scheduling process. With OpnForm's open-source form builder, you can easily create customizable appointment forms, receive email notifications, integrate with tools like Slack and Discord, and more. Try OpnForm today and upgrade your appointment scheduling experience.",
"description": "Need to schedule appointments? OpnForm offers Appointment Form Templates that can simplify your scheduling process! These templates are targeted at businesses, professionals, and service providers who need to collect appointment requests from clients. With OpnForm, you can easily create customizable appointment forms, streamline your scheduling process, and benefit from features like email notifications, form customization, form embedding, and integrations with tools like Slack and Discord via Zapier or webhooks. Use an appointment form template below, customize it to fit your needs, and see how OpnForm can upgrade your appointment scheduling process."
},
"contact_forms": {
"name": "Contact Forms",
"slug": "contact_forms",
"meta_title": "Supercharge Your Communication with OpnForm Contact Form Templates",
"meta_description": "Need a reliable way to collect inquiries from your website? Check out OpnForm's Contact Form Templates. Easily create and customize a contact form that matches your brand. Receive email notifications, integrate with Slack or Discord, and streamline your communication process with OpnForm.",
"description": "Looking to improve communication with your clients? OpnForm's Contact Form Templates are designed to help you effortlessly collect and manage inquiries from your website. With OpnForm, you can easily create and customize a contact form that matches your brand. Receive email notifications for every form submission, ensuring you never miss a message. Seamlessly integrate your contact form with tools like Slack or Discord using Zapier or webhooks. Whether you're a small business owner or a blogger, OpnForm's Contact Form Templates empower you to engage with your audience and streamline your communication process."
},
"questionnaire_templates": {
"name": "Questionnaire Templates",
"slug": "questionnaire_templates",
"meta_title": "Create Powerful Questionnaires with OpnForm",
"meta_description": "Discover how OpnForm's Questionnaire Templates can simplify your data collection process. Customize and analyze your questionnaires, receive email notifications, and integrate with other tools. Start creating powerful questionnaires with OpnForm today!",
"description": "Looking to create a comprehensive questionnaire? OpnForm's Questionnaire Templates are designed to make the process simple and efficient. Whether you need to conduct surveys, gather feedback, or collect data, OpnForm provides all the necessary features to create and analyze your questionnaires. With OpnForm, you can easily customize and brand your forms, receive email notifications for both form owners and respondents, and even integrate with other tools like Slack or Discord. Take advantage of OpnForm's open-source form builder to create powerful questionnaires and streamline your data collection process."
},
"signup_forms": {
"name": "Signup Forms",
"slug": "signup_forms",
"meta_title": "Supercharge Your Signup Process with OpnForm's Signup Form Templates",
"meta_description": "Discover how OpnForm's Signup Form Templates can revolutionize your signup process. Streamline user registrations, collect essential information, and integrate with other tools seamlessly. Build professional and branded signup forms using OpnForm's open-source form builder. Try OpnForm now!",
"description": "Looking to build a signup form? OpnForm offers a wide range of Signup Form Templates that can cater to your needs! Whether you're running a small business, organizing an event, or managing a community, OpnForm provides an intuitive and customizable form builder to create professional signup forms. With OpnForm, you can easily collect user information, streamline your signup process, and benefit from seamless integrations with tools like Slack and Discord via Zapier or webhooks. Customize your form's branding, protect it with a password, and embed it on any website. Upgrade your signup process with OpnForm and our versatile Signup Form Templates!"
},
"abstract_forms": {
"name": "Abstract Forms",
"slug": "abstract_forms",
"meta_title": "Create and Manage Abstract Forms with OpnForm",
"meta_description": "Discover how OpnForm, an open-source form builder, simplifies the creation and management of abstract forms. Collect abstract data effortlessly, streamline your process, and benefit from OpnForm's extensive features. Start building your abstract forms with OpnForm's customizable templates today!",
"description": "Looking for a versatile form builder for your abstract forms? OpnForm has got you covered! With OpnForm's open-source form builder, you can easily create and customize abstract forms tailored to your needs. Collect abstract data effortlessly, streamline your abstract form process, and benefit from OpnForm's extensive features. With email notifications, custom branding, embeddable forms, and integrations with popular tools like Slack and Discord, OpnForm empowers you to create, manage, and analyze abstract form submissions efficiently."
},
"audit_forms": {
"name": "Audit Forms",
"slug": "audit_forms",
"meta_title": "Simplify Your Audits with OpnForm's Audit Form Templates",
"meta_description": "Looking for a hassle-free way to perform audits? Discover OpnForm's Audit Form Templates and streamline your audit process. With OpnForm's open-source form builder, you can easily create customized audit forms, receive email notifications, integrate with other tools, and embed forms on any website. Start simplifying your audits today!",
"description": "Need to perform audits for your business? OpnForm's Audit Form Templates are designed to help you simplify the audit process. With OpnForm, you can easily create custom audit forms tailored to your specific needs. Use our templates as a starting point, customize them with your own questions and sections, and streamline your audit workflow. With features like email notifications, form customization, integration with other tools, and the ability to embed forms on any website, OpnForm is the perfect tool for conducting audits efficiently and effectively."
},
"award_forms": {
"name": "Award Forms",
"slug": "award_forms",
"meta_title": "Simplify Your Award Process with OpnForm's Award Form Templates",
"meta_description": "Looking for a way to streamline your award process? OpnForm's Award Form Templates are designed to help you gather nominations, track submissions, and simplify the selection process. With OpnForm, you can fully customize and brand your award forms, receive email notifications, integrate with other tools, and more. Discover how OpnForm can enhance your award process today!",
"description": "Recognizing excellence in your organization? OpnForm offers Award Form Templates that can simplify the process! These form templates are designed to help you gather nominations, track submissions, and streamline the award selection process. With OpnForm's open-source form builder, you can fully customize and brand your award forms to match your organization's identity. You can also take advantage of features like email notifications, custom domains, form embedding, and integration with tools like Slack and Discord. Explore our award form templates below, customize them to fit your requirements, and see how OpnForm can enhance your award process."
},
"calculation_forms": {
"name": "Calculation Forms",
"slug": "calculation_forms",
"meta_title": "Streamline Your Calculations with OpnForm's Calculation Form Templates",
"meta_description": "Discover the power of OpnForm's Calculation Form Templates to simplify your data analysis and advanced calculations. Customize, integrate, and optimize your calculation forms with our open-source form builder. Explore the features of OpnForm, including email notifications, custom branding, form embedding, and integration with various tools. Upgrade your calculation process with OpnForm today!",
"description": "Are you in need of advanced calculation forms? Look no further than OpnForm! Our Calculation Form Templates are designed for businesses and individuals who require complex calculations and data analysis. With OpnForm, you can easily create and customize calculation forms to suit your needs. Benefit from our open-source form builder, which allows you to fully customize and brand your forms. You can also integrate your calculation forms with various tools, such as Slack and Discord, via Zapier or webhooks. With features like email notifications, custom domain hosting, password protection, and form pre-filling, OpnForm provides a complete solution for all your calculation form needs."
},
"checklist_forms": {
"name": "Checklist Forms",
"slug": "checklist_forms",
"meta_title": "Efficient Task Management with OpnForm's Checklist Form Templates",
"meta_description": "Utilize OpnForm's Checklist Form Templates to streamline your task management process. With OpnForm, easily create, customize, and track your to-do lists or task checklists. Benefit from features like email notifications, custom branding, form embedding, and integrations with tools like Slack and Discord. Secure your forms with passwords and captchas. Explore our checklist form templates and discover how OpnForm can enhance your task organization and efficiency.",
"description": "Managing a to-do list or organizing tasks? OpnForm's Checklist Form Templates are designed to help you stay organized and streamline your workflow. With OpnForm, you can easily create and customize checklist forms, enabling you to track and manage tasks efficiently. Take advantage of OpnForm's email notifications, custom branding, and form embedding capabilities. Integrate your checklist forms with tools like Slack and Discord using Zapier or webhooks. Protect your forms with a password and add a captcha for enhanced security. With OpnForm, you can pre-fill form fields via URL parameters, set deadlines for form submissions, and even allow respondents to edit their own submissions. Explore our checklist form templates below and experience the power of OpnForm in simplifying your task management process."
},
"content_forms": {
"name": "Content Forms",
"slug": "content_forms",
"meta_title": "Boost Your Content Creation with OpnForm's Content Form Templates",
"meta_description": "Discover how OpnForm's Content Form Templates can revolutionize your content creation process. Whether you're running a blog, managing a website, or creating online content, OpnForm provides you with the tools to engage your audience, capture valuable feedback, and gather user-generated content. Start using OpnForm's open-source form builder and templates today!",
"description": "Looking to create engaging and interactive content? OpnForm's Content Form Templates are designed for content creators, bloggers, and website owners who want to gather valuable feedback, opinions, and user-generated content. With OpnForm, you can easily create stunning forms that capture user responses, embed them on your website, and benefit from advanced customization options. Harness the power of OpnForm's open-source form builder to collect data, interact with your audience, and enhance your content creation process."
},
"donation_forms": {
"name": "Donation Forms",
"slug": "donation_forms",
"meta_title": "Collect Donations Easily with OpnForm's Donation Form Templates",
"meta_description": "Looking for a simple and efficient way to collect donations online? Explore OpnForm's Donation Form Templates and discover how you can leverage our open-source form builder to create personalized donation forms, customize them to match your branding, and streamline your fundraising efforts. With features like email notifications, custom domain hosting, and integrations with popular tools like Slack and Zapier, OpnForm is the perfect solution for non-profit organizations seeking to collect donations online.",
"description": "Want to collect donations for your non-profit organization? OpnForm offers Donation Form Templates that make it easy to gather donations online. With OpnForm, you can create personalized donation forms, customize them to match your organization's branding, and collect donations securely. Take advantage of OpnForm's email notifications, custom domain hosting, and integrations with popular tools like Slack and Zapier to streamline your donation collection process. Start using one of our donation form templates below, and see how OpnForm can simplify your fundraising efforts."
},
"employment_forms": {
"name": "Employment Forms",
"slug": "employment_forms",
"meta_title": "Simplify Your Hiring Process with OpnForm's Employment Form Templates",
"meta_description": "OpnForm's Employment Form Templates are designed to help businesses and organizations streamline their hiring process. With features like email notifications, custom branding, and integrations with popular tools, OpnForm makes it easy to collect employment information and find the right candidates for your team.",
"description": "Looking to streamline your hiring process? OpnForm's Employment Form Templates are designed to make it easy for businesses and organizations to collect employment information. With OpnForm's open-source form builder, you can customize and brand your employment forms to match your company's identity. Our templates offer features such as email notifications for both the form owner and the applicant, integration with popular tools like Slack and Discord, and the ability to embed forms on any website. Use OpnForm's Employment Form Templates to simplify your hiring process and find the right candidates for your team."
},
"enrollment_forms": {
"name": "Enrollment Forms",
"slug": "enrollment_forms",
"meta_title": "Streamline Your Enrollment Process with OpnForm's Enrollment Form Templates",
"meta_description": "Discover how OpnForm's Enrollment Form Templates can simplify the enrollment process for educational institutions and training programs. Capture student or participant information easily, customize the forms to fit your needs, and benefit from OpnForm's advanced features like email notifications, branding options, and integrations. Start using OpnForm today and revolutionize your enrollment management!",
"description": "Are you running an educational institution or organizing a training program? OpnForm offers Enrollment Form Templates specifically designed for capturing student or participant information. With OpnForm, you can easily create and customize enrollment forms, streamline the enrollment process, and benefit from our various features. Collect all the necessary details, such as personal information, educational background, and program preferences, using our user-friendly templates. Utilize OpnForm's email notifications, branding options, and integration capabilities to enhance your enrollment management. Start using our Enrollment Form Templates now and enjoy a seamless enrollment experience!"
},
"evaluation_forms": {
"name": "Evaluation Forms",
"slug": "evaluation_forms",
"meta_title": "Revolutionize Performance Evaluation and Feedback Collection with OpnForm",
"meta_description": "Looking for an efficient and user-friendly way to conduct performance evaluations and gather feedback? Discover OpnForm's Evaluation Form Templates! With OpnForm, you can easily create customized and branded evaluation forms, streamline the evaluation process, and benefit from integrations with tools like Slack. Join thousands of satisfied users who have upgraded their performance evaluation and feedback collection processes with OpnForm!",
"description": "Struggling with evaluating employee performance or gathering feedback from customers? OpnForm's Evaluation Form Templates are here to help! Whether you need to conduct performance reviews, collect customer satisfaction surveys, or gather feedback from event attendees, our templates provide the perfect foundation. With OpnForm, you can easily customize and brand your evaluation forms, ensuring they align with your company's identity. Take advantage of our intuitive form builder, email notifications, and integrations with Slack and other tools to streamline the evaluation process. Start using OpnForm's Evaluation Form Templates today and revolutionize how you assess performance and gather feedback!"
},
"feedback_forms": {
"name": "Feedback Forms",
"slug": "feedback_forms",
"meta_title": "Collect Valuable Feedback with OpnForm's Feedback Form Templates",
"meta_description": "Discover how OpnForm's Feedback Form Templates can help you gather valuable feedback from your customers or website visitors. Create customizable feedback forms with OpnForm's open-source form builder. Embed them on your website or share them via a unique link. Take advantage of features like email notifications, form customization, integrations, and more. Start collecting feedback today!",
"description": "Want to gather feedback from your customers or website visitors? OpnForm's Feedback Form Templates are designed to make feedback collection easy! With OpnForm, you can create custom feedback forms that can be embedded on your website or shared via a unique link. Collect valuable feedback, opinions, and suggestions, and improve your products or services. OpnForm's open-source form builder allows you to fully customize your feedback forms and brand them to match your business. You can also take advantage of features like email notifications, form customization, integrations with tools like Slack and Discord, password protection, captcha, custom code, pre-filling forms via URL parameters, form submission editing, and multi-page forms. Start gathering valuable feedback today with OpnForm's Feedback Form Templates!"
},
"inspection_forms": {
"name": "Inspection Forms",
"slug": "inspection_forms",
"meta_title": "Simplify Your Inspections with OpnForm's Inspection Form Templates",
"meta_description": "OpnForm offers a range of Inspection Form Templates that can help you streamline your inspection process. Create customized inspection forms with ease and collect all the necessary data. Discover the benefits of OpnForm's features like email notifications, form customization, and integrations with tools like Slack and Discord. Use OpnForm and its inspection form templates to enhance your inspection workflow.",
"description": "Are you in the business of conducting inspections? OpnForm provides Inspection Form Templates that can simplify the process for you! With OpnForm, you can easily create and customize inspection forms to collect relevant data. Whether you need to conduct safety inspections, property inspections, or any other type of inspection, OpnForm has got you covered. Benefit from features like email notifications, form customization, form embedding, and integrations with tools like Slack and Discord. Explore our inspection form templates below, customize them to fit your specific requirements, and witness how OpnForm streamlines your inspection process."
},
"interview_forms": {
"name": "Interview Forms",
"slug": "interview_forms",
"meta_title": "Simplify Your Hiring Process with OpnForm's Interview Form Templates",
"meta_description": "Discover how OpnForm's Interview Form Templates can help you streamline your hiring process. Collect information from job applicants easily and efficiently with our open-source form builder. Customize your forms, integrate with communication tools, and simplify your workflow. Upgrade your interview process with OpnForm's Interview Form Templates now!",
"description": "Looking to streamline your hiring process? OpnForm offers Interview Form Templates that can help you efficiently collect information from job applicants. With OpnForm's open-source form builder, you can easily create customized interview forms that match your company's unique requirements. Take advantage of features like email notifications, form customization, custom domains, and form embedding to simplify the interview process. Plus, integrate with popular communication tools like Slack and Discord using Zapier or webhooks. Enhance your hiring process with OpnForm's Interview Form Templates today!"
},
"lead_generation_forms": {
"name": "Lead Generation Forms",
"slug": "lead_generation_forms",
"meta_title": "Supercharge Your Lead Generation with OpnForm's Form Templates",
"meta_description": "Discover how OpnForm's Lead Generation Form Templates can help you capture high-quality leads for your business. Create custom forms, host them on your own domain, and receive email notifications for every new lead. Integrate with popular tools and streamline your lead management process. Try OpnForm today for better lead generation!",
"description": "Looking to generate leads for your business? OpnForm's Lead Generation Form Templates are designed to help you do just that! Whether you're a small startup or a large corporation, these templates provide an efficient way to collect valuable information from potential customers. With OpnForm, you can easily create customized lead generation forms, brand them to match your company's identity, and host them on your own domain. Capture leads effortlessly and receive email notifications for every new submission. Take advantage of our integrations with popular tools like Slack and Discord to streamline your lead management process. Enhance your lead generation efforts with OpnForm and start converting more prospects into customers today!"
},
"legal_forms": {
"name": "Legal Forms",
"slug": "legal_forms",
"meta_title": "Simplify Your Legal Processes with OpnForm's Legal Form Templates",
"meta_description": "Need legal forms? OpnForm's open-source form builder and customizable legal form templates can streamline your legal processes. Benefit from features like email notifications, customization options, form embedding, tool integration, and more. Start simplifying your legal document workflow today!",
"description": "Need legal forms? OpnForm provides a range of Legal Form Templates to simplify your legal processes! Whether you need a simple contract, a rental agreement, or a non-disclosure agreement, OpnForm has got you covered. With OpnForm's open-source form builder and our customizable legal form templates, you can easily create and manage legal documents. Benefit from features like email notifications for both form owner and submitter, full customization and branding options, custom domain hosting, form embedding, integration with tools like Slack and Discord, password protection, captchas, custom code, pre-filling via URL parameters, form closure options, the ability for respondents to edit submissions, and support for multiple pages. Discover how OpnForm can revolutionize your legal document workflow!"
},
"membership_forms": {
"name": "Membership Forms",
"slug": "membership_forms",
"meta_title": "Simplify Membership Management with OpnForm Membership Form Templates",
"meta_description": "Streamline your membership management process with OpnForm's Membership Form Templates. Create customized forms, collect member details, and benefit from features like email notifications, form customization, and integrations with other tools. Try OpnForm today!",
"description": "Looking to build a membership form? OpnForm offers Membership Form Templates that can simplify the process of collecting membership details. Whether you run a club, an organization, or any other type of membership-based entity, OpnForm has you covered. With our templates, you can easily create customized membership forms that align with your branding and collect all the necessary information from your members. OpnForm's open-source form builder allows you to fully customize and brand your forms, ensuring a seamless membership form experience. Additionally, you can benefit from features such as email notifications for both the form owner and the submitter, integration with various tools via Zapier or webhooks, and the option to protect your forms with a password. Start building your membership form today and see how OpnForm can elevate your membership management process!"
},
"petition_forms": {
"name": "Petition Forms",
"slug": "petition_forms",
"meta_title": "Powerful Petition Form Templates for Your Cause | OpnForm",
"meta_description": "Create impactful petition forms with OpnForm's Petition Form Templates. Customize the design, protect the form, and integrate with tools like Slack or Discord. Gather signatures and support for your cause easily with OpnForm.",
"description": "Are you trying to make a difference and rally support for a cause? OpnForm's Petition Form Templates are designed to help you gather signatures and support for your petition. By using our easy-to-use form builder, you can create impactful and professional petition forms in minutes. Customize the design and branding, protect the form with a password, and integrate it with tools like Slack or Discord. With OpnForm, you can amplify your message and gain momentum for your cause."
},
"polls": {
"name": "Polls",
"slug": "polls",
"meta_title": "Discover the Power of Poll Form Templates with OpnForm",
"meta_description": "Looking to gather opinions or insights from your audience? Learn how OpnForm's Poll Form Templates can help you create engaging polls, customize them to match your brand, and gain valuable insights. Harness the power of OpnForm's open-source form builder and start creating interactive polls today!",
"description": "Running a blog or website and want to engage your audience? OpnForm offers Poll Form Templates that make it easy for you to create interactive polls and gather valuable insights. With OpnForm, you can customize your poll forms to match your brand, embed them on your site, and leverage features such as multiple pages and custom code integration. Engage your readers, collect valuable data, and enhance your content strategy with OpnForm's Poll Form Templates!"
},
"quiz_forms": {
"name": "Quiz Forms",
"slug": "quiz_forms",
"meta_title": "Create Engaging Quizzes with OpnForm's Quiz Form Templates",
"meta_description": "Looking for a user-friendly and customizable solution to create quizzes? OpnForm's Quiz Form Templates offer educators, trainers, and businesses the perfect tool. With email notifications, easy embedding, and integration options, OpnForm and our templates simplify the quiz creation process. Discover how you can streamline your assessments with OpnForm!",
"description": "Need to create engaging quizzes? OpnForm offers Quiz Form Templates that are perfect for educators, trainers, and businesses looking to assess knowledge and gather data. With OpnForm's open-source form builder, you can easily create interactive quiz forms, customize them to fit your branding, and harness powerful features to enhance your quiz-taking experience. Enjoy email notifications, seamless form embedding, integration with various tools, and the ability to protect your quizzes with passwords. Take your quizzes to the next level with OpnForm!"
},
"quote_forms": {
"name": "Quote Forms",
"slug": "quote_forms",
"meta_title": "Streamline Your Quote Collection Process with OpnForm",
"meta_description": "OpnForm is an open-source form builder that offers Quote Form Templates to simplify the process of gathering quotes. With features like email notifications, full customization options, and integrations with popular tools, OpnForm makes it easy to streamline your quote collection process. Try OpnForm and our templates today!",
"description": "Are you in need of a quick and easy way to gather quotes? OpnForm provides Quote Form Templates that can simplify the process for you! Whether you're a business owner looking to get quotes from potential vendors or a contractor gathering quotes from clients, OpnForm has got you covered. With our open-source form builder, you can easily create and customize quote forms to suit your specific needs. Benefit from features like email notifications, full customization options, embedding forms on any website, and integrations with popular tools like Slack and Discord. Start streamlining your quote collection process today!"
},
"recommendation_forms": {
"name": "Recommendation Forms",
"slug": "recommendation_forms",
"meta_title": "Effortless Recommendation Forms with OpnForm",
"meta_description": "Discover how OpnForm can simplify the process of collecting recommendations. With a wide range of customizable Recommendation Form Templates, OpnForm offers an open-source form builder with features like email notifications, branding options, integration with popular tools, and more. Start using OpnForm to streamline your recommendation process today!",
"description": "Looking for a reliable recommendation form solution? OpnForm offers a range of Recommendation Form Templates designed to make your recommendation process seamless. Whether you need to collect recommendations for products, services, or professionals, OpnForm has you covered. With OpnForm's open-source form builder, you can easily create and customize recommendation forms to suit your needs. Benefit from features like email notifications, fully customizable branding, and the ability to embed forms on any website. Integrate with popular tools like Slack or Discord through Zapier or webhooks. Ensure the security of your recommendation forms with password protection and captcha. Use OpnForm's custom code feature to enhance your forms further. Pre-fill forms via URL parameters, set form closing dates, or limit submissions as needed. Respondents can even edit their own submissions with OpnForm's multiple page functionality."
},
"report_forms": {
"name": "Report Forms",
"slug": "report_forms",
"meta_title": "Simplify Your Reporting with OpnForm's Report Form Templates",
"meta_description": "Discover how OpnForm and our Report Form Templates can revolutionize your reporting process. Customize and brand your report forms, receive instant email notifications, and streamline your workflow. Find the perfect template for your needs and start reporting with ease today!",
"description": "Are you in need of a simple and efficient way to collect reports? OpnForm's Report Form Templates are here to help! Whether you're a manager, supervisor, or team leader, these templates are designed to streamline the reporting process. With OpnForm, you can easily customize and brand your forms, receive instant email notifications for every submission, and even integrate the forms with tools like Slack or Discord. Simply choose a report form template below, customize it to fit your needs, and experience the convenience of OpnForm for all your reporting needs."
},
"request_forms": {
"name": "Request Forms",
"slug": "request_forms",
"meta_title": "Efficiently Manage Requests with OpnForm's Request Form Templates",
"meta_description": "Discover how OpnForm's Request Form Templates can simplify your process of collecting requests. Customize the templates to fit your needs, receive email notifications, integrate with other tools, and streamline your request management with OpnForm.",
"description": "Need to collect requests and gather information efficiently? OpnForm offers Request Form Templates that can streamline the process! These templates are designed for individuals, businesses, and organizations looking to manage incoming requests. With OpnForm, you can easily customize these templates, collect data securely, and benefit from various features like email notifications, form customization, integrations with Slack and other tools, and much more. Start using OpnForm's Request Form Templates today and simplify the way you handle requests!"
},
"reservation_forms": {
"name": "Reservation Forms",
"slug": "reservation_forms",
"meta_title": "Simplify Your Reservation Management with OpnForm",
"meta_description": "Looking for an easy way to manage reservations? Discover how OpnForm's Reservation Form Templates can streamline your booking process. Customize your form, collect reservation details, and leverage powerful features like email notifications, embeddable forms, and integrations with popular tools. Upgrade your reservation management with OpnForm now!",
"description": "Planning an event or managing bookings? OpnForm offers Reservation Form Templates to simplify the process! Whether you run a hotel, a restaurant, or any other business that requires reservations, OpnForm has got you covered. With our templates, you can easily collect reservation details, streamline your booking process, and benefit from OpnForm's powerful features. Customize your reservation form to match your branding, embed it on your website, and leverage our integrations with tools like Slack and Discord via Zapier or webhooks. Take advantage of features like email notifications, form customization, password protection, and more. Upgrade your reservation management with OpnForm today!"
},
"sponsorship_forms": {
"name": "Sponsorship Forms",
"slug": "sponsorship_forms",
"meta_title": "Simplify Sponsorship Management with OpnForm's Templates",
"meta_description": "OpnForm's Sponsorship Form Templates are the ultimate solution for event organizers, non-profits, and businesses seeking sponsorships. Create customized forms, streamline the application process, and leverage OpnForm's features such as branding, email notifications, integrations, and more. Explore the power of OpnForm today!",
"description": "Looking for a hassle-free way to manage sponsorships? OpnForm's Sponsorship Form Templates are designed to simplify the process! These templates are targeted at event organizers, non-profit organizations, and businesses seeking sponsorships. With OpnForm, you can easily create custom sponsorship forms tailored to your needs. Collect important information from potential sponsors, streamline your sponsorship application process, and enjoy the benefits of OpnForm's powerful features. Customize your form's branding, protect it with a password, and even embed it on your website. With email notifications, you'll stay updated on new submissions, while respondents receive confirmation emails. OpnForm also offers integrations with popular tools like Slack, Discord, and more, enabling seamless communication and automation. Discover the possibilities of OpnForm's Sponsorship Form Templates today!"
},
"subscription_forms": {
"name": "Subscription Forms",
"slug": "subscription_forms",
"meta_title": "Supercharge Your Subscriptions with OpnForm",
"meta_description": "Streamline your subscription process with OpnForm's Subscription Form Templates. Collect subscription information easily, customize your forms, and benefit from OpnForm's integrations. Choose a template, make it your own, and see how OpnForm can simplify your subscription management.",
"description": "Looking to gather subscriptions? OpnForm's Subscription Form Templates are perfect for anyone who needs to collect subscription information easily and efficiently. Whether you're running a newsletter, membership site, or online service, OpnForm has the tools you need. With features like email notifications, custom branding, and integrations with popular tools, OpnForm can help you streamline your subscription process. Choose a template below, customize it to your needs, and see how OpnForm can simplify your subscription management."
},
"summer_camp_surveys": {
"name": "Summer Camp Surveys",
"slug": "summer_camp_surveys",
"meta_title": "Upgrade Your Summer Camp Surveys with OpnForm!",
"meta_description": "If you're an organizer looking to improve your summer camp experience, OpnForm is here to help! Our open-source form builder provides Summer Camp Survey Form Templates that can make collecting feedback a breeze. With OpnForm, you can easily customize and embed these survey forms on your camp's website. Take advantage of features like email notifications and custom domains to streamline your survey process. Upgrade your summer camp surveys today with OpnForm!",
"description": "Planning a summer camp and need to gather feedback? OpnForm offers Summer Camp Survey Form Templates that can simplify your work! These templates are designed specifically for summer camp organizers to collect valuable feedback from parents and campers. With OpnForm, you can easily create and customize these survey forms to fit your camp's unique needs. Take advantage of OpnForm's features like email notifications, form customization, custom domains, and form embedding to streamline your survey process. Upgrade your summer camp surveys today with OpnForm!"
},
"telecommuting_forms": {
"name": "Telecommuting Forms",
"slug": "telecommuting_forms",
"meta_title": "Streamline Telecommuting with OpnForm's Templates",
"meta_description": "Transitioning to telecommuting? Discover OpnForm's Telecommuting Form Templates and simplify the process. Customize your forms, collect vital information, and streamline communication. Benefit from OpnForm's features like email notifications, form branding, and integration with collaboration tools such as Slack and Discord. Upgrade your telecommuting experience with OpnForm!",
"description": "Are you transitioning your workforce to telecommuting? OpnForm offers Telecommuting Form Templates that can simplify the process! With these form templates, you can easily collect information from your employees, streamline communication, and ensure a smooth transition to remote work. OpnForm, an open-source form builder, provides features such as customizable forms, email notifications, form branding, and integration with collaboration tools like Slack and Discord. Use our Telecommuting Form Templates to gather essential information, communicate effectively, and leverage OpnForm's powerful features to facilitate seamless telecommuting."
},
"tracking_forms": {
"name": "Tracking Forms",
"slug": "tracking_forms",
"meta_title": "Simplify Tracking with OpnForm's Tracking Form Templates",
"meta_description": "Looking for a simple and efficient way to track shipments and packages? Discover OpnForm's Tracking Form Templates and see how you can leverage our open-source form builder and customizable templates to streamline your tracking process.",
"description": "Need to track shipments or packages? OpnForm offers Tracking Form Templates that make it easy to monitor and manage your tracking information. With OpnForm, you can create customized forms to collect tracking details, streamline your tracking process, and benefit from our integration capabilities. Use a tracking form template below, tailor it to your specific needs, and discover how OpnForm can enhance your tracking workflow."
},
"voting_forms": {
"name": "Voting Forms",
"slug": "voting_forms",
"meta_title": "Streamline Your Voting Process with OpnForm's Voting Form Templates",
"meta_description": "Find the perfect solution for your voting needs with OpnForm's Voting Form Templates. Create customizable forms to collect votes, opinions, and feedback easily. Discover the power of OpnForm's open-source form builder, email notifications, form embedding, custom domains, integrations, security features, and more!",
"description": "Looking to collect votes and opinions? OpnForm's Voting Form Templates are here to help! Whether you're running an election, conducting a survey, or seeking feedback, OpnForm provides user-friendly templates that simplify the voting process. With OpnForm's open-source form builder, you can fully customize and brand your voting forms. Take advantage of features like email notifications, form embedding, custom domains, and integrations with popular tools like Slack and Discord via Zapier or webhooks. Ensure the security of your voting forms with password protection and captchas. Plus, you can pre-fill forms, set submission limits, allow respondents to edit their submissions, and even create multi-page forms. Discover how OpnForm can enhance your voting experience today!"
},
"wedding_forms": {
"name": "Wedding Forms",
"slug": "wedding_forms",
"meta_title": "Simplify Your Wedding Planning with OpnForm's Wedding Form Templates",
"meta_description": "OpnForm's Wedding Form Templates make wedding planning a breeze! Collect RSVPs, manage guest details, and send out wedding invitations effortlessly. Customize your forms, protect them with passwords, and embed them on your wedding website. Get started with OpnForm and make your wedding planning experience a memorable one.",
"description": "Planning a wedding has never been easier! OpnForm's Wedding Form Templates are designed specifically for those organizing their special day. With OpnForm, you can effortlessly collect RSVPs, manage guest details, and send out wedding invitations. Our form builder offers a range of features to enhance your wedding planning experience. Customize your forms to match your wedding theme, protect them with passwords, and embed them on your wedding website. Plus, with OpnForm's email notifications, you'll never miss a response. Start simplifying your wedding planning process with OpnForm's Wedding Form Templates today!"
},
"volunteer_forms": {
"name": "Volunteer Forms",
"slug": "volunteer_forms",
"meta_title": "Simplify Volunteer Recruitment with OpnForm's Volunteer Form Templates",
"meta_description": "OpnForm's Volunteer Form Templates are the perfect solution for organizations seeking to simplify their volunteer recruitment process. With OpnForm's open-source form builder, you can easily create personalized volunteer forms, customize and brand them to match your organization's identity, and benefit from powerful features like email notifications, integration with popular tools, form protection, and more. Discover how OpnForm can help you streamline your volunteer recruitment today!",
"description": "Looking to recruit volunteers? OpnForm offers Volunteer Form Templates that can make the process easier for you! These form templates are designed to help you gather information from potential volunteers, streamline your volunteer recruitment process, and benefit from OpnForm's powerful features. Customize and brand your forms, receive email notifications for new volunteer submissions, integrate with tools like Slack and Discord, and even protect your forms with a password. With OpnForm, you can create engaging and user-friendly volunteer forms that will make it simple for candidates to apply and for you to manage applications."
}
}

View File

@ -1,22 +1,61 @@
<template>
<div class="breadcrumbs flex">
<div v-for="(item,index) in path" :key="item.label" class="flex items-center">
<router-link v-if="item.route" class="p-1 hover:bg-blue-50 rounded-md" :to="item.route">
{{ item.label }}
</router-link>
<div v-else class="p-1" :class="{'font-semibold': index===path.length-1}">
{{ item.label }}
</div>
<div v-if="index!==path.length-1">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
<section class="sticky flex items-center inset-x-0 top-0 z-20 py-3 bg-white border-b border-gray-200">
<div class="hidden md:flex flex-grow">
<slot name="left" />
</div>
<div class="px-4 mx-auto sm:px-6 lg:px-8 max-w-7xl">
<div class="flex items-center justify-center space-x-4">
<div v-if="displayHome" class="flex items-center">
<router-link class="text-gray-400 hover:text-gray-500" :to="{ name: (authenticated) ? 'home' : 'welcome' }">
<svg class="flex-shrink-0 w-5 h-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd"
d="M9.293 2.293a1 1 0 011.414 0l7 7A1 1 0 0117 11h-1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-3a1 1 0 00-1-1H9a1 1 0 00-1 1v3a1 1 0 01-1 1H5a1 1 0 01-1-1v-6H3a1 1 0 01-.707-1.707l7-7z"
clip-rule="evenodd"
/>
</svg>
<span class="sr-only">Home</span>
</router-link>
<svg class="flex-shrink-0 w-5 h-5 text-gray-400 ml-4" viewBox="0 0 20 20" fill="currentColor"
aria-hidden="true"
>
<path fill-rule="evenodd"
d="M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z"
clip-rule="evenodd"
/>
</svg>
</div>
<div v-for="(item,index) in path" :key="index" class="flex items-center">
<router-link v-if="item.route" class="text-sm font-semibold text-gray-500 hover:text-gray-700 truncate"
:to="item.route"
>
{{ item.label }}
</router-link>
<div v-else class="text-sm font-semibold sm:w-full w-36 text-blue-500 truncate">
{{ item.label }}
</div>
<div v-if="index!==path.length-1">
<svg class="flex-shrink-0 w-5 h-5 text-gray-400 ml-4" viewBox="0 0 20 20" fill="currentColor"
aria-hidden="true"
>
<path fill-rule="evenodd"
d="M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z"
clip-rule="evenodd"
/>
</svg>
</div>
</div>
</div>
</div>
</div>
<div class="hidden md:flex flex-grow justify-end">
<slot name="right" />
</div>
</section>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
name: 'Breadcrumb',
props: {
@ -28,10 +67,16 @@ export default {
},
data () {
return {}
return {
displayHome: true
}
},
computed: {},
computed: {
...mapGetters({
authenticated: 'auth/check'
})
},
mounted () {
},

View File

@ -0,0 +1,182 @@
<template>
<modal :show="show" @close="$emit('close')">
<template #icon>
<svg class="w-10 h-10 text-blue" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M17 27C16.0681 27 15.6022 27 15.2346 26.8478C14.7446 26.6448 14.3552 26.2554 14.1522 25.7654C14 25.3978 14 24.9319 14 24V17.2C14 16.0799 14 15.5198 14.218 15.092C14.4097 14.7157 14.7157 14.4097 15.092 14.218C15.5198 14 16.0799 14 17.2 14H24C24.9319 14 25.3978 14 25.7654 14.1522C26.2554 14.3552 26.6448 14.7446 26.8478 15.2346C27 15.6022 27 16.0681 27 17M24.2 34H30.8C31.9201 34 32.4802 34 32.908 33.782C33.2843 33.5903 33.5903 33.2843 33.782 32.908C34 32.4802 34 31.9201 34 30.8V24.2C34 23.0799 34 22.5198 33.782 22.092C33.5903 21.7157 33.2843 21.4097 32.908 21.218C32.4802 21 31.9201 21 30.8 21H24.2C23.0799 21 22.5198 21 22.092 21.218C21.7157 21.4097 21.4097 21.7157 21.218 22.092C21 22.5198 21 23.0799 21 24.2V30.8C21 31.9201 21 32.4802 21.218 32.908C21.4097 33.2843 21.7157 33.5903 22.092 33.782C22.5198 34 23.0799 34 24.2 34Z"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
/>
</svg>
</template>
<template #title>
<template v-if="template">
Edit Template
</template>
<template v-else>
Create Template
</template>
</template>
<div class="p-4">
<p v-if="!template">
New template will be create from your form <span class="font-semibold">{{ form.title }}</span>.
</p>
<form v-if="templateForm" class="mt-6" @submit.prevent="onSubmit" @keydown="templateForm.onKeydown($event)">
<div class="-m-6">
<div class="border-t py-4 px-6">
<toggle-switch-input name="publicly_listed" :form="templateForm" class="mt-4" label="Publicly Listed?" />
<text-input name="name" :form="templateForm" class="mt-4" label="Title" :required="true" />
<text-input name="slug" :form="templateForm" class="mt-4" label="Slug" :required="true" />
<text-area-input name="short_description" :form="templateForm" class="mt-4" label="Short Description"
:required="true"
/>
<rich-text-area-input name="description" :form="templateForm" class="mt-4" label="Description"
:required="true"
/>
<text-input name="image_url" :form="templateForm" class="mt-4" label="Image" :required="true" />
<select-input name="types" :form="templateForm" class="mt-4" label="Types" :options="typesOptions"
:multiple="true" :searchable="true"
/>
<select-input name="industries" :form="templateForm" class="mt-4" label="Industries"
:options="industriesOptions" :multiple="true" :searchable="true"
/>
<select-input name="related_templates" :form="templateForm" class="mt-4" label="Related Templates"
:options="templatesOptions" :multiple="true" :searchable="true"
/>
<questions-editor name="questions" :questions="templateForm.questions" class="mt-4"
label="Frequently asked questions"
/>
</div>
<div class="flex justify-end mt-4 pb-5 px-6">
<v-button class="mr-2" :loading="templateForm.busy">
<template v-if="template">
Update
</template>
<template v-else>
Create
</template>
</v-button>
<v-button v-if="template" color="red" class="mr-2"
@click.prevent="alertConfirm('Do you really want to delete this template?', deleteFormTemplate)"
>
Delete
</v-button>
<v-button color="white" @click.prevent="$emit('close')">
Close
</v-button>
</div>
</div>
</form>
</div>
</modal>
</template>
<script>
import Form from 'vform'
import store from '~/store'
import { mapState } from 'vuex'
import axios from 'axios'
import QuestionsEditor from './QuestionsEditor.vue'
export default {
name: 'FormTemplateModal',
components: { QuestionsEditor },
props: {
show: { type: Boolean, required: true },
form: { type: Object, required: true },
template: { type: Object, required: false, default: () => {} }
},
data: () => ({
templateForm: null
}),
mounted () {
this.templateForm = new Form(this.template ?? {
publicly_listed: true,
name: '',
slug: '',
short_description: '',
description: '',
image_url: '',
types: null,
industries: null,
related_templates: null,
questions: []
})
store.dispatch('open/templates/loadIfEmpty')
},
computed: {
...mapState({
templates: state => state['open/templates'].content,
industries: state => state['open/templates'].industries,
types: state => state['open/templates'].types
}),
typesOptions () {
return Object.values(this.types).map((type) => {
return {
name: type.name,
value: type.slug
}
})
},
industriesOptions () {
return Object.values(this.industries).map((industry) => {
return {
name: industry.name,
value: industry.slug
}
})
},
templatesOptions () {
return this.templates.map((template) => {
return {
name: template.name,
value: template.slug
}
})
}
},
methods: {
onSubmit () {
if (this.template) {
this.updateFormTemplate()
} else {
this.createFormTemplate()
}
},
async createFormTemplate () {
this.templateForm.form = this.form
await this.templateForm.post('/api/templates').then((response) => {
if (response.data.message) {
this.alertSuccess(response.data.message)
}
this.$emit('close')
})
},
async updateFormTemplate () {
this.templateForm.form = this.form
await this.templateForm.put('/api/templates/' + this.template.id).then((response) => {
if (response.data.message) {
this.alertSuccess(response.data.message)
}
this.$store.dispatch('open/templates/addOrUpdate', response.data.data)
this.$emit('close')
})
},
async deleteFormTemplate () {
if (!this.template) return
axios.delete('/api/templates/' + this.template.id).then((response) => {
if (response.data.message) {
this.alertSuccess(response.data.message)
}
this.$router.push({ name: 'templates' })
this.$store.dispatch('open/templates/remove', response.data.data)
this.$emit('close')
})
}
}
}
</script>

View File

@ -0,0 +1,77 @@
<template>
<div :class="wrapperClass">
<label v-if="label" :for="id?id:name"
:class="[theme.default.label,{'uppercase text-xs':uppercaseLabels, 'text-sm':!uppercaseLabels}]"
>
{{ label }}
<span v-if="required" class="text-red-500 required-dot">*</span>
</label>
<loader v-if="loading" key="loader" class="h-6 w-6 text-nt-blue mx-auto" />
<div v-else class="my-3">
<div v-for="(questionForm, quesKey) in allQuestions" :key="quesKey" class="bg-gray-100 p-2 mb-4">
<v-button color="red" size="small" class="mb-2" @click.prevent="onRemove(quesKey)">
<svg class="h-4 w-4 text-white inline mr-1 -mt-1" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 6H5M5 6H21M5 6V20C5 20.5304 5.21071 21.0391 5.58579 21.4142C5.96086 21.7893 6.46957 22 7 22H17C17.5304 22 18.0391 21.7893 18.4142 21.4142C18.7893 21.0391 19 20.5304 19 20V6H5ZM8 6V4C8 3.46957 8.21071 2.96086 8.58579 2.58579C8.96086 2.21071 9.46957 2 10 2H14C14.5304 2 15.0391 2.21071 15.4142 2.58579C15.7893 2.96086 16 3.46957 16 4V6M10 11V17M14 11V17" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
Remove
</v-button>
<text-input name="question" :form="questionForm" placeholder="Question title" />
<rich-text-area-input name="answer" :form="questionForm" class="mt-4" placeholder="Question response" />
</div>
<v-button v-if="addNew" color="green" size="small" nativeType="button" class="mt-2 flex" @click.prevent="onAdd">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 mr-1 inline" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v6m3-3H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
Add New
</v-button>
</div>
<small v-if="help" :class="theme.SelectInput.help">
<slot name="help">{{ help }}</slot>
</small>
<has-error v-if="hasValidation" :form="form" :field="name" />
</div>
</template>
<script>
import inputMixin from '~/mixins/forms/input.js'
export default {
name: 'QuestionsEditor',
mixins: [inputMixin],
props: {
loading: { type: Boolean, default: false },
addNew: { type: Boolean, default: true },
questions: { type: Array, default: [] },
},
data () {
return {
allQuestions: null,
newQuestion: {
question: '',
answer: '',
}
}
},
mounted () {
this.allQuestions = (this.questions.length > 0) ? this.questions : [this.newQuestion]
},
watch: { },
computed: { },
methods: {
onAdd() {
this.allQuestions.push(this.newQuestion)
},
onRemove(key){
this.allQuestions.splice(key, 1)
}
}
}
</script>

View File

@ -1,70 +0,0 @@
<template>
<modal :show="show" @close="$emit('close')">
<template #icon>
<svg class="w-10 h-10 text-blue" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17 27C16.0681 27 15.6022 27 15.2346 26.8478C14.7446 26.6448 14.3552 26.2554 14.1522 25.7654C14 25.3978 14 24.9319 14 24V17.2C14 16.0799 14 15.5198 14.218 15.092C14.4097 14.7157 14.7157 14.4097 15.092 14.218C15.5198 14 16.0799 14 17.2 14H24C24.9319 14 25.3978 14 25.7654 14.1522C26.2554 14.3552 26.6448 14.7446 26.8478 15.2346C27 15.6022 27 16.0681 27 17M24.2 34H30.8C31.9201 34 32.4802 34 32.908 33.782C33.2843 33.5903 33.5903 33.2843 33.782 32.908C34 32.4802 34 31.9201 34 30.8V24.2C34 23.0799 34 22.5198 33.782 22.092C33.5903 21.7157 33.2843 21.4097 32.908 21.218C32.4802 21 31.9201 21 30.8 21H24.2C23.0799 21 22.5198 21 22.092 21.218C21.7157 21.4097 21.4097 21.7157 21.218 22.092C21 22.5198 21 23.0799 21 24.2V30.8C21 31.9201 21 32.4802 21.218 32.908C21.4097 33.2843 21.7157 33.5903 22.092 33.782C22.5198 34 23.0799 34 24.2 34Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</template>
<template #title>
Create template
</template>
<div class="p-4">
<p>
New template will be create from your form <span class="font-semibold">{{form.title}}</span>.
Template will be public for all to create form quickly.
</p>
<form @submit.prevent="createTemplate" @keydown="templateForm.onKeydown($event)" class="mt-6">
<div class="-m-6">
<div class="border-t py-4 px-6">
<text-input name="name" :form="templateForm" class="mt-4" label="Title" :required="true" />
<text-input name="slug" :form="templateForm" class="mt-4" label="Slug" :required="true" />
<rich-text-area-input name="description" :form="templateForm" class="mt-4" label="Description" :required="true" />
<text-input name="image_url" :form="templateForm" class="mt-4" label="Image" :required="true" />
<questions-editor name="questions" :form="templateForm" class="mt-4" label="Frequently asked questions" />
</div>
<div class="flex justify-end mt-4 pb-5 px-6">
<v-button class="mr-2" :loading="templateForm.busy">Create</v-button>
<v-button color="white" @click.prevent="$emit('close')">Close</v-button>
</div>
</div>
</form>
</div>
</modal>
</template>
<script>
import Form from 'vform'
import QuestionsEditor from '../../templates/QuestionsEditor.vue';
export default {
name: 'CreateTemplateModal',
components: { QuestionsEditor },
props: {
show: { type: Boolean, required: true },
form: { type: Object, required: true }
},
data: () => ({
templateForm: new Form({
name: '',
slug: '',
description: '',
image_url: '',
})
}),
computed: {},
methods: {
async createTemplate() {
this.templateForm.form = this.form
await this.templateForm.post('/api/templates').then((response) => {
this.alertSuccess('Template was successfully created.')
this.$emit('close')
});
}
}
}
</script>

View File

@ -69,7 +69,7 @@
</a>
<a href="#" v-if="user.template_editor"
class="block block px-4 py-2 text-md text-gray-700 dark:text-white hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600 flex items-center"
@click.prevent="showCreateTemplateModal=true"
@click.prevent="showFormTemplateModal=true"
>
<svg class="w-4 h-4 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke="currentColor" stroke-width="2">
@ -117,7 +117,7 @@
</div>
</modal>
<create-template-modal :form="form" :show="showCreateTemplateModal" @close="showCreateTemplateModal=false"/>
<form-template-modal :form="form" :show="showFormTemplateModal" @close="showFormTemplateModal=false"/>
</div>
</template>
@ -125,11 +125,11 @@
import axios from 'axios'
import {mapGetters, mapState} from 'vuex'
import Dropdown from '../../../common/Dropdown.vue'
import CreateTemplateModal from '../CreateTemplateModal.vue'
import FormTemplateModal from '../../../open/forms/components/templates/FormTemplateModal.vue'
export default {
name: 'ExtraMenu',
components: { Dropdown, CreateTemplateModal },
components: { Dropdown, FormTemplateModal },
props: {
form: { type: Object, required: true },
isMainPage: { type: Boolean, required: false, default: false }
@ -139,7 +139,7 @@ export default {
loadingDuplicate: false,
loadingDelete: false,
showDeleteFormModal: false,
showCreateTemplateModal: false
showFormTemplateModal: false
}),
computed: {

View File

@ -0,0 +1,80 @@
<template>
<div v-if="template" class="relative group">
<div v-if="template.is_new" class="absolute top-0 right-0 p-3 z-10">
<span
class="inline-flex items-center gap-1 rounded-full bg-blue-500 px-2 py-1 text-xs font-medium text-white"
>
<svg aria-hidden="true" class="h-3 w-3" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"
fill="currentColor"
>
<path fill-rule="evenodd"
d="M5 2a1 1 0 011 1v1h1a1 1 0 010 2H6v1a1 1 0 01-2 0V6H3a1 1 0 010-2h1V3a1 1 0 011-1zm0 10a1 1 0 011 1v1h1a1 1 0 110 2H6v1a1 1 0 11-2 0v-1H3a1 1 0 110-2h1v-1a1 1 0 011-1zM12 2a1 1 0 01.967.744L14.146 7.2 17.5 9.134a1 1 0 010 1.732l-3.354 1.935-1.18 4.455a1 1 0 01-1.933 0L9.854 12.8 6.5 10.866a1 1 0 010-1.732l3.354-1.935 1.18-4.455A1 1 0 0112 2z"
clip-rule="evenodd"
/>
</svg>
New
</span>
</div>
<div class="aspect-[4/3] rounded-lg shadow-sm overflow-hidden">
<img class="group-hover:scale-110 transition-all duration-200 h-full object-cover w-full"
:src="template.image_url" alt=""
>
</div>
<p
class="text-lg font-semibold leading-tight tracking-tight text-gray-900 mt-4 group-hover:text-blue-500 transition-all duration-150"
>
{{ template.name }}
</p>
<p class="line-clamp-2 mt-2 text-sm font-normal text-gray-600">
{{ cleanQuotes(template.short_description) }}
</p>
<template-tags :slug="template.slug"
class="flex mt-4 items-center flex-wrap gap-3"
/>
<router-link :to="{params:{slug:template.slug},name:'templates.show'}" title="">
<span class="absolute inset-0" aria-hidden="true" />
</router-link>
</div>
</template>
<script>
import store from '~/store'
import TemplateTags from './TemplateTags.vue'
export default {
components: { TemplateTags },
props: {
slug: {
type: String,
required: true
}
},
data: () => ({}),
computed: {
template () {
return this.$store.getters['open/templates/getBySlug'](this.slug)
}
},
watch: {
slug () {
store.dispatch('open/templates/loadTemplate', this.slug)
}
},
mounted () {
store.dispatch('open/templates/loadTemplate', this.slug)
},
methods: {
cleanQuotes (str) {
// Remove starting and ending quotes if any
return (str) ? str.replace(/^"/, '').replace(/"$/, '') : ''
}
}
}
</script>

View File

@ -0,0 +1,74 @@
<template>
<div v-if="template">
<template v-if="displayAll">
<span v-if="template.is_new"
class="inline-flex items-center gap-1 px-2 py-1 text-xs font-medium text-white bg-blue-500 rounded-full"
>
<svg aria-hidden="true" class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"
fill="currentColor"
>
<path fill-rule="evenodd"
d="M5 2a1 1 0 011 1v1h1a1 1 0 010 2H6v1a1 1 0 01-2 0V6H3a1 1 0 010-2h1V3a1 1 0 011-1zm0 10a1 1 0 011 1v1h1a1 1 0 110 2H6v1a1 1 0 11-2 0v-1H3a1 1 0 110-2h1v-1a1 1 0 011-1zM12 2a1 1 0 01.967.744L14.146 7.2 17.5 9.134a1 1 0 010 1.732l-3.354 1.935-1.18 4.455a1 1 0 01-1.933 0L9.854 12.8 6.5 10.866a1 1 0 010-1.732l3.354-1.935 1.18-4.455A1 1 0 0112 2z"
clip-rule="evenodd"
/>
</svg>
New
</span>
<span v-for="item in types"
class="inline-flex items-center rounded-full bg-gray-50 dark:bg-gray-800 dark:text-gray-400 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10"
>
{{ item }}
</span>
<span v-for="item in industries"
class="inline-flex items-center rounded-full bg-blue-50 dark:bg-blue-900 dark:text-gray-400 px-2 py-1 text-xs font-medium text-blue-700 ring-1 ring-inset ring-blue-700/10"
>
{{ item }}
</span>
</template>
<template v-else>
<span v-if="types.length > 0"
class="inline-flex items-center rounded-full bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10"
>
{{ types[0] }} <template v-if="types.length > 1">+{{ types.length - 1 }}</template>
</span>
<span v-if="industries.length > 0"
class="inline-flex items-center rounded-full bg-blue-50 px-2 py-1 text-xs font-medium text-blue-700 ring-1 ring-inset ring-blue-700/10"
>
{{ industries[0] }} <template v-if="industries.length > 1">+{{ industries.length - 1 }}</template>
</span>
</template>
</div>
</template>
<script>
export default {
props: {
slug: {
type: String,
required: true
},
displayAll: {
type: Boolean,
default: false
}
},
data: () => ({}),
computed: {
template () {
return this.$store.getters['open/templates/getBySlug'](this.slug)
},
types () {
if (!this.template) return null
return this.$store.getters['open/templates/getTemplateTypes'](this.template.types)
},
industries () {
if (!this.template) return null
return this.$store.getters['open/templates/getTemplateIndustries'](this.template.industries)
}
},
methods: {}
}
</script>

View File

@ -0,0 +1,70 @@
<template>
<div class="mx-auto mb-12 max-w-7xl px-6 lg:px-8">
<div class="mx-auto max-w-2xl text-center">
<h2 class="text-lg font-semibold leading-8 tracking-tight text-blue-500 ">Single or multi-page forms</h2>
<p class="mt-2 text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl">Discover our beautiful templates</p>
<p class="mt-3 px-8 text-center text-lg text-gray-400 ">If you need inspiration, checkout our templates.</p>
</div>
<div class="my-3 flex justify-center">
<router-link :to="{name:'templates'}">
See all templates
<svg class="h-4 w-4 inline" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd"
d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z"
clip-rule="evenodd"
/>
</svg>
</router-link>
</div>
<div v-if="templates.length > 0"
class="w-full inline-flex flex-nowrap overflow-hidden [mask-image:_linear-gradient(to_right,transparent_0,_black_128px,_black_calc(100%-128px),transparent_100%)]"
>
<ul ref="templates-slider" class="flex justify-center md:justify-start animate-infinite-scroll">
<li v-for="(template, i) in templates" :key="template.id" class="mx-4 w-72 h-auto">
<single-template :slug="template.slug" />
</li>
</ul>
</div>
</div>
</template>
<script>
import store from '~/store'
import { mapGetters, mapState } from 'vuex'
import SingleTemplate from '../templates/SingleTemplate.vue'
export default {
components: { SingleTemplate },
props: { },
data: () => ({}),
computed: {
...mapState({
templates: state => state['open/templates'].content
})
},
watch: {
templates () {
this.$nextTick(() => {
this.setInfinite()
})
}
},
mounted() {
store.dispatch('open/templates/loadWithLimit', 10)
},
methods: {
setInfinite() {
let ul = this.$refs['templates-slider']
if(ul){
ul.insertAdjacentHTML('afterend', ul.outerHTML)
ul.nextSibling.setAttribute('aria-hidden', 'true')
}
}
}
}
</script>

View File

@ -1,81 +0,0 @@
<template>
<div :class="wrapperClass">
<label v-if="label" :for="id?id:name"
:class="[theme.default.label,{'uppercase text-xs':uppercaseLabels, 'text-sm':!uppercaseLabels}]"
>
{{ label }}
<span v-if="required" class="text-red-500 required-dot">*</span>
</label>
<loader v-if="loading" key="loader" class="h-6 w-6 text-nt-blue mx-auto" />
<div v-else class="my-3">
<div v-for="(questionForm, quesKey) in allQuestions" :key="quesKey" class="bg-gray-100 p-2 mb-4">
<v-button color="red" size="small" class="mb-2" @click.prevent="onRemove(quesKey)">
<svg class="h-4 w-4 text-white inline mr-1 -mt-1" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 6H5M5 6H21M5 6V20C5 20.5304 5.21071 21.0391 5.58579 21.4142C5.96086 21.7893 6.46957 22 7 22H17C17.5304 22 18.0391 21.7893 18.4142 21.4142C18.7893 21.0391 19 20.5304 19 20V6H5ZM8 6V4C8 3.46957 8.21071 2.96086 8.58579 2.58579C8.96086 2.21071 9.46957 2 10 2H14C14.5304 2 15.0391 2.21071 15.4142 2.58579C15.7893 2.96086 16 3.46957 16 4V6M10 11V17M14 11V17" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
Remove
</v-button>
<text-input name="question" :form="questionForm" placeholder="Question title" />
<rich-text-area-input name="answer" :form="questionForm" class="mt-4" placeholder="Question response" />
</div>
<v-button v-if="addNew" color="green" size="small" nativeType="button" class="mt-2 flex" @click.prevent="onAdd">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 mr-1 inline" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v6m3-3H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
Add New
</v-button>
</div>
<small v-if="help" :class="theme.SelectInput.help">
<slot name="help">{{ help }}</slot>
</small>
<has-error v-if="hasValidation" :form="form" :field="name" />
</div>
</template>
<script>
import inputMixin from '~/mixins/forms/input.js'
import Form from 'vform'
export default {
name: 'QuestionsEditor',
mixins: [inputMixin],
props: {
loading: { type: Boolean, default: false },
addNew: { type: Boolean, default: true }
},
data () {
return {
allQuestions: [new Form({
question: '',
answer: '',
})]
}
},
watch: {
allQuestions: {
deep: true,
handler () {
this.compVal = this.allQuestions.map((ques) => {
return ques.data()
})
}
}
},
computed: { },
methods: {
onAdd() {
this.allQuestions.push(new Form({
question: '',
answer: '',
}))
},
onRemove(key){
this.allQuestions.splice(key, 1)
}
}
}
</script>

View File

@ -1,50 +1,191 @@
<template>
<div class="flex flex-col min-h-full mt-6">
<div class="w-full flex-grow md:w-4/5 lg:w-2/3 md:mx-auto md:max-w-4xl px-4">
<breadcrumb :path="breadcrumbs"/>
<div v-if="templatesLoading" class="text-center">
<loader class="h-6 w-6 text-nt-blue mx-auto"/>
</div>
<p v-else-if="template === null || !template">
Template does not exist.
</p>
<div v-else>
<div class="flex flex-wrap items-center mt-6 mb-4">
<h2 class="text-nt-blue text-3xl font-bold flex-grow">
{{ template.name }}
</h2>
<div class="flex flex-col min-h-full">
<breadcrumb :path="breadcrumbs">
<template #left>
<div v-if="user && (user.admin || user.template_editor)" class="ml-5">
<v-button color="gray" size="small" @click.prevent="showFormTemplateModal=true">
Edit Template
</v-button>
<form-template-modal v-if="form" :form="form" :template="template" :show="showFormTemplateModal"
@close="showFormTemplateModal=false"
/>
</div>
<div class="mb-10">
<div class="w-full shadow-xl rounded-lg my-5 max-h-72 flex items-center justify-center overflow-hidden">
<img :src="template.image_url" alt="Template cover image" class="w-full object-cover"/>
</div>
<div v-html="template.description"></div>
<div class="mt-5 text-center">
<v-button v-if="authenticated" class="mt-4 sm:mt-0" :to="{path:'/forms/create?template='+template.slug}">
Use this template
</v-button>
<v-button v-else class="mt-4 sm:mt-0" :to="{path:'/forms/create/guest?template='+template.slug}">
Use this template
</v-button>
</div>
</template>
<template #right>
<v-button v-track.use_template_button_clicked size="small" class="mr-5"
:to="{path: createFormWithTemplateUrl}"
>
Use this template
</v-button>
</template>
</breadcrumb>
<h3 class="text-center text-gray-500 mt-8 mb-2">Template Preview</h3>
<open-complete-form ref="open-complete-form" :form="form" :creating="true"
class="mb-4 p-4 bg-gray-50 rounded-lg"/>
<div v-if="templatesLoading" class="text-center my-4">
<loader class="h-6 w-6 text-nt-blue mx-auto" />
</div>
<p v-else-if="template === null || !template" class="text-center my-4">
We could not find this template.
</p>
<template v-else>
<section class="pt-12 bg-gray-50 sm:pt-16 border-b pb-[250px] relative">
<div class="px-4 mx-auto sm:px-6 lg:px-8 max-w-7xl">
<div class="flex flex-col items-center justify-center max-w-4xl gap-8 mx-auto md:gap-12 md:flex-row">
<div class="aspect-[4/3] shrink-0 rounded-lg shadow-sm overflow-hidden group max-w-xs">
<img class="object-cover w-full h-full transition-all duration-200 group-hover:scale-110"
:src="template.image_url" alt="Template cover image"
>
</div>
<div v-if="template.questions.length > 0" id="questions">
<h3 class="text-xl font-semibold mt-8">Frequently asked questions</h3>
<div class="pt-2">
<div v-for="(ques,ques_key) in template.questions" :key="ques_key" class="my-3 border rounded-lg">
<h5 class="border-b p-2 text-gray-700 font-semibold">{{ ques.question }}</h5>
<p class="p-2 text-gray-600" v-html="ques.answer"></p>
<div class="flex-1 text-center md:text-left relative">
<h1 class="text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl">
{{ template.name }}
</h1>
<p class="mt-2 text-lg font-normal text-gray-600">
{{ cleanQuotes(template.short_description) }}
</p>
<template-tags :slug="template.slug" :display-all="true"
class="flex flex-wrap items-center justify-center gap-3 mt-4 md:justify-start"
/>
</div>
</div>
</div>
</section>
<section class="relative px-4 mx-auto sm:px-6 lg:px-8 -mt-[210px]">
<div class="max-w-7xl">
<div
class="max-w-2xl p-4 mx-auto bg-white shadow-lg sm:p-6 lg:p-8 rounded-xl ring-1 ring-inset ring-gray-200 isolate"
>
<p class="text-sm font-medium text-center text-gray-500 -mt-2 mb-2">
Template Preview
</p>
<open-complete-form ref="open-complete-form" :form="form" :creating="true"
class="mb-4 p-4 bg-gray-50 border border-gray-200 border-dashed rounded-lg"
/>
</div>
</div>
<div class="absolute bottom-0 translate-y-full inset-x-0">
<div class="px-4 mx-auto sm:px-6 lg:px-8 max-w-7xl -mt-[20px]">
<div class="flex items-center justify-center">
<v-button v-track.use_template_button_clicked class="mx-auto w-full max-w-[300px]" :to="{path: createFormWithTemplateUrl}">
Use this template
</v-button>
</div>
<div class="flex items-center justify-center">
<div class="text-left mx-auto text-gray-500 text-xs mt-4">
Core features 100% free<br>
No credit card required<br>
No submissions limit on Free plan
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<section class="pt-20 pb-12 bg-white sm:pb-16">
<div class="px-4 mx-auto sm:px-6 lg:px-8 max-w-7xl">
<div class="max-w-2xl mx-auto mt-16 space-y-12 sm:mt-16 sm:space-y-16">
<div class="nf-text" v-html="template.description" />
<template v-if="template.questions.length > 0">
<hr class="mt-12 border-gray-200">
<div>
<div class="text-center">
<h3 class="text-xl font-bold tracking-tight text-gray-900 sm:text-2xl">
Frequently asked questions
</h3>
<p class="mt-2 text-base font-normal text-gray-600">
Everything you need to know about this template.
</p>
</div>
<dl class="mt-12 space-y-10">
<div v-for="(ques,ques_key) in template.questions" :key="ques_key" class="space-y-4">
<dt class="font-semibold text-gray-900 dark:text-gray-100">
{{ ques.question }}
</dt>
<dd class="mt-2 leading-6 text-gray-600 dark:text-gray-400" v-html="ques.answer" />
</div>
</dl>
</div>
</template>
</div>
</div>
</section>
<section v-if="template.related_templates.length > 0" class="py-12 bg-white border-t border-gray-200 sm:py-16">
<div class="px-4 mx-auto sm:px-6 lg:px-8 max-w-7xl">
<div class="flex items-center justify-between">
<h4 class="text-xl font-bold tracking-tight text-gray-900 sm:text-2xl">
Related templates
</h4>
<v-button :to="{name:'templates'}" color="white" size="small" :arrow="true">
View All
</v-button>
</div>
<div class="grid grid-cols-1 gap-8 mt-8 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 sm:gap-y-12">
<single-template v-for="related in template.related_templates" :key="related" :slug="related" />
</div>
</div>
</section>
<section class="py-12 bg-white border-t border-gray-200 sm:py-16">
<div class="px-4 mx-auto sm:px-6 lg:px-8 max-w-7xl">
<div class="text-center">
<h4 class="text-xl font-bold tracking-tight text-gray-900 sm:text-2xl">
How OpnForm works
</h4>
</div>
<div class="grid grid-cols-1 mt-12 md:grid-cols-2 gap-x-8 gap-y-12">
<div
class="flex flex-col items-center gap-4 text-center lg:items-start sm:text-left sm:items-start xl:flex-row"
>
<div
class="inline-flex items-center justify-center w-10 h-10 text-base font-bold bg-white rounded-full shadow-sm ring-1 ring-inset ring-gray-200 text-blue-500 shrink-0"
>
1
</div>
<div>
<h5 class="text-base font-bold leading-tight text-gray-900">
Copy the template and change it the way you like
</h5>
<p class="mt-2 text-sm font-normal text-gray-600">
<router-link :to="{path:createFormWithTemplateUrl}">
Click here to copy this template
</router-link>
and start customizing it. Change the questions, add new ones, choose colors and
more.
</p>
</div>
</div>
<div
class="flex flex-col items-center gap-4 text-center lg:items-start sm:text-left sm:items-start xl:flex-row"
>
<div
class="inline-flex items-center justify-center w-10 h-10 text-base font-bold bg-white rounded-full shadow-sm ring-1 ring-inset ring-gray-200 text-blue-500 shrink-0"
>
2
</div>
<div>
<h5 class="text-base font-bold leading-tight text-gray-900">
Embed the form or share it via a link
</h5>
<p class="mt-2 text-sm font-normal text-gray-600">
You can directly share your form link, or embed the form on your website. It's magic! 🪄
</p>
</div>
</div>
</div>
<!-- add video here -->
<!-- <div class="max-w-5xl mx-auto mt-12 shadow-sm rounded-xl bg-blue-50 aspect-video" />-->
</div>
</section>
</template>
<open-form-footer class="mt-8 border-t"/>
</div>
</template>
@ -52,61 +193,110 @@
<script>
import store from '~/store'
import Form from 'vform'
import {mapGetters, mapState} from 'vuex'
import Fuse from 'fuse.js'
import { mapGetters, mapState } from 'vuex'
import OpenFormFooter from '../../components/pages/OpenFormFooter.vue'
import OpenCompleteForm from '../../components/open/forms/OpenCompleteForm.vue'
import Breadcrumb from "../../components/common/Breadcrumb.vue";
import SeoMeta from "../../mixins/seo-meta";
const loadTemplates = function () {
store.commit('open/templates/startLoading')
store.dispatch('open/templates/loadIfEmpty').then(() => {
store.commit('open/templates/stopLoading')
})
}
import Breadcrumb from '../../components/common/Breadcrumb.vue'
import SeoMeta from '../../mixins/seo-meta.js'
import TemplateTags from '../../components/pages/templates/TemplateTags.vue'
import SingleTemplate from '../../components/pages/templates/SingleTemplate.vue'
import FormTemplateModal from '../../components/open/forms/components/templates/FormTemplateModal.vue'
export default {
components: { Breadcrumb, OpenFormFooter, OpenCompleteForm, TemplateTags, SingleTemplate, FormTemplateModal },
mixins: [SeoMeta],
components: {Breadcrumb, OpenFormFooter, OpenCompleteForm},
beforeRouteEnter(to, from, next) {
loadTemplates()
beforeRouteEnter (to, from, next) {
if (to.params?.slug) {
store.dispatch('open/templates/loadTemplate', to.params?.slug)
store.dispatch('open/templates/loadTypesAndIndustries')
}
next()
},
data() {
return {}
data () {
return {
showFormTemplateModal: false
}
},
mounted() {
mounted () {
},
methods: {},
methods: {
cleanQuotes (str) {
// Remove starting and ending quotes if any
return (str) ? str.replace(/^"/, '').replace(/"$/, '') : ''
}
},
computed: {
...mapGetters({
authenticated: 'auth/check'
authenticated: 'auth/check',
user: 'auth/user'
}),
...mapState({
templatesLoading: state => state['open/templates'].loading
}),
breadcrumbs() {
breadcrumbs () {
if (!this.template) {
return [{route: {name: 'templates'}, label: 'Templates'}]
return [{ route: { name: 'templates' }, label: 'Templates' }]
}
return [{route: {name: 'templates'}, label: 'Templates'}, {label: this.template.name}]
return [{ route: { name: 'templates' }, label: 'Templates' }, { label: this.template.name }]
},
template() {
template () {
return this.$store.getters['open/templates/getBySlug'](this.$route.params.slug)
},
form() {
form () {
return new Form(this.template.structure)
},
metaTitle () {
return this.template ? this.template.name : 'Template'
return this.template ? this.template.name : 'Form Template'
},
metaDescription () {
if (!this.template) return null
// take the first 140 characters of the description
return this.template.short_description?.substring(0, 140) + '... | Customize any template and create your own form in minutes.'
},
metaImage () {
if (!this.template) return null
return this.template.image_url
},
metaTags () {
return (this.template && this.template.publicly_listed) ? [] : [{ name: 'robots', content: 'noindex' }]
},
createFormWithTemplateUrl () {
if(this.authenticated) {
return '/forms/create?template=' + this.template?.slug
}
return '/forms/create/guest?template=' + this.template?.slug
}
}
}
</script>
<style lang='scss'>
.nf-text {
@apply space-y-4;
h2 {
@apply text-sm font-normal tracking-widest text-gray-500 uppercase;
}
p {
@apply font-normal leading-7 text-gray-900 dark:text-gray-100;
}
ol {
@apply list-decimal list-inside;
}
ul {
@apply list-disc list-inside;
}
}
.aspect-video {
aspect-ratio: 16/9;
}
</style>

View File

@ -1,94 +1,160 @@
<template>
<div class="flex flex-col min-h-full mt-6">
<div class="w-full flex-grow md:w-4/5 lg:w-2/3 md:mx-auto md:max-w-4xl px-4">
<div>
<div class="flex flex-wrap items-center mt-6 mb-4">
<h2 class="text-nt-blue text-3xl font-bold flex-grow">
Templates
</h2>
<div class="flex flex-col min-h-full border-t">
<section class="py-12 sm:py-16 bg-gray-50 border-b border-gray-200">
<div class="px-4 sm:px-6 lg:px-8 max-w-7xl mx-auto">
<div class="text-center max-w-xl mx-auto">
<h1 class="text-3xl sm:text-4xl lg:text-5xl font-bold tracking-tight text-gray-900">
Form Templates
</h1>
<p class="text-gray-600 mt-4 text-lg font-normal">
Our collection of beautiful templates to create your own forms!
</p>
</div>
<div v-if="templatesLoading" class="text-center">
<loader class="h-6 w-6 text-nt-blue mx-auto"/>
</div>
<p v-else-if="templates.length === 0">
No any templates found.
</p>
<div v-else class="mb-4">
<div v-if="templates && templates.length"
class="grid max-w-3xl grid-cols-1 mx-auto text-center sm:text-left sm:grid-cols-2 gap-y-8 gap-x-8 lg:gap-x-20">
<div class="relative group" v-for="(template, index) in templates" :key="template.id">
<div class="overflow-hidden rounded-lg aspect-w-16 aspect-h-9">
<img class="object-cover w-full h-full transition-all duration-300 transform group-hover:scale-125"
:src="template.image_url" alt=""/>
</div>
<p class="mt-3 mb-2 text-sm font-normal text-gray-600 font-pj">
{{ formatCreatedDate(template.created_at) }}</p>
<p class="text-xl font-bold text-gray-900 font-pj">{{ template.name }}</p>
<router-link :to="{params:{slug:template.slug},name:'templates.show'}" title="">
<span class="absolute inset-0" aria-hidden="true"></span>
</router-link>
</div>
</section>
<section class="bg-white py-12 sm:py-16">
<div class="px-4 sm:px-6 lg:px-8 max-w-7xl mx-auto">
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 sm:gap-6 relative z-20">
<div class="flex items-center gap-4">
<div class="flex-1 sm:flex-none">
<select-input v-model="selectedType" name="type"
:options="typesOptions" class="w-full sm:w-auto md:w-56"
/>
</div>
<div class="flex-1 sm:flex-none">
<select-input v-model="selectedIndustry" name="industry"
:options="industriesOptions" class="w-full sm:w-auto md:w-56"
/>
</div>
</div>
<div class="flex-1 w-full md:max-w-xs">
<text-input name="search" :form="searchTemplate" placeholder="Search..." />
</div>
</div>
<div v-if="templatesLoading" class="text-center mt-4">
<loader class="h-6 w-6 text-nt-blue mx-auto" />
</div>
<p v-else-if="enrichedTemplates.length === 0" class="text-center mt-4">
No templates found.
</p>
<div v-else class="relative z-10">
<div class="grid grid-cols-1 mt-8 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-8 sm:gap-y-12">
<single-template v-for="template in enrichedTemplates" :key="template.id" :slug="template.slug" />
</div>
</div>
</div>
</div>
</section>
<open-form-footer class="mt-8 border-t"/>
</div>
</template>
<script>
import store from '~/store'
import {mapGetters, mapState} from 'vuex'
import { mapGetters, mapState } from 'vuex'
import Form from 'vform'
import Fuse from 'fuse.js'
import SeoMeta from '../../mixins/seo-meta.js'
import OpenFormFooter from '../../components/pages/OpenFormFooter.vue'
import SeoMeta from "../../mixins/seo-meta";
import SingleTemplate from '../../components/pages/templates/SingleTemplate.vue'
const loadTemplates = function () {
store.commit('open/templates/startLoading')
store.dispatch('open/templates/load').then(() => {
store.dispatch('open/templates/loadIfEmpty').then(() => {
store.commit('open/templates/stopLoading')
})
}
export default {
components: { OpenFormFooter, SingleTemplate },
mixins: [SeoMeta],
components: {OpenFormFooter},
beforeRouteEnter(to, from, next) {
beforeRouteEnter (to, from, next) {
loadTemplates()
next()
},
props: {
metaTitle: {type: String, default: 'Templates'},
metaDescription: {type: String, default: 'Our collection of beautiful templates to create your own forms!'}
metaTitle: { type: String, default: 'Templates' },
metaDescription: { type: String, default: 'Our collection of beautiful templates to create your own forms!' }
},
data() {
return {}
},
mounted() {
},
methods: {
formatCreatedDate(createdDate) {
const date = new Date(createdDate)
const dateTimeFormat = new Intl.DateTimeFormat('en', {
year: 'numeric',
month: 'long',
day: 'numeric',
data () {
return {
selectedType: 'all',
selectedIndustry: 'all',
searchTemplate: new Form({
search: ''
})
return dateTimeFormat.format(date)
}
},
mounted () {
},
computed: {
...mapState({
templates: state => state['open/templates'].content,
templatesLoading: state => state['open/templates'].loading
templatesLoading: state => state['open/templates'].loading,
industries: state => state['open/templates'].industries,
types: state => state['open/templates'].types
}),
}
industriesOptions () {
return [{ name: 'All Industries', value: 'all' }].concat(Object.values(this.industries).map((industry) => {
return {
name: industry.name,
value: industry.slug
}
}))
},
typesOptions () {
return [{ name: 'All Types', value: 'all' }].concat(Object.values(this.types).map((type) => {
return {
name: type.name,
value: type.slug
}
}))
},
enrichedTemplates () {
let enrichedTemplates = this.templates
// Filter by Selected Type
if (this.selectedType && this.selectedType !== 'all') {
enrichedTemplates = enrichedTemplates.filter((item) => {
return (item.types && item.types.length > 0) ? item.types.includes(this.selectedType) : false
})
}
// Filter by Selected Industry
if (this.selectedIndustry && this.selectedIndustry !== 'all') {
enrichedTemplates = enrichedTemplates.filter((item) => {
return (item.industries && item.industries.length > 0) ? item.industries.includes(this.selectedIndustry) : false
})
}
if (this.searchTemplate.search === '' || this.searchTemplate.search === null) {
return enrichedTemplates
}
// Fuze search
const fuzeOptions = {
keys: [
'name',
'slug',
'description',
'short_description'
]
}
const fuse = new Fuse(enrichedTemplates, fuzeOptions)
return fuse.search(this.searchTemplate.search).map((res) => {
return res.item
})
}
},
methods: {}
}
</script>

View File

@ -78,6 +78,8 @@
<!-- <testimonials/>-->
<!-- </div>-->
<templates-slider />
<div class="w-full bg-blue-900 p-12 md:p-24 text-center">
<h4 class="font-semibold text-3xl text-white">Take your forms to the next level</h4>
<p class="text-gray-300 my-8">Generous, unlimited free plan.</p>
@ -123,10 +125,11 @@ import MoreFeatures from '~/components/pages/welcome/MoreFeatures.vue'
import AiFeature from '~/components/pages/welcome/AiFeature.vue'
import OpenFormFooter from '../components/pages/OpenFormFooter.vue'
import Testimonials from '../components/pages/welcome/Testimonials.vue'
import TemplatesSlider from '../components/pages/welcome/TemplatesSlider.vue'
import SeoMeta from '../mixins/seo-meta.js'
export default {
components: {Testimonials, OpenFormFooter, Features, MoreFeatures, AiFeature},
components: {Testimonials, OpenFormFooter, Features, MoreFeatures, AiFeature, TemplatesSlider},
layout: 'default',

View File

@ -67,8 +67,8 @@ export default [
{ path: '/forms/:slug', name: 'forms.show_public', component: page('forms/show-public.vue') },
// Templates
{ path: '/templates', name: 'templates', component: page('templates/templates.vue') },
{ path: '/templates/:slug', name: 'templates.show', component: page('templates/show.vue') },
{ path: '/form-templates', name: 'templates', component: page('templates/templates.vue') },
{ path: '/form-templates/:slug', name: 'templates.show', component: page('templates/show.vue') },
{ path: '*', component: page('errors/404.vue') }
]

View File

@ -1,55 +1,124 @@
import Vue from 'vue'
import axios from 'axios'
export const templatesEndpoint = '/api/templates'
export const namespaced = true
// state
export const state = {
content: [],
industries: {},
types: {},
allLoaded: false,
loading: false
}
// getters
export const getters = {
getById: (state) => (id) => {
if (state.content.length === 0) return null
return state.content.find(item => item.id === id)
},
getBySlug: (state) => (slug) => {
if (state.content.length === 0) return null
return state.content.find(item => item.slug === slug)
},
getTemplateTypes: (state) => (slugs) => {
if (state.types.length === 0) return null
return Object.values(state.types).filter((val) => slugs.includes(val.slug)).map((item) => { return item.name })
},
getTemplateIndustries: (state) => (slugs) => {
if (state.industries.length === 0) return null
return Object.values(state.industries).filter((val) => slugs.includes(val.slug)).map((item) => { return item.name })
}
}
// mutations
export const mutations = {
set (state, items) {
state.content = items
state.allLoaded = true
},
append (state, items) {
const ids = items.map((item) => { return item.id })
state.content = state.content.filter((val) => !ids.includes(val.id))
state.content = state.content.concat(items)
},
addOrUpdate (state, item) {
state.content = state.content.filter((val) => val.id !== item.id)
state.content.push(item)
},
startLoading () {
remove (state, item) {
state.content = state.content.filter((val) => val.id !== item.id)
},
startLoading (state) {
state.loading = true
},
stopLoading () {
stopLoading (state) {
state.loading = false
},
setAllLoaded (state, val) {
state.allLoaded = val
}
}
// actions
export const actions = {
load (context) {
resetState (context) {
context.commit('set', [])
context.commit('stopLoading')
},
loadTypesAndIndustries (context) {
if (Object.keys(context.state.industries).length === 0) {
import('@/data/forms/templates/industries.json').then((module) => {
context.state.industries = module.default
})
}
if (Object.keys(context.state.types).length === 0) {
import('@/data/forms/templates/types.json').then((module) => {
context.state.types = module.default
})
}
},
loadTemplate (context, slug) {
context.commit('startLoading')
return axios.get('/api/templates').then((response) => {
context.commit('set', response.data)
context.dispatch('loadTypesAndIndustries')
if (context.getters.getBySlug(slug)) {
context.commit('stopLoading')
return Promise.resolve()
}
return axios.get(templatesEndpoint + '/' + slug).then((response) => {
context.commit('addOrUpdate', response.data)
context.commit('stopLoading')
}).catch((error) => {
context.commit('stopLoading')
})
},
loadIfEmpty ({ context, dispatch, state }) {
if (state.content.length === 0) {
return dispatch('load')
loadAll (context) {
context.commit('startLoading')
context.dispatch('loadTypesAndIndustries')
return axios.get(templatesEndpoint).then((response) => {
context.commit('append', response.data)
context.commit('setAllLoaded', true)
context.commit('stopLoading')
}).catch((error) => {
context.commit('stopLoading')
})
},
loadIfEmpty (context) {
if (!context.state.allLoaded) {
return context.dispatch('loadAll')
}
context.commit('stopLoading')
return Promise.resolve()
},
loadWithLimit (context, limit) {
context.commit('startLoading')
context.dispatch('loadTypesAndIndustries')
return axios.get(templatesEndpoint + '?limit=' + limit).then((response) => {
context.commit('set', response.data)
context.commit('setAllLoaded', false)
context.commit('stopLoading')
}).catch((error) => {
context.commit('stopLoading')
})
}
}

View File

@ -161,5 +161,10 @@ Route::prefix('content')->name('content.')->group(function () {
});
// Templates
Route::get('templates', [TemplateController::class, 'index'])->name('templates.show');
Route::post('templates', [TemplateController::class, 'create'])->name('templates.create');
Route::prefix('templates')->group(function () {
Route::get('/', [TemplateController::class, 'index'])->name('templates.index');
Route::post('/', [TemplateController::class, 'create'])->name('templates.create');
Route::get('/{slug}', [TemplateController::class, 'show'])->name('templates.show');
Route::put('/{id}', [TemplateController::class, 'update'])->name('templates.update');
Route::delete('/{id}', [TemplateController::class, 'destroy'])->name('templates.destroy');
});

7
tailwind.config.js vendored
View File

@ -21,10 +21,15 @@ module.exports = {
'0%, 20%': {transform: 'translateY(0)'},
'8%': {transform: 'translateY(-25%)'},
'16%': {transform: 'translateY(+10%)'}
},
'infinite-scroll': {
from: { transform: 'translateX(0)' },
to: { transform: 'translateX(-100%)' },
}
},
animation: {
'bounce-slow': 'bonce-slow 3s ease-in-out infinite'
'bounce-slow': 'bonce-slow 3s ease-in-out infinite',
'infinite-scroll': 'infinite-scroll 50s linear infinite',
},
maxHeight: {
42: '10.5rem'

View File

@ -14,8 +14,10 @@ it('can create template', function () {
$templateData = [
'name' => 'Demo Template',
'slug' => 'demo_template',
'description' => 'Some description here...',
'short_description' => 'Short description here...',
'description' => 'Some long description here...',
'image_url' => 'https://d3ietpyl4f2d18.cloudfront.net/6c35a864-ee3a-4039-80a4-040b6c20ac60/img/pages/welcome/product_cover.jpg',
'publicly_listed' => true,
'form' => $form->getAttributes(),
'questions' => [['question'=>'Question 1','answer'=>'Answer 1 will be here...']]
];
@ -23,6 +25,6 @@ it('can create template', function () {
->assertSuccessful()
->assertJson([
'type' => 'success',
'message' => 'Template created.'
'message' => 'Template was created.'
]);
});